Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
50e3b55
feat(api): add generic `workos api` gateway for raw API requests
nicknisi May 4, 2026
ca3c9af
feat(api): add interactive request builder and fix duplicate resolveA…
nicknisi May 4, 2026
619b578
fix: Temporarily copy over the YAML spec
nicknisi May 4, 2026
0054db9
refactor(api): use @workos/openapi-spec package instead of vendored YAML
nicknisi May 5, 2026
5a5ad2b
chore(build): remove vendored YAML copy from postbuild
nicknisi May 5, 2026
39c67aa
refactor(api): address code review findings
nicknisi May 5, 2026
add7794
fix(api): handle invalid JSON body in dry-run JSON mode and add tests
nicknisi May 5, 2026
aaaa66f
fix(api): emit pure JSON in JSON mode and gracefully handle missing -…
devin-ai-integration[bot] May 5, 2026
ff3b3e7
fix(api): emit structured error from runApiInteractive in JSON mode
devin-ai-integration[bot] May 5, 2026
2d87eb7
fix(api): respect empty bodies and require --yes for mutating JSON re…
devin-ai-integration[bot] May 5, 2026
0b23d79
fix(api): close remaining bugs flagged by Devin Review and CodeRabbit
devin-ai-integration[bot] May 5, 2026
f2af84f
fix(api): refuse JSON-mode interactive flow even in a TTY
devin-ai-integration[bot] May 5, 2026
37ef3b8
fix(api): expose --insecure-storage in help-json for the api command
devin-ai-integration[bot] May 5, 2026
4912d24
fix(api): tighten edge-case handling in body, path, and fetch flows
devin-ai-integration[bot] May 5, 2026
b843058
fix(api): URL-encode path param values in interactive mode
devin-ai-integration[bot] May 5, 2026
a57f38d
fix(api): resolve $ref params and dedupe path/operation overlap
devin-ai-integration[bot] May 5, 2026
11e5ffb
fix(api): switch catalog spec read to async to match CLAUDE.md
devin-ai-integration[bot] May 5, 2026
6e5c43e
fix(api): pass --api-key to interactive, require mandatory params and…
nicknisi May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,21 @@
"@anthropic-ai/sdk": "^0.78.0",
"@clack/core": "^1.0.1",
"@clack/prompts": "1.0.1",
"@hono/node-server": "^1",
"@napi-rs/keyring": "^1.2.0",
"@workos-inc/node": "^8.7.0",
"@workos/openapi-spec": "^0.1.0",
"@workos/skills": "0.5.0",
"chalk": "^5.6.2",
"diff": "^8.0.3",
"fast-glob": "^3.3.3",
"hono": "^4",
"ink": "^6.8.0",
"opn": "^5.4.0",
"react": "^19.2.4",
"semver": "^7.7.4",
"uuid": "^13.0.0",
"xstate": "^5.28.0",
"hono": "^4",
"@hono/node-server": "^1",
"yaml": "^2.8.2",
"yargs": "^18.0.0",
"zod": "^4.3.6"
Expand Down
8 changes: 8 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 82 additions & 0 deletions src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,88 @@ yargs(rawArgs)
);
return yargs.demandCommand(1, 'Please specify an env subcommand').strict();
})
.command(
'api [endpoint] [filter]',
'Make authenticated requests to the WorkOS API',
(yargs) =>
yargs
.options(insecureStorageOption)
.positional('endpoint', {
type: 'string',
describe: "API endpoint path (e.g. /users), or 'ls' to list endpoints",
})
.positional('filter', {
type: 'string',
describe: 'Filter keyword (used with ls)',
})
.option('method', {
alias: 'X',
type: 'string',
describe: 'HTTP method (default: GET, or POST if body provided)',
})
.option('data', {
alias: 'd',
type: 'string',
describe: 'JSON request body',
})
.option('file', {
type: 'string',
describe: 'Read request body from a file (or - for stdin)',
})
.option('include', {
alias: 'i',
type: 'boolean',
default: false,
describe: 'Show response headers',
})
.option('api-key', {
type: 'string',
describe: 'Override the API key',
})
.option('dry-run', {
type: 'boolean',
default: false,
describe: 'Show the request without executing it',
})
.option('yes', {
alias: 'y',
type: 'boolean',
default: false,
describe: 'Skip confirmation for mutating requests',
})
.example('workos api ls', 'List all available endpoints')
.example('workos api ls users', 'List endpoints matching "users"')
.example('workos api /user_management/users', 'GET /user_management/users')
.example('workos api /organizations -d \'{"name":"Acme"}\'', 'POST with a JSON body')
.example('workos api /organizations/org_123 -X DELETE', 'DELETE an organization'),
Comment thread
devin-ai-integration[bot] marked this conversation as resolved.
async (argv) => {
await applyInsecureStorage(argv.insecureStorage as boolean | undefined);
const endpoint = argv.endpoint as string | undefined;
const filter = argv.filter as string | undefined;

const { runApiLs, runApiRequest, runApiInteractive } = await import('./commands/api/index.js');

if (!endpoint) {
await runApiInteractive({ apiKey: argv.apiKey as string | undefined });
return;
}

if (endpoint === 'ls') {
await runApiLs(filter);
return;
}

await runApiRequest(endpoint, {
method: argv.method,
data: argv.data,
file: argv.file,
include: argv.include,
apiKey: argv.apiKey,
dryRun: argv.dryRun,
yes: argv.yes,
});
},
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
.command(['organization', 'org'], 'Manage WorkOS organizations (create, update, get, list, delete)', (yargs) => {
yargs.options({
...insecureStorageOption,
Expand Down
Loading
Loading