OpenAPI TypeScript CLI (openapi-ts)#
Overview#
@hey-api/openapi-ts is a TypeScript code generator driven from a CLI (openapi-ts) or the programmatic createClient() API. The CLI entry point is src/run.ts, which calls runCli() from src/cli/index.ts. It accepts an OpenAPI spec (local file, URL, or inline object) and an output path, then runs configured plugins to generate TypeScript interfaces, SDK clients, and related artifacts.
Three invocation modes :
- CLI:
npx @hey-api/openapi-ts -i <spec> -o <output>or via anopenapi-tsscript inpackage.json - Node.js API:
import { createClient } from '@hey-api/openapi-ts' - Vite plugin:
@hey-api/vite-plugin
CLI Flags & Configuration#
The CLI is built on Commander.js. Flags are mapped to UserConfig by cliToConfig() in src/cli/adapter.ts.
| Flag | Short | Description |
|---|---|---|
--input | -i | OpenAPI spec path, URL, or inline string |
--output | -o | Output folder(s) |
--client | -c | HTTP client plugin to generate |
--plugins | -p | Plugins to use |
--file | -f | Path to config file |
--debug | -d | Enable debug logging |
--silent | -s | Suppress all output |
--logs | -l | Logs folder path |
--no-log-file | Disable log file output | |
--dry-run | Skip writing files | |
--watch | -w | Watch for changes (interval in ms) |
All flags are optional on the command line; missing values are resolved from a config file (default lookup via jiti/c12) .
Exit Code Behavior#
Exit codes are controlled in runCli() inside src/cli/index.ts.
| Scenario | Exit Code |
|---|---|
| Successful generation (no watch mode) | 0 |
| Watch mode active | Process stays alive; process.exit not called |
Commander parse error (optionMissingArgument, unknownOption) | Commander's own error.exitCode |
| Unexpected / unhandled error | 1 |
Successful run: after createClient() resolves, the CLI calls process.exit(0) only when no active watch is detected .
Commander errors: if Commander throws a CommanderError, runCli() prints a human-readable hint and exits with the exitCode embedded in the error :
commander.optionMissingArgument→"Missing required argument. Run '...' --help for usage."commander.unknownOption→"Unknown option. Run '...' --help for available options."
Unexpected errors: any other caught exception logs "Unexpected error:" to stderr and exits 1 .
Error Handling & Input Failures#
Error classification happens in src/generate.ts and src/createClient.ts.
Input errors (file not found, HTTP 4xx)#
- Missing local file: when
$RefParserfails withENOENT,createClient.tscatches it and throwsInputError("Input file not found"). - HTTP 4xx on remote input: a 4xx response is treated as a client-side
InputError(bad URL, missing auth, etc.) and includes the source path in the error . - HTTP 5xx: re-thrown as a generic
Error— treated as a potential server bug .
Key behavior: generate.ts catches InputError specifically via getInputError() and returns an empty array ([]) instead of re-throwing . This means input errors do not propagate to runCli()'s catch block and do not trigger process.exit(1) — the process exits 0. The crash report and GitHub issue prompt are also suppressed for input errors .
Config validation errors#
ConfigValidationError is thrown before any jobs run when the resolved config is invalid. This does propagate out of generate.ts and will cause runCli() to exit 1.
Watch mode degradation#
In watch mode, errors on subsequent runs (after the first) do not throw — the CLI silently swallows fetch errors to handle cases where the server is temporarily unavailable .
Per-job errors#
Each job is wrapped in a try/catch; any thrown Error is wrapped in a JobError and re-thrown from generate.ts , ultimately reaching runCli() as an unexpected error → exit 1.
Input Validation (validate_EXPERIMENTAL)#
To validate the OpenAPI spec before generation, enable the experimental validator in the parser config :
export default {
input: './openapi.json',
output: 'src/client',
parser: {
validate_EXPERIMENTAL: true,
},
};
When enabled, any detected errors in the input will exit @hey-api/openapi-ts and no plugins will be executed . The feature is currently limited in scope; additional use cases are tracked in GitHub issue #1970.
Key Source Files#
| File | Purpose |
|---|---|
src/run.ts | CLI binary entry point; calls runCli() |
src/cli/index.ts | Commander setup, option definitions, runCli(), exit code logic |
src/cli/adapter.ts | cliToConfig() — maps CLI flags to UserConfig |
src/cli/schema.ts | CliOptions interface |
src/generate.ts | Top-level createClient(), error classification, InputError suppression |
src/createClient.ts | Per-job execution: spec fetching, ENOENT detection, watch loop |
Config reference: the full UserConfig type is defined in src/config/types.ts .