Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
166 commits
Select commit Hold shift + click to select a range
850706f
feat(openapi-typescript): generate-client — typed, zero-dependency Op…
Marshevskyy Jun 15, 2026
6aeb52b
docs(cli): update text formatting
JLekawa Jun 17, 2026
2e5ae8d
Apply suggestions from code review
JLekawa Jun 17, 2026
ae5cebe
docs(cli): fix Markdoc errors, fix formatting
JLekawa Jun 17, 2026
3f38466
docs(realm): fix redirect error
JLekawa Jun 18, 2026
1adbf1e
docs(cli): fix redirect error
JLekawa Jun 18, 2026
0d974de
fix(openapi-typescript): point examples at the spec server + add test…
Marshevskyy Jun 22, 2026
7efcb23
Merge origin/main into feat/ts-client-gen
Marshevskyy Jun 22, 2026
e53e0b1
docs(generate-client): strip trailing spaces to satisfy markdownlint …
Marshevskyy Jun 22, 2026
95adc1e
ci(docs): use vale filter_mode nofilter to survive large-PR diffs
Marshevskyy Jun 22, 2026
5afa6a5
test(generate-client): commit consumer api.ts so flat typecheck finds it
Marshevskyy Jun 22, 2026
adc413e
fix: formatting
Marshevskyy Jun 22, 2026
f44e269
fix: align root react/react-dom with main (19.x) to fix build-docs sn…
Marshevskyy Jun 22, 2026
212bb7f
ci(docs): use reviewdog local reporter for vale so large PRs don't 406
Marshevskyy Jun 22, 2026
34594a7
Update docs/@v2/commands/generate-client.md
Marshevskyy Jun 22, 2026
f0c810b
fix(openapi-typescript): explicit .js extensions in example imports; …
Marshevskyy Jun 22, 2026
041040e
chore: revert vale reporter change; drop branch-added coverage thresh…
Marshevskyy Jun 22, 2026
776d818
docs(openapi-typescript): add a Node (msw/node) variant to the mock e…
Marshevskyy Jun 23, 2026
0340e2d
chore: drop trailing comma in vitest.config.ts (oxfmt es5 normalization)
Marshevskyy Jun 23, 2026
8dad18b
fix(openapi-typescript): SSE — flush final frame and finish on clean …
Marshevskyy Jun 23, 2026
dab6d50
fix(openapi-typescript): empty generators list falls back to the defa…
Marshevskyy Jun 23, 2026
aab5c4a
fix(cli): generate-client only loads a config file when --config-file…
Marshevskyy Jun 23, 2026
b97f6ba
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jun 23, 2026
840c33a
fix: formatting
Marshevskyy Jun 23, 2026
f7dec25
fix(openapi-typescript): drain a retried response body before the nex…
Marshevskyy Jun 23, 2026
6532520
fix(openapi-typescript): regenerate programmatic example with the bod…
Marshevskyy Jun 24, 2026
914d1c6
fix(openapi-typescript): SSE reconnects on a transport failure openin…
Marshevskyy Jun 24, 2026
28a9c05
test(openapi-typescript): move examples drift test under generate-cli…
Marshevskyy Jun 24, 2026
3a0754b
refactor(openapi-typescript): drop *.config.ts config-file support an…
Marshevskyy Jun 26, 2026
69393cf
refactor!: rename @redocly/openapi-typescript → @redocly/client-gener…
Marshevskyy Jun 26, 2026
ba801b4
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jun 30, 2026
977e19d
fix(client-generator): serialize request body after the onRequest chain
Marshevskyy Jun 30, 2026
448a592
feat(client-generator): operation context on requests + baked publish…
Marshevskyy Jun 30, 2026
b4930f2
fix: formatting
Marshevskyy Jun 30, 2026
18fe9c3
fix(client-generator): resolve CodeQL alerts (ReDoS, URL/stack-trace,…
Marshevskyy Jun 30, 2026
ee13cb5
docs(client-generator): fix --setup section link fragment (MD051)
Marshevskyy Jun 30, 2026
4b7b44a
docs(client-generator): use imperative --setup heading (Vale HeaderGe…
Marshevskyy Jun 30, 2026
7dbd311
fix(client-generator): accept relative base-url; resolve CLI --setup …
Marshevskyy Jun 30, 2026
b55d394
fix(client-generator): serialize multipart body after the onRequest c…
Marshevskyy Jun 30, 2026
9946803
fix(client-generator): resolve generateClient setup path from cwd, li…
Marshevskyy Jun 30, 2026
18705f9
fix: formatting
Marshevskyy Jun 30, 2026
58573fd
refactor(client-generator): move examples under tests/e2e/generate-cl…
Marshevskyy Jul 1, 2026
abff0c3
docs(client-generator): simplify and restructure the command reference
Marshevskyy Jul 1, 2026
7b87b6c
refactor(client-generator): rename the input positional/field to api
Marshevskyy Jul 1, 2026
2b87a3f
feat(core): register client + clientOutput in the redocly.yaml config…
Marshevskyy Jul 2, 2026
3596d12
refactor(client-generator): rename baseUrl to serverUrl
Marshevskyy Jul 2, 2026
9379791
feat(cli): generate-client reads the client config block; three invoc…
Marshevskyy Jul 2, 2026
37b5949
test(client-generator): move examples + e2e to the new client config …
Marshevskyy Jul 2, 2026
2159ba5
refactor(client-generator): rename setBaseUrl to setServerUrl
Marshevskyy Jul 2, 2026
794649e
docs(client-generator): document the client config model + serverUrl
Marshevskyy Jul 2, 2026
4d55775
refactor(core): type client + clientOutput on the resolved config
Marshevskyy Jul 2, 2026
582b3e4
chore: drop the body-serialization changeset
Marshevskyy Jul 2, 2026
953206c
refactor(cli): use openapi-core pluralize for the generate-client sum…
Marshevskyy Jul 2, 2026
829839e
refactor(cli): drop explanatory comments in the generators coerce
Marshevskyy Jul 2, 2026
5deef0d
refactor(client-generator): rename ir/ to intermediate-representation/
Marshevskyy Jul 2, 2026
5728f00
fix(client-generator): correct stale/misplaced comments and a dead __…
Marshevskyy Jul 2, 2026
f8faebf
chore: stop blanket-ignoring e2e yaml in oxfmt
Marshevskyy Jul 2, 2026
7197b02
style: run oxfmt across the client-generator branch
Marshevskyy Jul 2, 2026
4743b58
test(client-generator): compile generated clients under nodenext, not…
Marshevskyy Jul 2, 2026
6ea02b4
refactor(client-generator): expose everything from the single package…
Marshevskyy Jul 2, 2026
e1d9098
test(client-generator): use outdent for inline specs and consumer scr…
Marshevskyy Jul 2, 2026
447b4e9
docs: add generate-client to the v2 sidebar
Marshevskyy Jul 2, 2026
da30a43
docs: split generate-client into command, client-usage, and config pages
Marshevskyy Jul 2, 2026
fe64930
docs: keep generate-client as a single command page
Marshevskyy Jul 2, 2026
25d8f18
docs: drop the extra generate-client sidebar entries
Marshevskyy Jul 2, 2026
6f46549
docs: client usage as a guide, client config under configuration/refe…
Marshevskyy Jul 2, 2026
4158cdc
fix(client-generator): address cursor-bot findings (serverUrl, dup ou…
Marshevskyy Jul 2, 2026
6f21aa5
docs(client-generator): note retry resend + use()/configure middlewar…
Marshevskyy Jul 2, 2026
3f0323c
Update README.md
Marshevskyy Jul 3, 2026
59990e9
docs(client-generator): new ard for msw vs mock server
Marshevskyy Jul 3, 2026
d6f7e80
feat(client-generator): runtime module + descriptor client (--runtime…
Marshevskyy Jul 6, 2026
b5dda87
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 6, 2026
273c7a7
docs: wrap overlong line in the generated-client guide (markdownlint …
Marshevskyy Jul 6, 2026
303bd1c
fix: align @redocly/client-generator's openapi-core dependency with t…
Marshevskyy Jul 6, 2026
93d7ee1
fix(generate-client): restrict serverUrl to http(s)/root-relative; re…
Marshevskyy Jul 6, 2026
b472709
feat(client-generator): auto-pagination — declared, statically verifi…
Marshevskyy Jul 8, 2026
eb526f7
feat(client-generator): nested-facade example + output-path interpola…
Marshevskyy Jul 8, 2026
1bd0464
fix: versions
Marshevskyy Jul 8, 2026
be55f66
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 8, 2026
489ed53
fix: stop oxfmt reformatting generated pagination-consumer artifacts
Marshevskyy Jul 8, 2026
504696d
fix(respect): wait for json-server readiness in the local-json-server…
Marshevskyy Jul 8, 2026
3f09b2b
fix(client-generator): result-mode pagination must not throw on succe…
Marshevskyy Jul 8, 2026
214b867
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 8, 2026
bf5f82b
ci: cap e2e parallelism to keep the runner within memory
Marshevskyy Jul 8, 2026
5a424ec
test(client-generator): refresh base/sse consumer fixtures for the pa…
Marshevskyy Jul 8, 2026
fc32f83
fix: change ci runner to gh hosted
Marshevskyy Jul 8, 2026
2989dc8
fix(client-generator): deep-merge pagination when layering client con…
Marshevskyy Jul 8, 2026
be92b1e
ci: split e2e into two sharded jobs
Marshevskyy Jul 9, 2026
0ef1ba1
docs(client-generator): fix README generateClient import and list the…
Marshevskyy Jul 9, 2026
45887e6
fix: vitest thresholds
Marshevskyy Jul 10, 2026
a9eb026
fix(client-generator): address PR review comments
Marshevskyy Jul 10, 2026
f649e42
feat(client-generator): repeatable --generator flag; resolve per-alia…
Marshevskyy Jul 10, 2026
47a44fe
fix(client-generator): update stale golden + assertions for the revie…
Marshevskyy Jul 10, 2026
4f9bde4
test(client-generator): regenerate inline consumer fixtures for the r…
Marshevskyy Jul 10, 2026
698d123
fix(client-generator): encode cookie auth, coerce string pagination o…
Marshevskyy Jul 10, 2026
895908a
docs(changeset): shorten the client-generator changeset to what's added
Marshevskyy Jul 13, 2026
71fbff9
fix(cli): resolve generate-client apis via getFallbackApisOrExit like…
Marshevskyy Jul 13, 2026
7d0fc4c
chore(cli): restore the original build banner comment
Marshevskyy Jul 13, 2026
1015231
refactor(cli): move generate-client comments into docs and yargs desc…
Marshevskyy Jul 13, 2026
5152c2b
refactor(cli): return each serverUrl validation case explicitly
Marshevskyy Jul 13, 2026
51550d8
refactor(cli): read the effective client block via config.forAlias
Marshevskyy Jul 13, 2026
c589573
fix(client-generator): UTF-8-safe basic auth encoding and Headers-ins…
Marshevskyy Jul 13, 2026
d66f14c
refactor(core): remove needless client config comments
Marshevskyy Jul 13, 2026
3cbe9b8
fix(cli): opt apis into generate-client fan-out via clientOutput too
Marshevskyy Jul 13, 2026
8c5a54b
fix(client-generator): put the types condition first in package exports
Marshevskyy Jul 13, 2026
41a96e7
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 13, 2026
f9904f3
fix(core): layer a per-api client block over the top-level one field …
Marshevskyy Jul 13, 2026
1c6fe7e
fix(client-generator): fail closed on oversized SSE frames instead of…
Marshevskyy Jul 13, 2026
a381825
fix(client-generator): skip the optional-auth marker when resolving o…
Marshevskyy Jul 14, 2026
e25b149
fix(core): keep the pagination block additive when layering per-api c…
Marshevskyy Jul 14, 2026
36c569f
fix(client-generator): let CommonJS projects require() the package ru…
Marshevskyy Jul 14, 2026
0896157
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 14, 2026
1a16633
fix(client-generator): apply the first configured security alternativ…
Marshevskyy Jul 14, 2026
f5776cf
fix(client-generator): cancel the abandoned body when onResponse repl…
Marshevskyy Jul 14, 2026
3aea0d0
feat(client-generator): zod runtime validation — operationSchemas map…
Marshevskyy Jul 15, 2026
7958fbb
fix(client-generator): declaration-safe operationSchemas and omit on …
Marshevskyy Jul 15, 2026
3bef857
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
cebc122
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
1b7ce53
Update docs/@v2/configuration/reference/client.md
Marshevskyy Jul 16, 2026
8bca18f
test(cli): prove shared generator defaults survive per-api client ove…
Marshevskyy Jul 16, 2026
fae2394
refactor(client-generator): match apiKey scheme kinds exactly
Marshevskyy Jul 16, 2026
238612b
test(client-generator): share the example spec, gitignore generated c…
Marshevskyy Jul 17, 2026
de9b41f
test(client-generator): extract shared e2e helpers and stop committin…
Marshevskyy Jul 17, 2026
26455fa
test(client-generator): drop redundant unit tests and runtime-embeddi…
Marshevskyy Jul 17, 2026
3874370
refactor(client-generator): dedupe emitter helpers, inline the writer…
Marshevskyy Jul 17, 2026
1970eb7
fix(cli): validate the --setup flag like the config setup and complet…
Marshevskyy Jul 17, 2026
617f1a1
docs(cli): use semantic line breaks in the generate-client guide and …
Marshevskyy Jul 17, 2026
94a7339
test(cli): drive the redocly-config e2e suite with a minimal inline s…
Marshevskyy Jul 17, 2026
ed231e1
docs(client-generator): fold the customization example into configure…
Marshevskyy Jul 17, 2026
38f807b
test(client-generator): make fixture arguments explicit and dedupe th…
Marshevskyy Jul 17, 2026
c6266bc
Potential fix for pull request finding 'CodeQL / Workflow does not co…
Marshevskyy Jul 17, 2026
0f71a56
fix(client-generator): resolve server-URL variables, match pagination…
Marshevskyy Jul 17, 2026
a8deb80
fix(client-generator): snapshot release
Marshevskyy Jul 20, 2026
d4c6f3b
fix(client-generator): snapshot release p2
Marshevskyy Jul 20, 2026
c1e7ce0
chore(examples): reference the published client-generator snapshot in…
Marshevskyy Jul 20, 2026
75b1cd6
fix(client-generator): publish the CLI snapshot before client-generator
Marshevskyy Jul 20, 2026
f11d5af
test(cli): per-api runtime-only block inherits shared generators and …
Marshevskyy Jul 20, 2026
a6c3064
chore(client-generator): docs updates
Marshevskyy Jul 20, 2026
0377b77
docs(client-generator): use native markdown tables in the client conf…
Marshevskyy Jul 20, 2026
91a6a0f
feat(client-generator): --import-ext ts for Node native TypeScript ex…
Marshevskyy Jul 20, 2026
dc3a114
docs(client-generator): move the Run with Node directly section to th…
Marshevskyy Jul 21, 2026
32cadfe
feat(client-generator): named operation closures, pagination hasMore …
Marshevskyy Jul 21, 2026
6d85483
chore(client-generator): strip review-oriented comments and type gymn…
Marshevskyy Jul 21, 2026
18df6c5
fix(client-generator): runtime-only package root, SSE request bodies,…
Marshevskyy Jul 21, 2026
7fc25e2
fix(client-generator): reference sdk schema types by their emitted na…
Marshevskyy Jul 22, 2026
98b7a89
fix(client-generator): fail fast on unresolved $refs instead of emitt…
Marshevskyy Jul 22, 2026
597866f
fix(client-generator): support 2XX/4XX/5XX response-code range wildcards
Marshevskyy Jul 22, 2026
96e7d50
Merge remote-tracking branch 'origin/main' into feat/ts-client-gen
Marshevskyy Jul 22, 2026
4d2e42c
fix(client-generator): type Swagger 2 path-item and shared parameters
Marshevskyy Jul 22, 2026
1a69986
fix(client-generator): map Swagger 2 collectionFormat to OAS3 query s…
Marshevskyy Jul 22, 2026
1de44a6
fix(client-generator): validate the API description structurally befo…
Marshevskyy Jul 23, 2026
4b7d6f6
docs(client-generator): disambiguate custom generators from publisher…
Marshevskyy Jul 23, 2026
cf10c61
docs(client-generator): disambiguate generators from setup and link b…
Marshevskyy Jul 23, 2026
8a94248
feat(client-generator)!: remove --enum-style — string enums always em…
Marshevskyy Jul 23, 2026
0437921
refactor(client-generator): replace --query-framework with tanstack-q…
Marshevskyy Jul 23, 2026
ab6b6c9
docs(client-generator): note the runtime serverUrl override next to -…
Marshevskyy Jul 23, 2026
07643e3
docs(client-generator): document the importless plain-object setup form
Marshevskyy Jul 23, 2026
7d4db8a
refactor(client-generator): rename mock-data baked to static, reservi…
Marshevskyy Jul 23, 2026
915af0e
fix(client-generator): transformers for ref/readonly date fields, moc…
Marshevskyy Jul 24, 2026
8375e45
fix(client-generator): survive operation/schema name collisions and m…
Marshevskyy Jul 24, 2026
875f298
fix(client-generator): rename schemas and operations that collide wit…
Marshevskyy Jul 24, 2026
9913cc5
refactor(client-generator): rename the codegen entry to generate and …
Marshevskyy Jul 24, 2026
21e345b
fix(client-generator): rename schemas that collide with derived auth …
Marshevskyy Jul 24, 2026
42d2fae
fix(client-generato): formatting
Marshevskyy Jul 24, 2026
00d2e49
fix(client-generator): keep derived names collision-free and align Op…
Marshevskyy Jul 24, 2026
4adcdc8
fix(client-generator): make generated output pass strict consumer lin…
Marshevskyy Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
9 changes: 9 additions & 0 deletions .changeset/client-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@redocly/client-generator': minor
'@redocly/openapi-core': minor
'@redocly/cli': minor
---

Added an experimental `generate-client` command that generates a typed, zero-dependency TypeScript client from an OpenAPI description — with auth, retries, middleware, typed SSE streaming, auto-pagination, and multipart support.
The `--generator` option emits companion modules from the same description: `zod`, `tanstack-query`, `swr`, `transformers`, and `mock`.
See the [`generate-client` command reference](https://redocly.com/docs/cli/commands/generate-client) and the [Use the generated client](https://redocly.com/docs/cli/guides/use-generated-client) guide.
16 changes: 13 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,11 @@ jobs:
cache: npm
registry-url: https://registry.npmjs.org

# Install before the version bump: npm links workspace packages only while
# their versions still match the dependency specs in package.json files.
- name: Install dependencies
run: npm install

- name: Update package versions
run: |
TIMESTAMP=$(date +%s)
Expand All @@ -218,6 +223,10 @@ jobs:
jq ".version = \"$VERSION\"" packages/respect-core/package.json > tmp.json && mv tmp.json packages/respect-core/package.json
jq ".dependencies[\"@redocly/openapi-core\"] = \"$VERSION\"" packages/respect-core/package.json > tmp.json && mv tmp.json packages/respect-core/package.json

# Update Client Generator package version and dependencies
jq ".version = \"$VERSION\"" packages/client-generator/package.json > tmp.json && mv tmp.json packages/client-generator/package.json
jq ".dependencies[\"@redocly/openapi-core\"] = \"$VERSION\"" packages/client-generator/package.json > tmp.json && mv tmp.json packages/client-generator/package.json

# Update CLI package version
jq ".version = \"$VERSION\"" packages/cli/package.json > tmp.json && mv tmp.json packages/cli/package.json

Expand All @@ -236,9 +245,6 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}

- name: Install dependencies
run: npm install

- name: Build packages
run: npm run compile

Expand All @@ -258,3 +264,7 @@ jobs:
npm run prepare:publish-dir
npm publish ./.publish --tag snapshot
npm run clean:publish-dir
sleep 10

cd ../client-generator
npm publish --tag snapshot
43 changes: 41 additions & 2 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
branches:
- main

permissions:
contents: read

env:
CI: true
REDOCLY_TELEMETRY: off
Expand All @@ -32,8 +35,44 @@ jobs:
continue-on-error: true # Do not fail if there is an error during reporting
uses: davelosert/vitest-coverage-report-action@d63aa97db4c0319f304f1787689de1ca548365cf # v2.11.1

- name: E2E Tests
run: npm run e2e
e2e:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for this change? The e2e job isn't a required check in the repo's settings, and it would be possible to merge a PR even with the job failing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We had canceled GH job without any reason. I tried to do deep research, this is a summary:

Tets started failing after we added more tests, there is no specific test impacting this. Only number of tests...
AI made some research:
What I ruled out with live in-job instrumentation (every metric healthy at the moment of cancel): RAM (~14 GB free), disk (~90 GB free), CPU/load, processes (~190), threads (~480), file descriptors (~2 500 of 65 536), sockets/TIME-WAIT, inodes (18 M free), kernel OOM (none). Also ruled out: parallel contention (serial --maxWorkers=1 still cancels, just later), network, log volume, and any single test (all pass locally and individually).

The decisive piece — from the runner's own _diag logs: the job token renews successfully every 60 s and console uploads succeed (1/1) right up to the cancel. So the runner stays healthy and connected; GitHub's service is deliberately cancelling a healthy job. The exact service-side reason isn't observable from inside — when the service cancels, it tears the step down and stops accepting console output, so streamed diag lines can't upload. That last mile needs GitHub support or org runner-group admin visibility

# The e2e suite is split across shards so no single runner carries the whole set.
# Running all suites in one step was cancelled mid-run by the Actions service once the
# generate-client suites grew past ~28 (a healthy runner, no resource exhaustion);
# each shard stays well under that.
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: E2E Tests (shard ${{ matrix.shard }}/2)
run: npm run e2e -- --shard=${{ matrix.shard }}/2

examples:
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
# The examples gitignore their generated clients (only zero-install-quickstart commits
# its canonical copy), so this job regenerates every client and type-checks the
# hand-written consumer code against it.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: 24
cache: npm
- name: Install dependencies
run: npm ci
- name: Regenerate example clients
run: npm run examples:regen -w @redocly/client-generator
- name: Type-check examples
run: npm run typecheck:examples -w @redocly/client-generator
Comment thread
Marshevskyy marked this conversation as resolved.

code-style-check:
runs-on: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
"packages/respect-core/src/modules/runtime-expressions/abnf-parser.js",
"packages/core/src/rules/common/__tests__/fixtures/invalid-yaml.yaml",
"tests/performance/api-definitions/",
"tests/e2e/generate-client/examples/*/src/api/",
"tests/e2e/generate-client/*-consumer/api*.ts",
"tests/smoke/**/*.yaml",
"snapshot*.txt",
"tests/e2e/generate-client/*.snapshot.ts",
"*.html",
"*.hbs",
"*.toml",
Expand Down
19 changes: 18 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@
"builtin": true,
"es2026": true
},
"ignorePatterns": ["packages/*/lib/**", "*.js", "*.cjs"],
"ignorePatterns": [
"packages/*/lib/**",
"*.js",
"*.cjs",
"tests/e2e/generate-client/examples/*/src/api/**",
"tests/e2e/generate-client/examples/*/generate.ts",
"tests/e2e/generate-client/*.snapshot.ts",
"tests/e2e/generate-client/*-consumer/api.ts"
],
"rules": {
"eslint/no-array-constructor": "error",
"eslint/no-case-declarations": "error",
Expand Down Expand Up @@ -68,6 +76,15 @@
"rules": {
"eslint/no-console": "allow"
}
},
{
"files": [
"tests/e2e/generate-client/examples/*/src/**",
"tests/e2e/generate-client/examples/*/worker.ts"
],
"rules": {
"eslint/no-console": "allow"
}
}
]
}
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ Run `npm test` to start both unit and e2e tests (and additionally typecheck the
### Unit tests

Run unit tests with this command: `npm run unit`.
This command runs the suite for every package whose tests match the discovery glob — there is no per-package `npm test` script.

Unit tests in the **cli** package are sensitive to top-level configuration file (**redocly.yaml**).

Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@ Respect is Redocly's community-edition product. Looking for something more? We a

Learn more about [Respect](https://redocly.com/respect) and [get started with API contract testing](https://redocly.com/docs/respect/get-started).

### Generate a TypeScript client

> ⚠️ **Experimental** — flags, output, and configuration may change in any minor release until declared stable.

Turn an OpenAPI description (3.0/3.1/3.2 or Swagger 2.0) into a typed TypeScript client with the `generate-client` command.
The emitted client has zero runtime dependencies and runs in browsers, Node, Bun, Deno, and edge runtimes.

```sh
redocly generate-client openapi.yaml --output src/client.ts
```

Inline types plus a typed client instance and one async function per operation, with auth, opt-in abort-aware retries, middleware, and typed Server-Sent Events.
The same command can also emit Zod schemas, TanStack Query / SWR hooks, MSW mocks, and more via `--generators`.
For detailed information, read the [ `generate-client` docs](./docs/@v2/commands/generate-client.md).

### Transform an OpenAPI description

If your OpenAPI description isn't everything you hoped it would be, enhance it with the Redocly [decorators](https://redocly.com/docs/cli/decorators) feature.
Expand Down
112 changes: 112 additions & 0 deletions docs/@v2/commands/generate-client.md
Comment thread
vadyvas marked this conversation as resolved.
Comment thread
vadyvas marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# `generate-client`

{% admonition type="warning" name="Experimental" %}
`generate-client` is an experimental feature: its flags, generated output, configuration schema, and custom-generator API may change in any minor release until it's stable.
We'd love your feedback while we stabilize it.
{% /admonition %}

## Introduction

The `generate-client` command generates a typed TypeScript client from an OpenAPI 3.x description.
Swagger 2.0 descriptions are also accepted and normalized to the 3.x shape before generation.
The description is validated first: unresolved `$ref`s or structural errors fail generation with the problems listed, independent of your lint configuration.

The generated client has zero runtime dependencies by default — it uses only web-standard APIs (`fetch`, `AbortController`, `URLSearchParams`), so it runs in browsers, Node, Bun, Deno, and edge runtimes.
By default it emits a single self-contained file with inline types and one async function per operation.

The `<api>` argument is a file path, a URL, or an [`apis:` alias](../configuration/index.md), resolved the same way as in other commands such as `bundle` and `lint`.
An alias, or a path matching an api's `root`, uses that api's `client` block and `clientOutput`; an unmatched path or URL uses the top-level `client` defaults.
With no argument, a client is generated for every api that declares a `client` block or a `clientOutput` (see [`client` configuration](../configuration/reference/client.md)).

This page covers running the command; for the generated client's runtime API (auth, error handling, middleware, retries, and the add-on generators), see [Use the generated client](../guides/use-generated-client.md).

## Usage

```bash
redocly generate-client
redocly generate-client <api>
redocly generate-client <api> [--output=<path>] [--output-mode=<mode>] [--runtime=<mode>]
redocly generate-client <api> [--generator=<name>] [--args-style=<style>] [--error-mode=<mode>]
redocly generate-client <api> [--config=<path>]
```

## Options

| Option | Type | Description |
| ---------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `api` | `string` | OpenAPI description file path, URL, or an `apis:` alias. Omit it to generate for every api that has a `client` block or `clientOutput`. |
| `--output`, `-o` | `string` | Output path (must end in `.ts`); the entry file in multi-file modes. Defaults to the api's `clientOutput`, else `<name>.client.ts` next to the configuration file. Single-API invocations only. |
| `--output-mode` | `string` | File layout. See [Choose an output mode](#choose-an-output-mode). <br/> **Possible values:** `single`, `split`. Default value is `single`. |
| `--runtime` | `string` | Where the client's engine lives. See [Choose a runtime](#choose-a-runtime). <br/> **Possible values:** `inline`, `package`. Default value is `inline`. |
| `--import-ext` | `string` | Extension in generated relative imports. See [Run with Node directly](../guides/use-generated-client.md#run-with-node-directly). <br/> **Possible values:** `js` (the tsc/bundler convention), `ts` (for Node's built-in type stripping). Default value is `js`. |
| `--generator` | `[string]` | Generator to run — a built-in name (`tanstack-query` also has `-vue`/`-svelte`/`-solid` variants) or a custom generator's path or package; repeat the flag to run several. Default value is `sdk`. See [Generators](../guides/use-generated-client.md#generators). |
| `--args-style` | `string` | How operation inputs are passed. See [Argument style](../guides/use-generated-client.md#argument-style). <br/> **Possible values:** `flat`, `grouped`. Default value is `flat`. |
| `--error-mode` | `string` | How operations report HTTP errors. See [Error handling](../guides/use-generated-client.md#error-handling). <br/> **Possible values:** `throw`, `result`. Default value is `throw`. |
| `--date-type` | `string` | Type of `date`/`date-time` fields; pair `Date` with the `transformers` generator. <br/> **Possible values:** `string`, `Date`. Default value is `string`. |
| `--mock-data` | `string` | Data mode for the `mock` generator. <br/> **Possible values:** `static` (deterministic literals), `faker` (`@faker-js/faker` calls). Default value is `static`. |
| `--mock-seed` | `number` | Seed for `faker`-mode mocks, for reproducible data. Ignored in `static` mode. |
| `--server-url` | `string` | Override the server URL baked into the client. Accepts an absolute (`https://api.example.com`) or relative (`/v1`) URL. Defaults to `servers[0].url`. The app can also repoint the client at runtime — `createClient({ serverUrl })` or `configure({ serverUrl })`, see [Authentication](../guides/use-generated-client.md#authentication) in the usage guide. |
| `--setup` | `string` | Path to a publisher setup module baked into the client. See [Publisher defaults](../guides/use-generated-client.md#publisher-defaults). |
| `--config` | `string` | Specify path to the [configuration file](#generate-from-the-configuration-file). |

## Examples

### Generate from the configuration file

Instead of passing flags every time, keep the settings in `redocly.yaml` under a top-level `client` block and per-API `apis.<name>.client` / `clientOutput` — see the [`client` configuration reference](../configuration/reference/client.md) for the fields and how they layer.
CLI flags take precedence over the configuration.
Auto-pagination has no CLI flag; it's declared only as [`client.pagination`](../configuration/reference/client.md#pagination-object) configuration or the `x-pagination` operation extension.

```yaml
client:
generators:
- sdk
apis:
cafe:
root: ./openapi.yaml
clientOutput: ./src/api/client.ts
```

```bash
redocly generate-client # every api with a `client` block or `clientOutput`
redocly generate-client cafe # just the `cafe` api
```

### Generate from a file path or URL

An unmatched path or URL uses the top-level `client` defaults; `--output` names the entry file:

```bash
redocly generate-client openapi.yaml --output dist/client.ts
```

### Choose an output mode

`--output-mode` controls how the client is split across files:

- `single` (default) — one file (self-contained with the default `inline` runtime).
- `split` — two files: the schema types and type guards move to a sibling `<name>.schemas.ts`, and the entry file re-exports them, so your imports are the same as in `single`.

```bash
redocly generate-client openapi.yaml -o src/api/client.ts --output-mode split
```

Both modes work with both runtimes.

### Choose a runtime

`--runtime` controls where the client's engine (request building, auth, retries, middleware, SSE) lives:

- `inline` (default) — the runtime source is embedded in the generated output (only the parts your API needs): self-contained, zero runtime dependencies.
- `package` — the generated file imports the runtime from `@redocly/client-generator` and contains only the types, operation descriptors, and thin call wrappers.

Choose `package` when you want engine fixes to arrive via `npm update @redocly/client-generator` with no regeneration; the consuming app must then have that package installed as a regular dependency.
Your application code is identical in both modes.
See [Package runtime](../guides/use-generated-client.md#package-runtime) in the usage guide and the [`package-runtime` example](https://github.com/Redocly/redocly-cli/tree/main/tests/e2e/generate-client/examples/package-runtime).

## Resources

- [Use the generated client](../guides/use-generated-client.md) — the runtime API and the add-on generators.
- [`client` configuration](../configuration/reference/client.md) — the `redocly.yaml` `client` block.
- [Lint command](./lint.md) to validate your API description before generating a client.
- [Bundle command](./bundle.md) to combine a multi-file description into a single input file.
1 change: 1 addition & 0 deletions docs/@v2/commands/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Documentation commands:
API management commands:

- [`bundle`](bundle.md) Bundle API description.
- [`generate-client`](generate-client.md) Generate a typed TypeScript client from an OpenAPI description [experimental feature].
- [`join`](join.md) Join API descriptions [experimental feature].
- [`score`](score.md) Score an API for integration simplicity and AI agent readiness.
- [`split`](split.md) Split API description into a multi-file structure.
Expand Down
12 changes: 12 additions & 0 deletions docs/@v2/configuration/reference/apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ If your project contains multiple APIs, the `apis` configuration section allows
- Output file path
- When running `bundle` without specifying an API, the bundled API description is saved to this location.

---

- client
- [Client object](./client.md)
- Additional TypeScript client generation configuration for this API, used by the experimental `generate-client` command.

---

- clientOutput

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should the output be inside of client?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really, we wanted to follow existing approach of config, discusssed with @tatomyr

- Output file path
- When running `generate-client` without specifying an API, the generated TypeScript client is saved to this location.

{% /table %}

## Examples
Expand Down
Loading
Loading