@orpc/zod 0.0.0-next.75f1e0e β 0.0.0-next.7605f6c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -16
- package/dist/index.d.mts +16 -7
- package/dist/index.d.ts +16 -7
- package/dist/index.mjs +94 -46
- package/dist/zod4/index.d.mts +22 -10
- package/dist/zod4/index.d.ts +22 -10
- package/dist/zod4/index.mjs +91 -47
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<image align="center" src="https://orpc.
|
|
2
|
+
<image align="center" src="https://orpc.dev/logo.webp" width=280 alt="oRPC logo" />
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
5
|
<h1></h1>
|
|
6
6
|
|
|
7
7
|
<div align="center">
|
|
8
|
-
<a href="https://codecov.io/gh/
|
|
9
|
-
<img alt="codecov" src="https://codecov.io/gh/
|
|
8
|
+
<a href="https://codecov.io/gh/middleapi/orpc">
|
|
9
|
+
<img alt="codecov" src="https://codecov.io/gh/middleapi/orpc/branch/main/graph/badge.svg">
|
|
10
10
|
</a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/@orpc/zod">
|
|
12
12
|
<img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fzod?logo=npm" />
|
|
13
13
|
</a>
|
|
14
|
-
<a href="https://github.com/
|
|
15
|
-
<img alt="MIT License" src="https://img.shields.io/github/license/
|
|
14
|
+
<a href="https://github.com/middleapi/orpc/blob/main/LICENSE">
|
|
15
|
+
<img alt="MIT License" src="https://img.shields.io/github/license/middleapi/orpc?logo=open-source-initiative" />
|
|
16
16
|
</a>
|
|
17
17
|
<a href="https://discord.gg/TXEbwRBvQn">
|
|
18
18
|
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
|
|
19
19
|
</a>
|
|
20
|
+
<a href="https://deepwiki.com/middleapi/orpc">
|
|
21
|
+
<img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
|
|
22
|
+
</a>
|
|
20
23
|
</div>
|
|
21
24
|
|
|
22
25
|
<h3 align="center">Typesafe APIs Made Simple πͺ</h3>
|
|
@@ -30,7 +33,8 @@
|
|
|
30
33
|
- **π End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
|
|
31
34
|
- **π First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
|
|
32
35
|
- **π Contract-First Development**: Optionally define your API contract before implementation.
|
|
33
|
-
-
|
|
36
|
+
- **π First-Class OpenTelemetry**: Seamlessly integrate with OpenTelemetry for observability.
|
|
37
|
+
- **βοΈ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), SWR, Pinia Colada, and more.
|
|
34
38
|
- **π Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
|
|
35
39
|
- **π Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
|
|
36
40
|
- **ποΈ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
|
|
@@ -38,11 +42,10 @@
|
|
|
38
42
|
- **π‘ SSE & Streaming**: Enjoy full type-safe support for SSE and streaming.
|
|
39
43
|
- **π Multi-Runtime Support**: Fast and lightweight on Cloudflare, Deno, Bun, Node.js, and beyond.
|
|
40
44
|
- **π Extendability**: Easily extend functionality with plugins, middleware, and interceptors.
|
|
41
|
-
- **π‘οΈ Reliability**: Well-tested, TypeScript-based, production-ready, and MIT licensed.
|
|
42
45
|
|
|
43
46
|
## Documentation
|
|
44
47
|
|
|
45
|
-
You can find the full documentation [here](https://orpc.
|
|
48
|
+
You can find the full documentation [here](https://orpc.dev).
|
|
46
49
|
|
|
47
50
|
## Packages
|
|
48
51
|
|
|
@@ -50,9 +53,11 @@ You can find the full documentation [here](https://orpc.unnoq.com).
|
|
|
50
53
|
- [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract.
|
|
51
54
|
- [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety.
|
|
52
55
|
- [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
|
|
56
|
+
- [@orpc/otel](https://www.npmjs.com/package/@orpc/otel): [OpenTelemetry](https://opentelemetry.io/) integration for observability.
|
|
53
57
|
- [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Deeply integrate oRPC with [NestJS](https://nestjs.com/).
|
|
54
58
|
- [@orpc/react](https://www.npmjs.com/package/@orpc/react): Utilities for integrating oRPC with React and React Server Actions.
|
|
55
59
|
- [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): [TanStack Query](https://tanstack.com/query/latest) integration.
|
|
60
|
+
- [@orpc/experimental-react-swr](https://www.npmjs.com/package/@orpc/experimental-react-swr): [SWR](https://swr.vercel.app/) integration.
|
|
56
61
|
- [@orpc/vue-colada](https://www.npmjs.com/package/@orpc/vue-colada): Integration with [Pinia Colada](https://pinia-colada.esm.dev/).
|
|
57
62
|
- [@orpc/hey-api](https://www.npmjs.com/package/@orpc/hey-api): [Hey API](https://heyapi.dev/) integration.
|
|
58
63
|
- [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): More schemas that [Zod](https://zod.dev/) doesn't support yet.
|
|
@@ -72,7 +77,7 @@ More schemas that [Zod](https://zod.dev/) doesn't support yet, and provides `Zod
|
|
|
72
77
|
|
|
73
78
|
```ts
|
|
74
79
|
import { oz } from '@orpc/zod'
|
|
75
|
-
import { z } from 'zod'
|
|
80
|
+
import { z } from 'zod/v3'
|
|
76
81
|
|
|
77
82
|
const Example = z.object({
|
|
78
83
|
url: oz.url(),
|
|
@@ -86,7 +91,7 @@ const Example = z.object({
|
|
|
86
91
|
|
|
87
92
|
```ts
|
|
88
93
|
import { OpenAPIGenerator } from '@orpc/openapi'
|
|
89
|
-
import { ZodToJsonSchemaConverter } from '@orpc/zod'
|
|
94
|
+
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'
|
|
90
95
|
|
|
91
96
|
const openAPIGenerator = new OpenAPIGenerator({
|
|
92
97
|
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
@@ -111,7 +116,7 @@ const specFromRouter = await openAPIGenerator.generate(router, {
|
|
|
111
116
|
|
|
112
117
|
```ts
|
|
113
118
|
import { oz } from '@orpc/zod'
|
|
114
|
-
import
|
|
119
|
+
import * as z from 'zod'
|
|
115
120
|
|
|
116
121
|
const InputSchema = oz.openapi(
|
|
117
122
|
z.object({
|
|
@@ -129,12 +134,119 @@ const InputSchema = oz.openapi(
|
|
|
129
134
|
|
|
130
135
|
## Sponsors
|
|
131
136
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
137
|
+
If you find oRPC valuable and would like to support its development, you can do so here: [GitHub Sponsors](https://github.com/sponsors/dinwwwh).
|
|
138
|
+
|
|
139
|
+
### π Platinum Sponsor
|
|
140
|
+
|
|
141
|
+
<table>
|
|
142
|
+
<tr>
|
|
143
|
+
<td align="center"><a href="https://screenshotone.com/?ref=orpc" target="_blank" rel="noopener" title="ScreenshotOne.com"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="279" alt="ScreenshotOne.com"/><br />ScreenshotOne.com</a></td>
|
|
144
|
+
</tr>
|
|
145
|
+
</table>
|
|
146
|
+
|
|
147
|
+
### π₯ Silver Sponsor
|
|
148
|
+
|
|
149
|
+
<table>
|
|
150
|
+
<tr>
|
|
151
|
+
<td align="center"><a href="https://misskey.io/?ref=orpc" target="_blank" rel="noopener" title="ζδΈγγ"><img src="https://avatars.githubusercontent.com/u/37681609?u=0dd4c7e4ba937cbb52b068c55914b1d8164dc0c7&v=4" width="209" alt="ζδΈγγ"/><br />ζδΈγγ</a></td>
|
|
152
|
+
</tr>
|
|
153
|
+
</table>
|
|
154
|
+
|
|
155
|
+
### Generous Sponsors
|
|
156
|
+
|
|
157
|
+
<table>
|
|
158
|
+
<tr>
|
|
159
|
+
<td align="center"><a href="https://github.com/ln-markets?ref=orpc" target="_blank" rel="noopener" title="LN Markets"><img src="https://avatars.githubusercontent.com/u/70597625?v=4" width="167" alt="LN Markets"/><br />LN Markets</a></td>
|
|
160
|
+
</tr>
|
|
161
|
+
</table>
|
|
162
|
+
|
|
163
|
+
### Sponsors
|
|
164
|
+
|
|
165
|
+
<table>
|
|
166
|
+
<tr>
|
|
167
|
+
<td align="center"><a href="https://github.com/hrmcdonald?ref=orpc" target="_blank" rel="noopener" title="Reece McDonald"><img src="https://avatars.githubusercontent.com/u/39349270?v=4" width="139" alt="Reece McDonald"/><br />Reece McDonald</a></td>
|
|
168
|
+
<td align="center"><a href="https://github.com/nicognaW?ref=orpc" target="_blank" rel="noopener" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&v=4" width="139" alt="nk"/><br />nk</a></td>
|
|
169
|
+
<td align="center"><a href="https://github.com/supastarter?ref=orpc" target="_blank" rel="noopener" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="139" alt="supastarter"/><br />supastarter</a></td>
|
|
170
|
+
<td align="center"><a href="https://github.com/divmgl?ref=orpc" target="_blank" rel="noopener" title="Dexter Miguel"><img src="https://avatars.githubusercontent.com/u/5452298?u=645993204be8696c085ecf0d228c3062efe2ed65&v=4" width="139" alt="Dexter Miguel"/><br />Dexter Miguel</a></td>
|
|
171
|
+
<td align="center"><a href="https://github.com/herrfugbaum?ref=orpc" target="_blank" rel="noopener" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&v=4" width="139" alt="herrfugbaum"/><br />herrfugbaum</a></td>
|
|
172
|
+
<td align="center"><a href="https://github.com/ryota-murakami?ref=orpc" target="_blank" rel="noopener" title="Ryota Murakami"><img src="https://avatars.githubusercontent.com/u/5501268?u=599389e03340734325726ca3f8f423c021d47d7f&v=4" width="139" alt="Ryota Murakami"/><br />Ryota Murakami</a></td>
|
|
173
|
+
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<td align="center"><a href="https://github.com/dcramer?ref=orpc" target="_blank" rel="noopener" title="David Cramer"><img src="https://avatars.githubusercontent.com/u/23610?v=4" width="139" alt="David Cramer"/><br />David Cramer</a></td>
|
|
176
|
+
<td align="center"><a href="https://github.com/valerii15298?ref=orpc" target="_blank" rel="noopener" title="Valerii Petryniak"><img src="https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4" width="139" alt="Valerii Petryniak"/><br />Valerii Petryniak</a></td>
|
|
177
|
+
<td align="center"><a href="https://github.com/letstri?ref=orpc" target="_blank" rel="noopener" title="Valerii Strilets"><img src="https://avatars.githubusercontent.com/u/13253748?u=c7b10399ccc8f8081e24db94ec32cd9858e86ac3&v=4" width="139" alt="Valerii Strilets"/><br />Valerii Strilets</a></td>
|
|
178
|
+
<td align="center"><a href="https://github.com/K-Mistele?ref=orpc" target="_blank" rel="noopener" title="Kyle Mistele"><img src="https://avatars.githubusercontent.com/u/18430555?u=3afebeb81de666e35aaac3ed46f14159d7603ffb&v=4" width="139" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
|
|
179
|
+
<td align="center"><a href="https://github.com/andrewpeters9?ref=orpc" target="_blank" rel="noopener" title="Andrew Peters"><img src="https://avatars.githubusercontent.com/u/36251325?v=4" width="139" alt="Andrew Peters"/><br />Andrew Peters</a></td>
|
|
180
|
+
<td align="center"><a href="https://github.com/R44VC0RP?ref=orpc" target="_blank" rel="noopener" title="Ryan Vogel"><img src="https://avatars.githubusercontent.com/u/89211796?u=1857347b9787d8d8a7ea5bfc333f96be92d5a683&v=4" width="139" alt="Ryan Vogel"/><br />Ryan Vogel</a></td>
|
|
181
|
+
</tr>
|
|
182
|
+
<tr>
|
|
183
|
+
<td align="center"><a href="https://github.com/christ12938?ref=orpc" target="_blank" rel="noopener" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="139" alt="christ12938"/><br />christ12938</a></td>
|
|
184
|
+
<td align="center"><a href="https://github.com/peter-adam-dy?ref=orpc" target="_blank" rel="noopener" title="Peter Adam"><img src="https://avatars.githubusercontent.com/u/132129459?u=4f3dbbb3b443990b56acb7d6a5d11ed2c555f6db&v=4" width="139" alt="Peter Adam"/><br />Peter Adam</a></td>
|
|
185
|
+
<td align="center"><a href="https://github.com/yukimotochern?ref=orpc" target="_blank" rel="noopener" title="Chen, Zhi-Yuan"><img src="https://avatars.githubusercontent.com/u/20896173?u=945c33fc21725e4d566a0d02afc54b136ca1d67a&v=4" width="139" alt="Chen, Zhi-Yuan"/><br />Chen, Zhi-Yuan</a></td>
|
|
186
|
+
<td align="center"><a href="https://github.com/Ryanjso?ref=orpc" target="_blank" rel="noopener" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&v=4" width="139" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
|
|
187
|
+
</tr>
|
|
188
|
+
</table>
|
|
189
|
+
|
|
190
|
+
### Backers
|
|
191
|
+
|
|
192
|
+
<table>
|
|
193
|
+
<tr>
|
|
194
|
+
<td align="center"><a href="https://github.com/rhinodavid?ref=orpc" target="_blank" rel="noopener" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&v=4" width="119" alt="David Walsh"/><br />David Walsh</a></td>
|
|
195
|
+
<td align="center"><a href="https://github.com/Robbe95?ref=orpc" target="_blank" rel="noopener" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&v=4" width="119" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>
|
|
196
|
+
<td align="center"><a href="https://github.com/aidansunbury?ref=orpc" target="_blank" rel="noopener" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="119" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>
|
|
197
|
+
<td align="center"><a href="https://github.com/soonoo?ref=orpc" target="_blank" rel="noopener" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&v=4" width="119" alt="soonoo"/><br />soonoo</a></td>
|
|
198
|
+
<td align="center"><a href="https://github.com/kporten?ref=orpc" target="_blank" rel="noopener" title="Kevin Porten"><img src="https://avatars.githubusercontent.com/u/1839345?u=dc2263d5cfe0d927ce1a0be04a1d55dd6b55405c&v=4" width="119" alt="Kevin Porten"/><br />Kevin Porten</a></td>
|
|
199
|
+
<td align="center"><a href="https://github.com/pumpkinlink?ref=orpc" target="_blank" rel="noopener" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&v=4" width="119" alt="Denis"/><br />Denis</a></td>
|
|
200
|
+
<td align="center"><a href="https://github.com/christopher-kapic?ref=orpc" target="_blank" rel="noopener" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
|
|
201
|
+
</tr>
|
|
202
|
+
<tr>
|
|
203
|
+
<td align="center"><a href="https://github.com/thomasballinger?ref=orpc" target="_blank" rel="noopener" title="Tom Ballinger"><img src="https://avatars.githubusercontent.com/u/458879?u=4b045ac75d721b6ac2b42a74d7d37f61f0414031&v=4" width="119" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>
|
|
204
|
+
<td align="center"><a href="https://github.com/SSam0419?ref=orpc" target="_blank" rel="noopener" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&v=4" width="119" alt="Sam"/><br />Sam</a></td>
|
|
205
|
+
<td align="center"><a href="https://github.com/Titoine?ref=orpc" target="_blank" rel="noopener" title="Titoine"><img src="https://avatars.githubusercontent.com/u/3514286?u=1bb1e86b0c99c8a1121372e56d51a177eea12191&v=4" width="119" alt="Titoine"/><br />Titoine</a></td>
|
|
206
|
+
<td align="center"><a href="https://github.com/Mnigos?ref=orpc" target="_blank" rel="noopener" title="Igor Makowski"><img src="https://avatars.githubusercontent.com/u/56691628?u=ee8c879478f7c151b9156aef6c74243fa3e247a8&v=4" width="119" alt="Igor Makowski"/><br />Igor Makowski</a></td>
|
|
207
|
+
<td align="center"><a href="https://github.com/steelbrain?ref=orpc" target="_blank" rel="noopener" title="Anees Iqbal"><img src="https://avatars.githubusercontent.com/u/4278113?u=22b80b5399eed68ac76cd58b02961b0481f1db11&v=4" width="119" alt="Anees Iqbal"/><br />Anees Iqbal</a></td>
|
|
208
|
+
<td align="center"><a href="https://github.com/hanayashiki?ref=orpc" target="_blank" rel="noopener" title="wang chenyu"><img src="https://avatars.githubusercontent.com/u/26056783?u=06c3b9205a16fd41a871e82da1cc2a09306d53f5&v=4" width="119" alt="wang chenyu"/><br />wang chenyu</a></td>
|
|
209
|
+
<td align="center"><a href="https://github.com/piscis?ref=orpc" target="_blank" rel="noopener" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="119" alt="Alex"/><br />Alex</a></td>
|
|
210
|
+
</tr>
|
|
211
|
+
<tr>
|
|
212
|
+
<td align="center"><a href="https://github.com/nattstack?ref=orpc" target="_blank" rel="noopener" title="nattstack"><img src="https://avatars.githubusercontent.com/u/31426677?u=fa9dbb8b3e66eb0ea3c88db5dc07f31c8c5418fe&v=4" width="119" alt="nattstack"/><br />nattstack</a></td>
|
|
213
|
+
</tr>
|
|
214
|
+
</table>
|
|
215
|
+
|
|
216
|
+
### Past Sponsors
|
|
217
|
+
|
|
218
|
+
<p>
|
|
219
|
+
<a href="https://github.com/MrMaxie?ref=orpc" target="_blank" rel="noopener" title="Maxie"><img src="https://avatars.githubusercontent.com/u/3857836?u=5e6b57973d4385d655663ffdd836e487856f2984&v=4" width="32" height="32" alt="Maxie" /></a>
|
|
220
|
+
<a href="https://github.com/Stijn-Timmer?ref=orpc" target="_blank" rel="noopener" title="Stijn Timmer"><img src="https://avatars.githubusercontent.com/u/100147665?u=106b2c18e9c98a61861b4ee7fc100f5b9906a6c9&v=4" width="32" height="32" alt="Stijn Timmer" /></a>
|
|
221
|
+
<a href="https://github.com/u1-liquid?ref=orpc" target="_blank" rel="noopener" title="γγγγγ¨γΌγ«γ
"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&v=4" width="32" height="32" alt="γγγγγ¨γΌγ«γ
" /></a>
|
|
222
|
+
<a href="https://github.com/zuplo?ref=orpc" target="_blank" rel="noopener" title="Zuplo"><img src="https://avatars.githubusercontent.com/u/85497839?v=4" width="32" height="32" alt="Zuplo" /></a>
|
|
223
|
+
<a href="https://github.com/motopods?ref=orpc" target="_blank" rel="noopener" title="motopods"><img src="https://avatars.githubusercontent.com/u/58200641?u=18833983d65b481ae90a4adec2373064ec58bcf3&v=4" width="32" height="32" alt="motopods" /></a>
|
|
224
|
+
<a href="https://github.com/franciscohermida?ref=orpc" target="_blank" rel="noopener" title="Francisco Hermida"><img src="https://avatars.githubusercontent.com/u/483242?u=bbcbc80eb9d8781ff401f7dafc3b59cd7bea0561&v=4" width="32" height="32" alt="Francisco Hermida" /></a>
|
|
225
|
+
<a href="https://github.com/theoludwig?ref=orpc" target="_blank" rel="noopener" title="ThΓ©o LUDWIG"><img src="https://avatars.githubusercontent.com/u/25207499?u=a6a9653725a2f574c07893748806668e0598cdbe&v=4" width="32" height="32" alt="ThΓ©o LUDWIG" /></a>
|
|
226
|
+
<a href="https://github.com/abhay-ramesh?ref=orpc" target="_blank" rel="noopener" title="Abhay Ramesh"><img src="https://avatars.githubusercontent.com/u/66196314?u=c5c2b0327b26606c2efcfaf17046ab18c3d25c57&v=4" width="32" height="32" alt="Abhay Ramesh" /></a>
|
|
227
|
+
<a href="https://github.com/shr-ink?ref=orpc" target="_blank" rel="noopener" title="shr.ink oΓΌ"><img src="https://avatars.githubusercontent.com/u/139700438?v=4" width="32" height="32" alt="shr.ink oΓΌ" /></a>
|
|
228
|
+
<a href="https://github.com/johngerome?ref=orpc" target="_blank" rel="noopener" title="0x4e32"><img src="https://avatars.githubusercontent.com/u/2002000?u=24e8dd943cfc862aa284d858a023532c75071ade&v=4" width="32" height="32" alt="0x4e32" /></a>
|
|
229
|
+
<a href="https://github.com/yzuyr?ref=orpc" target="_blank" rel="noopener" title="Ryuz"><img src="https://avatars.githubusercontent.com/u/196539378?u=d38374588d219b6748b16406982f6559411466d4&v=4" width="32" height="32" alt="Ryuz" /></a>
|
|
230
|
+
<a href="https://github.com/happyboy2022?ref=orpc" target="_blank" rel="noopener" title="happyboy"><img src="https://avatars.githubusercontent.com/u/103669586?u=65b49c4b893ed3703909fbb3a7a22313f3f9c121&v=4" width="32" height="32" alt="happyboy" /></a>
|
|
231
|
+
<a href="https://github.com/YiCChi?ref=orpc" target="_blank" rel="noopener" title="yicchi"><img src="https://avatars.githubusercontent.com/u/86967274?u=6c2756f09fe15dd94d572f560e979cd157982852&v=4" width="32" height="32" alt="yicchi" /></a>
|
|
232
|
+
<a href="https://github.com/cloudycotton?ref=orpc" target="_blank" rel="noopener" title="Saksham"><img src="https://avatars.githubusercontent.com/u/168998965?u=9b9634a5aed66a51c1b880663272725b00b92b14&v=4" width="32" height="32" alt="Saksham" /></a>
|
|
233
|
+
<a href="https://github.com/hrynevychroman?ref=orpc" target="_blank" rel="noopener" title="Roman Hrynevych"><img src="https://avatars.githubusercontent.com/u/82209198?u=1a1d111ab3d589855b9cc8a7fefb1b5c6a4fbbaf&v=4" width="32" height="32" alt="Roman Hrynevych" /></a>
|
|
234
|
+
<a href="https://github.com/rokitgg?ref=orpc" target="_blank" rel="noopener" title="rokitg"><img src="https://avatars.githubusercontent.com/u/125133357?u=06c74aefaa2236b06a2e5fba5a5c612339f45912&v=4" width="32" height="32" alt="rokitg" /></a>
|
|
235
|
+
<a href="https://github.com/omarkhatibgg?ref=orpc" target="_blank" rel="noopener" title="Omar Khatib"><img src="https://avatars.githubusercontent.com/u/9054278?u=afbba7331b85c51b8eee4130f5fd31b1017dc919&v=4" width="32" height="32" alt="Omar Khatib" /></a>
|
|
236
|
+
<a href="https://github.com/YuSabo90002?ref=orpc" target="_blank" rel="noopener" title="Yu-Sabo"><img src="https://avatars.githubusercontent.com/u/13120582?v=4" width="32" height="32" alt="Yu-Sabo" /></a>
|
|
237
|
+
<a href="https://github.com/bapspatil?ref=orpc" target="_blank" rel="noopener" title="Bapusaheb Patil"><img src="https://avatars.githubusercontent.com/u/16699418?u=6d9d8e0a64a6f91ca1c4d559c72d931172bdcbbd&v=4" width="32" height="32" alt="Bapusaheb Patil" /></a>
|
|
238
|
+
<a href="https://github.com/ripgrim?ref=orpc" target="_blank" rel="noopener" title="grim"><img src="https://avatars.githubusercontent.com/u/75869731?u=b17c42ec2309552fdb822a86b25a2f99146a4d72&v=4" width="32" height="32" alt="grim" /></a>
|
|
239
|
+
<a href="https://github.com/nelsonlaidev?ref=orpc" target="_blank" rel="noopener" title="Nelson Lai"><img src="https://avatars.githubusercontent.com/u/75498339?u=2fc0e0b95dd184c5ffb744df977cb15a18b60672&v=4" width="32" height="32" alt="Nelson Lai" /></a>
|
|
240
|
+
<a href="https://github.com/nguyenlc1993?ref=orpc" target="_blank" rel="noopener" title="LΓͺ Cao NguyΓͺn"><img src="https://avatars.githubusercontent.com/u/13871971?u=83c8b69d9e35b589c4e1f066cc113b1d9461386f&v=4" width="32" height="32" alt="LΓͺ Cao NguyΓͺn" /></a>
|
|
241
|
+
<a href="https://github.com/wobsoriano?ref=orpc" target="_blank" rel="noopener" title="Robert Soriano"><img src="https://avatars.githubusercontent.com/u/13049130?u=6d72104182e7c9ed25934815313fb69107332111&v=4" width="32" height="32" alt="Robert Soriano" /></a>
|
|
242
|
+
<a href="https://github.com/SKostyukovich?ref=orpc" target="_blank" rel="noopener" title="SKostyukovich"><img src="https://avatars.githubusercontent.com/u/10700067?v=4" width="32" height="32" alt="SKostyukovich" /></a>
|
|
243
|
+
<a href="https://github.com/FabworksHQ?ref=orpc" target="_blank" rel="noopener" title="Fabworks"><img src="https://avatars.githubusercontent.com/u/160179500?v=4" width="32" height="32" alt="Fabworks" /></a>
|
|
244
|
+
<a href="https://github.com/NovakAnton?ref=orpc" target="_blank" rel="noopener" title="Novak Antonijevic"><img src="https://avatars.githubusercontent.com/u/157126729?u=ae49fa22292d55c0434ff0ca008206155b18663b&v=4" width="32" height="32" alt="Novak Antonijevic" /></a>
|
|
245
|
+
<a href="https://github.com/laduniestu?ref=orpc" target="_blank" rel="noopener" title="Laduni Estu Syalwa"><img src="https://avatars.githubusercontent.com/u/44757637?u=a2fc1ea8f7d827a96721176f79d30592d1c48059&v=4" width="32" height="32" alt="Laduni Estu Syalwa" /></a>
|
|
246
|
+
<a href="https://github.com/illarionvk?ref=orpc" target="_blank" rel="noopener" title="Illarion Koperski"><img src="https://avatars.githubusercontent.com/u/5012724?u=7cfa13652f7ac5fb3c56d880e3eb3fbe40c3ea34&v=4" width="32" height="32" alt="Illarion Koperski" /></a>
|
|
247
|
+
<a href="https://github.com/Scrumplex?ref=orpc" target="_blank" rel="noopener" title="Sefa Eyeoglu"><img src="https://avatars.githubusercontent.com/u/11587657?u=ab503582165c0bbff0cca47ce31c9450bb1553c9&v=4" width="32" height="32" alt="Sefa Eyeoglu" /></a>
|
|
136
248
|
</p>
|
|
137
249
|
|
|
138
250
|
## License
|
|
139
251
|
|
|
140
|
-
Distributed under the MIT License. See [LICENSE](https://github.com/
|
|
252
|
+
Distributed under the MIT License. See [LICENSE](https://github.com/middleapi/orpc/blob/main/LICENSE) for more information.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSONSchema, ConditionalSchemaConverter, SchemaConvertOptions } from '@orpc/openapi';
|
|
2
|
-
import { ZodTypeAny, input, output, ZodTypeDef, CustomErrorParams, ZodType, ZodEffects } from 'zod';
|
|
2
|
+
import { ZodTypeAny, input, output, ZodTypeDef, CustomErrorParams, ZodType, ZodEffects } from 'zod/v3';
|
|
3
3
|
import { Context } from '@orpc/server';
|
|
4
4
|
import { StandardHandlerPlugin, StandardHandlerOptions } from '@orpc/server/standard';
|
|
5
5
|
import { AnySchema } from '@orpc/contract';
|
|
@@ -40,34 +40,43 @@ declare class ZodSmartCoercionPlugin<TContext extends Context> implements Standa
|
|
|
40
40
|
|
|
41
41
|
interface ZodToJsonSchemaOptions {
|
|
42
42
|
/**
|
|
43
|
-
* Max depth of lazy type
|
|
43
|
+
* Max depth of lazy type
|
|
44
44
|
*
|
|
45
|
-
* Used `{}` when
|
|
45
|
+
* Used `{}` when exceed max depth
|
|
46
46
|
*
|
|
47
47
|
* @default 3
|
|
48
48
|
*/
|
|
49
49
|
maxLazyDepth?: number;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Max depth of nested types
|
|
52
52
|
*
|
|
53
|
-
*
|
|
53
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
54
|
+
*
|
|
55
|
+
* @default 10
|
|
54
56
|
*/
|
|
55
|
-
|
|
57
|
+
maxStructureDepth?: number;
|
|
56
58
|
/**
|
|
57
59
|
* The schema to be used to represent the any | unknown type.
|
|
58
60
|
*
|
|
59
61
|
* @default { }
|
|
60
62
|
*/
|
|
61
63
|
anyJsonSchema?: Exclude<JSONSchema, boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* The schema to be used when the Zod schema is unsupported.
|
|
66
|
+
*
|
|
67
|
+
* @default { not: {} }
|
|
68
|
+
*/
|
|
69
|
+
unsupportedJsonSchema?: Exclude<JSONSchema, boolean>;
|
|
62
70
|
}
|
|
63
71
|
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
|
64
72
|
#private;
|
|
65
73
|
private readonly maxLazyDepth;
|
|
74
|
+
private readonly maxStructureDepth;
|
|
66
75
|
private readonly unsupportedJsonSchema;
|
|
67
76
|
private readonly anyJsonSchema;
|
|
68
77
|
constructor(options?: ZodToJsonSchemaOptions);
|
|
69
78
|
condition(schema: AnySchema | undefined): boolean;
|
|
70
|
-
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
79
|
+
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean, structureDepth?: number): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
declare const oz: {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { JSONSchema, ConditionalSchemaConverter, SchemaConvertOptions } from '@orpc/openapi';
|
|
2
|
-
import { ZodTypeAny, input, output, ZodTypeDef, CustomErrorParams, ZodType, ZodEffects } from 'zod';
|
|
2
|
+
import { ZodTypeAny, input, output, ZodTypeDef, CustomErrorParams, ZodType, ZodEffects } from 'zod/v3';
|
|
3
3
|
import { Context } from '@orpc/server';
|
|
4
4
|
import { StandardHandlerPlugin, StandardHandlerOptions } from '@orpc/server/standard';
|
|
5
5
|
import { AnySchema } from '@orpc/contract';
|
|
@@ -40,34 +40,43 @@ declare class ZodSmartCoercionPlugin<TContext extends Context> implements Standa
|
|
|
40
40
|
|
|
41
41
|
interface ZodToJsonSchemaOptions {
|
|
42
42
|
/**
|
|
43
|
-
* Max depth of lazy type
|
|
43
|
+
* Max depth of lazy type
|
|
44
44
|
*
|
|
45
|
-
* Used `{}` when
|
|
45
|
+
* Used `{}` when exceed max depth
|
|
46
46
|
*
|
|
47
47
|
* @default 3
|
|
48
48
|
*/
|
|
49
49
|
maxLazyDepth?: number;
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
51
|
+
* Max depth of nested types
|
|
52
52
|
*
|
|
53
|
-
*
|
|
53
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
54
|
+
*
|
|
55
|
+
* @default 10
|
|
54
56
|
*/
|
|
55
|
-
|
|
57
|
+
maxStructureDepth?: number;
|
|
56
58
|
/**
|
|
57
59
|
* The schema to be used to represent the any | unknown type.
|
|
58
60
|
*
|
|
59
61
|
* @default { }
|
|
60
62
|
*/
|
|
61
63
|
anyJsonSchema?: Exclude<JSONSchema, boolean>;
|
|
64
|
+
/**
|
|
65
|
+
* The schema to be used when the Zod schema is unsupported.
|
|
66
|
+
*
|
|
67
|
+
* @default { not: {} }
|
|
68
|
+
*/
|
|
69
|
+
unsupportedJsonSchema?: Exclude<JSONSchema, boolean>;
|
|
62
70
|
}
|
|
63
71
|
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
|
64
72
|
#private;
|
|
65
73
|
private readonly maxLazyDepth;
|
|
74
|
+
private readonly maxStructureDepth;
|
|
66
75
|
private readonly unsupportedJsonSchema;
|
|
67
76
|
private readonly anyJsonSchema;
|
|
68
77
|
constructor(options?: ZodToJsonSchemaOptions);
|
|
69
78
|
condition(schema: AnySchema | undefined): boolean;
|
|
70
|
-
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
79
|
+
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean, structureDepth?: number): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
71
80
|
}
|
|
72
81
|
|
|
73
82
|
declare const oz: {
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { custom, ZodFirstPartyTypeKind } from 'zod';
|
|
1
|
+
import { custom, ZodFirstPartyTypeKind } from 'zod/v3';
|
|
2
2
|
import wcmatch from 'wildcard-match';
|
|
3
|
-
import { isObject, guard } from '@orpc/shared';
|
|
3
|
+
import { isObject, guard, toArray } from '@orpc/shared';
|
|
4
|
+
import { JsonSchemaXNativeType } from '@orpc/json-schema';
|
|
4
5
|
import { JSONSchemaFormat } from '@orpc/openapi';
|
|
5
6
|
import escapeStringRegexp from 'escape-string-regexp';
|
|
6
7
|
|
|
@@ -128,7 +129,7 @@ class ZodSmartCoercionPlugin {
|
|
|
128
129
|
options.clientInterceptors ??= [];
|
|
129
130
|
options.clientInterceptors.unshift((options2) => {
|
|
130
131
|
const inputSchema = options2.procedure["~orpc"].inputSchema;
|
|
131
|
-
if (!inputSchema || inputSchema["~standard"].vendor !== "zod") {
|
|
132
|
+
if (!inputSchema || inputSchema["~standard"].vendor !== "zod" || "_zod" in inputSchema) {
|
|
132
133
|
return options2.next();
|
|
133
134
|
}
|
|
134
135
|
const coercedInput = zodCoerceInternal(inputSchema, options2.input);
|
|
@@ -390,25 +391,39 @@ function safeToDate(value) {
|
|
|
390
391
|
|
|
391
392
|
class ZodToJsonSchemaConverter {
|
|
392
393
|
maxLazyDepth;
|
|
394
|
+
maxStructureDepth;
|
|
393
395
|
unsupportedJsonSchema;
|
|
394
396
|
anyJsonSchema;
|
|
395
397
|
constructor(options = {}) {
|
|
396
398
|
this.maxLazyDepth = options.maxLazyDepth ?? 3;
|
|
399
|
+
this.maxStructureDepth = options.maxStructureDepth ?? 10;
|
|
397
400
|
this.unsupportedJsonSchema = options.unsupportedJsonSchema ?? { not: {} };
|
|
398
401
|
this.anyJsonSchema = options.anyJsonSchema ?? {};
|
|
399
402
|
}
|
|
400
403
|
condition(schema) {
|
|
401
|
-
return schema !== void 0 && schema["~standard"].vendor === "zod";
|
|
404
|
+
return schema !== void 0 && schema["~standard"].vendor === "zod" && !("_zod" in schema);
|
|
402
405
|
}
|
|
403
|
-
convert(schema, options, lazyDepth = 0, isHandledCustomJSONSchema = false, isHandledZodDescription = false) {
|
|
406
|
+
convert(schema, options, lazyDepth = 0, isHandledCustomJSONSchema = false, isHandledZodDescription = false, structureDepth = 0) {
|
|
404
407
|
const def = schema._def;
|
|
408
|
+
if (structureDepth > this.maxStructureDepth) {
|
|
409
|
+
return [false, this.anyJsonSchema];
|
|
410
|
+
}
|
|
411
|
+
if (!options.minStructureDepthForRef || options.minStructureDepthForRef <= structureDepth) {
|
|
412
|
+
const components = toArray(options.components);
|
|
413
|
+
for (const component of components) {
|
|
414
|
+
if (component.schema === schema && component.allowedStrategies.includes(options.strategy)) {
|
|
415
|
+
return [component.required, { $ref: component.ref }];
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
405
419
|
if (!isHandledZodDescription && "description" in def && typeof def.description === "string") {
|
|
406
420
|
const [required, json] = this.convert(
|
|
407
421
|
schema,
|
|
408
422
|
options,
|
|
409
423
|
lazyDepth,
|
|
410
424
|
isHandledCustomJSONSchema,
|
|
411
|
-
true
|
|
425
|
+
true,
|
|
426
|
+
structureDepth
|
|
412
427
|
);
|
|
413
428
|
return [required, { ...json, description: def.description }];
|
|
414
429
|
}
|
|
@@ -420,7 +435,8 @@ class ZodToJsonSchemaConverter {
|
|
|
420
435
|
options,
|
|
421
436
|
lazyDepth,
|
|
422
437
|
true,
|
|
423
|
-
isHandledZodDescription
|
|
438
|
+
isHandledZodDescription,
|
|
439
|
+
structureDepth
|
|
424
440
|
);
|
|
425
441
|
return [required, { ...json, ...customJSONSchema }];
|
|
426
442
|
}
|
|
@@ -548,7 +564,11 @@ class ZodToJsonSchemaConverter {
|
|
|
548
564
|
return [true, json];
|
|
549
565
|
}
|
|
550
566
|
case ZodFirstPartyTypeKind.ZodBigInt: {
|
|
551
|
-
const json = {
|
|
567
|
+
const json = {
|
|
568
|
+
"type": "string",
|
|
569
|
+
"pattern": "^-?[0-9]+$",
|
|
570
|
+
"x-native-type": JsonSchemaXNativeType.BigInt
|
|
571
|
+
};
|
|
552
572
|
return [true, json];
|
|
553
573
|
}
|
|
554
574
|
case ZodFirstPartyTypeKind.ZodNaN: {
|
|
@@ -558,7 +578,11 @@ class ZodToJsonSchemaConverter {
|
|
|
558
578
|
return [true, { type: "boolean" }];
|
|
559
579
|
}
|
|
560
580
|
case ZodFirstPartyTypeKind.ZodDate: {
|
|
561
|
-
const schema2 = {
|
|
581
|
+
const schema2 = {
|
|
582
|
+
"type": "string",
|
|
583
|
+
"format": JSONSchemaFormat.DateTime,
|
|
584
|
+
"x-native-type": JsonSchemaXNativeType.Date
|
|
585
|
+
};
|
|
562
586
|
return [true, schema2];
|
|
563
587
|
}
|
|
564
588
|
case ZodFirstPartyTypeKind.ZodNull: {
|
|
@@ -581,17 +605,26 @@ class ZodToJsonSchemaConverter {
|
|
|
581
605
|
}
|
|
582
606
|
case ZodFirstPartyTypeKind.ZodEnum: {
|
|
583
607
|
const schema_ = schema;
|
|
584
|
-
|
|
608
|
+
const values = schema_._def.values;
|
|
609
|
+
const json = { enum: values, type: "string" };
|
|
610
|
+
return [true, json];
|
|
585
611
|
}
|
|
586
612
|
case ZodFirstPartyTypeKind.ZodNativeEnum: {
|
|
587
613
|
const schema_ = schema;
|
|
588
|
-
|
|
614
|
+
const values = getEnumValues(schema_._def.values);
|
|
615
|
+
const json = { enum: values };
|
|
616
|
+
if (values.every((v) => typeof v === "string")) {
|
|
617
|
+
json.type = "string";
|
|
618
|
+
} else if (values.every((v) => Number.isFinite(v))) {
|
|
619
|
+
json.type = "number";
|
|
620
|
+
}
|
|
621
|
+
return [true, json];
|
|
589
622
|
}
|
|
590
623
|
case ZodFirstPartyTypeKind.ZodArray: {
|
|
591
624
|
const schema_ = schema;
|
|
592
625
|
const def2 = schema_._def;
|
|
593
626
|
const json = { type: "array" };
|
|
594
|
-
const [itemRequired, itemJson] = this.convert(def2.type, options, lazyDepth, false, false);
|
|
627
|
+
const [itemRequired, itemJson] = this.convert(def2.type, options, lazyDepth, false, false, structureDepth + 1);
|
|
595
628
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
|
596
629
|
if (def2.exactLength) {
|
|
597
630
|
json.maxItems = def2.exactLength.value;
|
|
@@ -610,7 +643,7 @@ class ZodToJsonSchemaConverter {
|
|
|
610
643
|
const prefixItems = [];
|
|
611
644
|
const json = { type: "array" };
|
|
612
645
|
for (const item of schema_._def.items) {
|
|
613
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
|
646
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth + 1);
|
|
614
647
|
prefixItems.push(
|
|
615
648
|
this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy)
|
|
616
649
|
);
|
|
@@ -619,7 +652,7 @@ class ZodToJsonSchemaConverter {
|
|
|
619
652
|
json.prefixItems = prefixItems;
|
|
620
653
|
}
|
|
621
654
|
if (schema_._def.rest) {
|
|
622
|
-
const [itemRequired, itemJson] = this.convert(schema_._def.rest, options, lazyDepth, false, false);
|
|
655
|
+
const [itemRequired, itemJson] = this.convert(schema_._def.rest, options, lazyDepth, false, false, structureDepth + 1);
|
|
623
656
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
|
624
657
|
}
|
|
625
658
|
return [true, json];
|
|
@@ -630,7 +663,7 @@ class ZodToJsonSchemaConverter {
|
|
|
630
663
|
const properties = {};
|
|
631
664
|
const required = [];
|
|
632
665
|
for (const [key, value] of Object.entries(schema_.shape)) {
|
|
633
|
-
const [itemRequired, itemJson] = this.convert(value, options, lazyDepth, false, false);
|
|
666
|
+
const [itemRequired, itemJson] = this.convert(value, options, lazyDepth, false, false, structureDepth + 1);
|
|
634
667
|
properties[key] = itemJson;
|
|
635
668
|
if (itemRequired) {
|
|
636
669
|
required.push(key);
|
|
@@ -648,7 +681,7 @@ class ZodToJsonSchemaConverter {
|
|
|
648
681
|
json.additionalProperties = false;
|
|
649
682
|
}
|
|
650
683
|
} else {
|
|
651
|
-
const [_, addJson] = this.convert(schema_._def.catchall, options, lazyDepth, false, false);
|
|
684
|
+
const [_, addJson] = this.convert(schema_._def.catchall, options, lazyDepth, false, false, structureDepth + 1);
|
|
652
685
|
json.additionalProperties = addJson;
|
|
653
686
|
}
|
|
654
687
|
return [true, json];
|
|
@@ -656,28 +689,32 @@ class ZodToJsonSchemaConverter {
|
|
|
656
689
|
case ZodFirstPartyTypeKind.ZodRecord: {
|
|
657
690
|
const schema_ = schema;
|
|
658
691
|
const json = { type: "object" };
|
|
659
|
-
const [__, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
|
|
692
|
+
const [__, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false, structureDepth + 1);
|
|
660
693
|
if (Object.entries(keyJson).some(([k, v]) => k !== "type" || v !== "string")) {
|
|
661
694
|
json.propertyNames = keyJson;
|
|
662
695
|
}
|
|
663
|
-
const [_, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
|
|
696
|
+
const [_, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
|
664
697
|
json.additionalProperties = itemJson;
|
|
665
698
|
return [true, json];
|
|
666
699
|
}
|
|
667
700
|
case ZodFirstPartyTypeKind.ZodSet: {
|
|
668
701
|
const schema_ = schema;
|
|
669
|
-
const json = {
|
|
670
|
-
|
|
702
|
+
const json = {
|
|
703
|
+
"type": "array",
|
|
704
|
+
"uniqueItems": true,
|
|
705
|
+
"x-native-type": JsonSchemaXNativeType.Set
|
|
706
|
+
};
|
|
707
|
+
const [itemRequired, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
|
671
708
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
|
672
709
|
return [true, json];
|
|
673
710
|
}
|
|
674
711
|
case ZodFirstPartyTypeKind.ZodMap: {
|
|
675
712
|
const schema_ = schema;
|
|
676
|
-
const [keyRequired, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
|
|
677
|
-
const [valueRequired, valueJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
|
|
678
|
-
|
|
679
|
-
type: "array",
|
|
680
|
-
items: {
|
|
713
|
+
const [keyRequired, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false, structureDepth + 1);
|
|
714
|
+
const [valueRequired, valueJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
|
715
|
+
const json = {
|
|
716
|
+
"type": "array",
|
|
717
|
+
"items": {
|
|
681
718
|
type: "array",
|
|
682
719
|
prefixItems: [
|
|
683
720
|
this.#toArrayItemJsonSchema(keyRequired, keyJson, options.strategy),
|
|
@@ -685,8 +722,10 @@ class ZodToJsonSchemaConverter {
|
|
|
685
722
|
],
|
|
686
723
|
maxItems: 2,
|
|
687
724
|
minItems: 2
|
|
688
|
-
}
|
|
689
|
-
|
|
725
|
+
},
|
|
726
|
+
"x-native-type": JsonSchemaXNativeType.Map
|
|
727
|
+
};
|
|
728
|
+
return [true, json];
|
|
690
729
|
}
|
|
691
730
|
case ZodFirstPartyTypeKind.ZodUnion:
|
|
692
731
|
case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
|
|
@@ -694,7 +733,7 @@ class ZodToJsonSchemaConverter {
|
|
|
694
733
|
const anyOf = [];
|
|
695
734
|
let required = true;
|
|
696
735
|
for (const item of schema_._def.options) {
|
|
697
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
|
736
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth + 1);
|
|
698
737
|
if (!itemRequired) {
|
|
699
738
|
required = false;
|
|
700
739
|
if (itemJson !== this.unsupportedJsonSchema) {
|
|
@@ -704,9 +743,6 @@ class ZodToJsonSchemaConverter {
|
|
|
704
743
|
anyOf.push(itemJson);
|
|
705
744
|
}
|
|
706
745
|
}
|
|
707
|
-
if (anyOf.length === 1) {
|
|
708
|
-
return [required, anyOf[0]];
|
|
709
|
-
}
|
|
710
746
|
return [required, { anyOf }];
|
|
711
747
|
}
|
|
712
748
|
case ZodFirstPartyTypeKind.ZodIntersection: {
|
|
@@ -714,7 +750,7 @@ class ZodToJsonSchemaConverter {
|
|
|
714
750
|
const allOf = [];
|
|
715
751
|
let required = false;
|
|
716
752
|
for (const item of [schema_._def.left, schema_._def.right]) {
|
|
717
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
|
753
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth + 1);
|
|
718
754
|
allOf.push(itemJson);
|
|
719
755
|
if (itemRequired) {
|
|
720
756
|
required = true;
|
|
@@ -723,25 +759,26 @@ class ZodToJsonSchemaConverter {
|
|
|
723
759
|
return [required, { allOf }];
|
|
724
760
|
}
|
|
725
761
|
case ZodFirstPartyTypeKind.ZodLazy: {
|
|
726
|
-
|
|
762
|
+
const currentLazyDepth = lazyDepth + 1;
|
|
763
|
+
if (currentLazyDepth > this.maxLazyDepth) {
|
|
727
764
|
return [false, this.anyJsonSchema];
|
|
728
765
|
}
|
|
729
766
|
const schema_ = schema;
|
|
730
|
-
return this.convert(schema_._def.getter(), options,
|
|
767
|
+
return this.convert(schema_._def.getter(), options, currentLazyDepth, false, false, structureDepth);
|
|
731
768
|
}
|
|
732
769
|
case ZodFirstPartyTypeKind.ZodOptional: {
|
|
733
770
|
const schema_ = schema;
|
|
734
|
-
const [_, inner] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
|
771
|
+
const [_, inner] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
|
735
772
|
return [false, inner];
|
|
736
773
|
}
|
|
737
774
|
case ZodFirstPartyTypeKind.ZodReadonly: {
|
|
738
775
|
const schema_ = schema;
|
|
739
|
-
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
|
776
|
+
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
|
740
777
|
return [required, { ...json, readOnly: true }];
|
|
741
778
|
}
|
|
742
779
|
case ZodFirstPartyTypeKind.ZodDefault: {
|
|
743
780
|
const schema_ = schema;
|
|
744
|
-
const [_, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
|
781
|
+
const [_, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
|
745
782
|
return [false, { default: schema_._def.defaultValue(), ...json }];
|
|
746
783
|
}
|
|
747
784
|
case ZodFirstPartyTypeKind.ZodEffects: {
|
|
@@ -749,15 +786,15 @@ class ZodToJsonSchemaConverter {
|
|
|
749
786
|
if (schema_._def.effect.type === "transform" && options.strategy === "output") {
|
|
750
787
|
return [false, this.anyJsonSchema];
|
|
751
788
|
}
|
|
752
|
-
return this.convert(schema_._def.schema, options, lazyDepth, false, false);
|
|
789
|
+
return this.convert(schema_._def.schema, options, lazyDepth, false, false, structureDepth);
|
|
753
790
|
}
|
|
754
791
|
case ZodFirstPartyTypeKind.ZodCatch: {
|
|
755
792
|
const schema_ = schema;
|
|
756
|
-
return this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
|
793
|
+
return this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
|
757
794
|
}
|
|
758
795
|
case ZodFirstPartyTypeKind.ZodBranded: {
|
|
759
796
|
const schema_ = schema;
|
|
760
|
-
return this.convert(schema_._def.type, options, lazyDepth, false, false);
|
|
797
|
+
return this.convert(schema_._def.type, options, lazyDepth, false, false, structureDepth);
|
|
761
798
|
}
|
|
762
799
|
case ZodFirstPartyTypeKind.ZodPipeline: {
|
|
763
800
|
const schema_ = schema;
|
|
@@ -766,13 +803,14 @@ class ZodToJsonSchemaConverter {
|
|
|
766
803
|
options,
|
|
767
804
|
lazyDepth,
|
|
768
805
|
false,
|
|
769
|
-
false
|
|
806
|
+
false,
|
|
807
|
+
structureDepth
|
|
770
808
|
);
|
|
771
809
|
}
|
|
772
810
|
case ZodFirstPartyTypeKind.ZodNullable: {
|
|
773
811
|
const schema_ = schema;
|
|
774
|
-
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
|
775
|
-
return [required, { anyOf: [{ type: "null" }
|
|
812
|
+
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
|
813
|
+
return [required, { anyOf: [json, { type: "null" }] }];
|
|
776
814
|
}
|
|
777
815
|
}
|
|
778
816
|
return [true, this.unsupportedJsonSchema];
|
|
@@ -791,12 +829,17 @@ class ZodToJsonSchemaConverter {
|
|
|
791
829
|
}
|
|
792
830
|
case "regexp": {
|
|
793
831
|
return {
|
|
794
|
-
type: "string",
|
|
795
|
-
pattern: "^\\/(.*)\\/([a-z]*)$"
|
|
832
|
+
"type": "string",
|
|
833
|
+
"pattern": "^\\/(.*)\\/([a-z]*)$",
|
|
834
|
+
"x-native-type": JsonSchemaXNativeType.RegExp
|
|
796
835
|
};
|
|
797
836
|
}
|
|
798
837
|
case "url": {
|
|
799
|
-
return {
|
|
838
|
+
return {
|
|
839
|
+
"type": "string",
|
|
840
|
+
"format": JSONSchemaFormat.URI,
|
|
841
|
+
"x-native-type": JsonSchemaXNativeType.Url
|
|
842
|
+
};
|
|
800
843
|
}
|
|
801
844
|
}
|
|
802
845
|
}
|
|
@@ -810,6 +853,11 @@ class ZodToJsonSchemaConverter {
|
|
|
810
853
|
return strategy === "input" ? { anyOf: [schema, this.unsupportedJsonSchema] } : { anyOf: [schema, { type: "null" }] };
|
|
811
854
|
}
|
|
812
855
|
}
|
|
856
|
+
function getEnumValues(entries) {
|
|
857
|
+
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
858
|
+
const values = Object.entries(entries).filter(([k, _]) => !numericValues.includes(+k)).map(([_, v]) => v);
|
|
859
|
+
return values;
|
|
860
|
+
}
|
|
813
861
|
|
|
814
862
|
const oz = {
|
|
815
863
|
file,
|
package/dist/zod4/index.d.mts
CHANGED
|
@@ -6,20 +6,31 @@ import { Interceptor } from '@orpc/shared';
|
|
|
6
6
|
import * as zod_v4_core from 'zod/v4/core';
|
|
7
7
|
import { $ZodType, $input, $output } from 'zod/v4/core';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use [Smart Coercion Plugin](https://orpc.dev/docs/openapi/plugins/smart-coercion) instead.
|
|
11
|
+
*/
|
|
9
12
|
declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> implements StandardHandlerPlugin<TContext> {
|
|
10
13
|
#private;
|
|
11
14
|
init(options: StandardHandlerOptions<TContext>): void;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
interface
|
|
17
|
+
interface ZodToJsonSchemaConverterOptions {
|
|
15
18
|
/**
|
|
16
|
-
* Max depth of lazy type
|
|
19
|
+
* Max depth of lazy type.
|
|
17
20
|
*
|
|
18
|
-
* Used anyJsonSchema (`{}`) when
|
|
21
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
19
22
|
*
|
|
20
23
|
* @default 2
|
|
21
24
|
*/
|
|
22
25
|
maxLazyDepth?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Max depth of nested types.
|
|
28
|
+
*
|
|
29
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
30
|
+
*
|
|
31
|
+
* @default 10
|
|
32
|
+
*/
|
|
33
|
+
maxStructureDepth?: number;
|
|
23
34
|
/**
|
|
24
35
|
* The schema to be used to represent the any | unknown type.
|
|
25
36
|
*
|
|
@@ -48,14 +59,15 @@ interface experimental_ZodToJsonSchemaOptions {
|
|
|
48
59
|
jsonSchema: Exclude<JSONSchema, boolean>
|
|
49
60
|
]>[];
|
|
50
61
|
}
|
|
51
|
-
declare class
|
|
62
|
+
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
|
52
63
|
#private;
|
|
53
64
|
private readonly maxLazyDepth;
|
|
65
|
+
private readonly maxStructureDepth;
|
|
54
66
|
private readonly anyJsonSchema;
|
|
55
67
|
private readonly unsupportedJsonSchema;
|
|
56
68
|
private readonly undefinedJsonSchema;
|
|
57
69
|
private readonly interceptors;
|
|
58
|
-
constructor(options?:
|
|
70
|
+
constructor(options?: ZodToJsonSchemaConverterOptions);
|
|
59
71
|
condition(schema: AnySchema | undefined): boolean;
|
|
60
72
|
convert(schema: AnySchema | undefined, options: SchemaConvertOptions): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
61
73
|
}
|
|
@@ -77,7 +89,7 @@ declare class experimental_ZodToJsonSchemaConverter implements ConditionalSchema
|
|
|
77
89
|
* })
|
|
78
90
|
* ```
|
|
79
91
|
*/
|
|
80
|
-
declare const
|
|
92
|
+
declare const JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
81
93
|
$anchor?: string;
|
|
82
94
|
$comment?: string;
|
|
83
95
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -156,7 +168,7 @@ declare const experimental_JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
|
156
168
|
* })
|
|
157
169
|
* ```
|
|
158
170
|
*/
|
|
159
|
-
declare const
|
|
171
|
+
declare const JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
160
172
|
$anchor?: string;
|
|
161
173
|
$comment?: string;
|
|
162
174
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -235,7 +247,7 @@ declare const experimental_JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<
|
|
|
235
247
|
* })
|
|
236
248
|
* ```
|
|
237
249
|
*/
|
|
238
|
-
declare const
|
|
250
|
+
declare const JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
239
251
|
$anchor?: string;
|
|
240
252
|
$comment?: string;
|
|
241
253
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -298,5 +310,5 @@ declare const experimental_JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry
|
|
|
298
310
|
writeOnly?: boolean;
|
|
299
311
|
}, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
300
312
|
|
|
301
|
-
export {
|
|
302
|
-
export type {
|
|
313
|
+
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter, experimental_ZodSmartCoercionPlugin };
|
|
314
|
+
export type { ZodToJsonSchemaConverterOptions };
|
package/dist/zod4/index.d.ts
CHANGED
|
@@ -6,20 +6,31 @@ import { Interceptor } from '@orpc/shared';
|
|
|
6
6
|
import * as zod_v4_core from 'zod/v4/core';
|
|
7
7
|
import { $ZodType, $input, $output } from 'zod/v4/core';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use [Smart Coercion Plugin](https://orpc.dev/docs/openapi/plugins/smart-coercion) instead.
|
|
11
|
+
*/
|
|
9
12
|
declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> implements StandardHandlerPlugin<TContext> {
|
|
10
13
|
#private;
|
|
11
14
|
init(options: StandardHandlerOptions<TContext>): void;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
interface
|
|
17
|
+
interface ZodToJsonSchemaConverterOptions {
|
|
15
18
|
/**
|
|
16
|
-
* Max depth of lazy type
|
|
19
|
+
* Max depth of lazy type.
|
|
17
20
|
*
|
|
18
|
-
* Used anyJsonSchema (`{}`) when
|
|
21
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
19
22
|
*
|
|
20
23
|
* @default 2
|
|
21
24
|
*/
|
|
22
25
|
maxLazyDepth?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Max depth of nested types.
|
|
28
|
+
*
|
|
29
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
|
30
|
+
*
|
|
31
|
+
* @default 10
|
|
32
|
+
*/
|
|
33
|
+
maxStructureDepth?: number;
|
|
23
34
|
/**
|
|
24
35
|
* The schema to be used to represent the any | unknown type.
|
|
25
36
|
*
|
|
@@ -48,14 +59,15 @@ interface experimental_ZodToJsonSchemaOptions {
|
|
|
48
59
|
jsonSchema: Exclude<JSONSchema, boolean>
|
|
49
60
|
]>[];
|
|
50
61
|
}
|
|
51
|
-
declare class
|
|
62
|
+
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
|
52
63
|
#private;
|
|
53
64
|
private readonly maxLazyDepth;
|
|
65
|
+
private readonly maxStructureDepth;
|
|
54
66
|
private readonly anyJsonSchema;
|
|
55
67
|
private readonly unsupportedJsonSchema;
|
|
56
68
|
private readonly undefinedJsonSchema;
|
|
57
69
|
private readonly interceptors;
|
|
58
|
-
constructor(options?:
|
|
70
|
+
constructor(options?: ZodToJsonSchemaConverterOptions);
|
|
59
71
|
condition(schema: AnySchema | undefined): boolean;
|
|
60
72
|
convert(schema: AnySchema | undefined, options: SchemaConvertOptions): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
|
61
73
|
}
|
|
@@ -77,7 +89,7 @@ declare class experimental_ZodToJsonSchemaConverter implements ConditionalSchema
|
|
|
77
89
|
* })
|
|
78
90
|
* ```
|
|
79
91
|
*/
|
|
80
|
-
declare const
|
|
92
|
+
declare const JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
81
93
|
$anchor?: string;
|
|
82
94
|
$comment?: string;
|
|
83
95
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -156,7 +168,7 @@ declare const experimental_JSON_SCHEMA_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
|
156
168
|
* })
|
|
157
169
|
* ```
|
|
158
170
|
*/
|
|
159
|
-
declare const
|
|
171
|
+
declare const JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
160
172
|
$anchor?: string;
|
|
161
173
|
$comment?: string;
|
|
162
174
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -235,7 +247,7 @@ declare const experimental_JSON_SCHEMA_INPUT_REGISTRY: zod_v4_core.$ZodRegistry<
|
|
|
235
247
|
* })
|
|
236
248
|
* ```
|
|
237
249
|
*/
|
|
238
|
-
declare const
|
|
250
|
+
declare const JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry<{
|
|
239
251
|
$anchor?: string;
|
|
240
252
|
$comment?: string;
|
|
241
253
|
$defs?: Record<string, JSONSchema>;
|
|
@@ -298,5 +310,5 @@ declare const experimental_JSON_SCHEMA_OUTPUT_REGISTRY: zod_v4_core.$ZodRegistry
|
|
|
298
310
|
writeOnly?: boolean;
|
|
299
311
|
}, zod_v4_core.$ZodType<unknown, unknown, zod_v4_core.$ZodTypeInternals<unknown, unknown>>>;
|
|
300
312
|
|
|
301
|
-
export {
|
|
302
|
-
export type {
|
|
313
|
+
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter, experimental_ZodSmartCoercionPlugin };
|
|
314
|
+
export type { ZodToJsonSchemaConverterOptions };
|
package/dist/zod4/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { isObject, guard, intercept } from '@orpc/shared';
|
|
1
|
+
import { isObject, guard, intercept, toArray } from '@orpc/shared';
|
|
2
|
+
import { JsonSchemaXNativeType } from '@orpc/json-schema';
|
|
2
3
|
import { JSONSchemaFormat, JSONSchemaContentEncoding } from '@orpc/openapi';
|
|
3
4
|
import { registry, globalRegistry } from 'zod/v4/core';
|
|
4
5
|
|
|
@@ -7,7 +8,7 @@ class experimental_ZodSmartCoercionPlugin {
|
|
|
7
8
|
options.clientInterceptors ??= [];
|
|
8
9
|
options.clientInterceptors.unshift((options2) => {
|
|
9
10
|
const inputSchema = options2.procedure["~orpc"].inputSchema;
|
|
10
|
-
if (!inputSchema || inputSchema["~standard"].vendor !== "zod") {
|
|
11
|
+
if (!inputSchema || inputSchema["~standard"].vendor !== "zod" || !("_zod" in inputSchema)) {
|
|
11
12
|
return options2.next();
|
|
12
13
|
}
|
|
13
14
|
const coercedInput = this.#coerce(inputSchema, options2.input);
|
|
@@ -268,38 +269,51 @@ class experimental_ZodSmartCoercionPlugin {
|
|
|
268
269
|
}
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
const
|
|
272
|
+
const JSON_SCHEMA_REGISTRY = registry();
|
|
273
|
+
const JSON_SCHEMA_INPUT_REGISTRY = registry();
|
|
274
|
+
const JSON_SCHEMA_OUTPUT_REGISTRY = registry();
|
|
274
275
|
|
|
275
|
-
class
|
|
276
|
+
class ZodToJsonSchemaConverter {
|
|
276
277
|
maxLazyDepth;
|
|
278
|
+
maxStructureDepth;
|
|
277
279
|
anyJsonSchema;
|
|
278
280
|
unsupportedJsonSchema;
|
|
279
281
|
undefinedJsonSchema;
|
|
280
282
|
interceptors;
|
|
281
283
|
constructor(options = {}) {
|
|
282
284
|
this.maxLazyDepth = options.maxLazyDepth ?? 2;
|
|
285
|
+
this.maxStructureDepth = options.maxStructureDepth ?? 10;
|
|
283
286
|
this.anyJsonSchema = options.anyJsonSchema ?? {};
|
|
284
287
|
this.unsupportedJsonSchema = options.unsupportedJsonSchema ?? { not: {} };
|
|
285
288
|
this.undefinedJsonSchema = options.undefinedJsonSchema ?? { not: {} };
|
|
286
289
|
this.interceptors = options.interceptors ?? [];
|
|
287
290
|
}
|
|
288
291
|
condition(schema) {
|
|
289
|
-
return schema !== void 0 && schema["~standard"].vendor === "zod";
|
|
292
|
+
return schema !== void 0 && schema["~standard"].vendor === "zod" && "_zod" in schema;
|
|
290
293
|
}
|
|
291
294
|
convert(schema, options) {
|
|
292
|
-
return this.#convert(schema, options, 0);
|
|
295
|
+
return this.#convert(schema, options, 0, 0);
|
|
293
296
|
}
|
|
294
|
-
#convert(schema, options, lazyDepth, isHandledCustomJSONSchema = false) {
|
|
297
|
+
#convert(schema, options, lazyDepth, structureDepth, isHandledCustomJSONSchema = false) {
|
|
295
298
|
return intercept(
|
|
296
299
|
this.interceptors,
|
|
297
300
|
{ schema, options, lazyDepth, isHandledCustomJSONSchema },
|
|
298
301
|
({ schema: schema2, options: options2, lazyDepth: lazyDepth2, isHandledCustomJSONSchema: isHandledCustomJSONSchema2 }) => {
|
|
302
|
+
if (structureDepth > this.maxStructureDepth) {
|
|
303
|
+
return [false, this.anyJsonSchema];
|
|
304
|
+
}
|
|
305
|
+
if (!options2.minStructureDepthForRef || options2.minStructureDepthForRef <= structureDepth) {
|
|
306
|
+
const components = toArray(options2.components);
|
|
307
|
+
for (const component of components) {
|
|
308
|
+
if (component.schema === schema2 && component.allowedStrategies.includes(options2.strategy)) {
|
|
309
|
+
return [component.required, { $ref: component.ref }];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
299
313
|
if (!isHandledCustomJSONSchema2) {
|
|
300
314
|
const customJSONSchema = this.#getCustomJsonSchema(schema2, options2);
|
|
301
315
|
if (customJSONSchema) {
|
|
302
|
-
const [required, json] = this.#convert(schema2, options2, lazyDepth2, true);
|
|
316
|
+
const [required, json] = this.#convert(schema2, options2, lazyDepth2, structureDepth, true);
|
|
303
317
|
return [required, { ...json, ...customJSONSchema }];
|
|
304
318
|
}
|
|
305
319
|
}
|
|
@@ -363,10 +377,18 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
363
377
|
return [true, { type: "boolean" }];
|
|
364
378
|
}
|
|
365
379
|
case "bigint": {
|
|
366
|
-
return [true, {
|
|
380
|
+
return [true, {
|
|
381
|
+
"type": "string",
|
|
382
|
+
"pattern": "^-?[0-9]+$",
|
|
383
|
+
"x-native-type": JsonSchemaXNativeType.BigInt
|
|
384
|
+
}];
|
|
367
385
|
}
|
|
368
386
|
case "date": {
|
|
369
|
-
return [true, {
|
|
387
|
+
return [true, {
|
|
388
|
+
"type": "string",
|
|
389
|
+
"format": JSONSchemaFormat.DateTime,
|
|
390
|
+
"x-native-type": JsonSchemaXNativeType.Date
|
|
391
|
+
}];
|
|
370
392
|
}
|
|
371
393
|
case "null": {
|
|
372
394
|
return [true, { type: "null" }];
|
|
@@ -394,14 +416,14 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
394
416
|
if (typeof maximum === "number") {
|
|
395
417
|
json.maxItems = maximum;
|
|
396
418
|
}
|
|
397
|
-
json.items = this.#handleArrayItemJsonSchema(this.#convert(array._zod.def.element, options2, lazyDepth2), options2);
|
|
419
|
+
json.items = this.#handleArrayItemJsonSchema(this.#convert(array._zod.def.element, options2, lazyDepth2, structureDepth + 1), options2);
|
|
398
420
|
return [true, json];
|
|
399
421
|
}
|
|
400
422
|
case "object": {
|
|
401
423
|
const object = schema2;
|
|
402
424
|
const json = { type: "object" };
|
|
403
425
|
for (const [key, value] of Object.entries(object._zod.def.shape)) {
|
|
404
|
-
const [itemRequired, itemJson] = this.#convert(value, options2, lazyDepth2);
|
|
426
|
+
const [itemRequired, itemJson] = this.#convert(value, options2, lazyDepth2, structureDepth + 1);
|
|
405
427
|
json.properties ??= {};
|
|
406
428
|
json.properties[key] = itemJson;
|
|
407
429
|
if (itemRequired) {
|
|
@@ -413,7 +435,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
413
435
|
if (object._zod.def.catchall._zod.def.type === "never") {
|
|
414
436
|
json.additionalProperties = false;
|
|
415
437
|
} else {
|
|
416
|
-
const [_, addJson] = this.#convert(object._zod.def.catchall, options2, lazyDepth2);
|
|
438
|
+
const [_, addJson] = this.#convert(object._zod.def.catchall, options2, lazyDepth2, structureDepth + 1);
|
|
417
439
|
json.additionalProperties = addJson;
|
|
418
440
|
}
|
|
419
441
|
}
|
|
@@ -424,7 +446,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
424
446
|
const anyOf = [];
|
|
425
447
|
let required = true;
|
|
426
448
|
for (const item of union._zod.def.options) {
|
|
427
|
-
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2);
|
|
449
|
+
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2, structureDepth + 1);
|
|
428
450
|
if (!itemRequired) {
|
|
429
451
|
required = false;
|
|
430
452
|
}
|
|
@@ -438,14 +460,14 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
438
460
|
}
|
|
439
461
|
}
|
|
440
462
|
}
|
|
441
|
-
return [required,
|
|
463
|
+
return [required, { anyOf }];
|
|
442
464
|
}
|
|
443
465
|
case "intersection": {
|
|
444
466
|
const intersection = schema2;
|
|
445
467
|
const json = { allOf: [] };
|
|
446
468
|
let required = false;
|
|
447
469
|
for (const item of [intersection._zod.def.left, intersection._zod.def.right]) {
|
|
448
|
-
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2);
|
|
470
|
+
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2, structureDepth + 1);
|
|
449
471
|
json.allOf.push(itemJson);
|
|
450
472
|
if (itemRequired) {
|
|
451
473
|
required = true;
|
|
@@ -457,10 +479,10 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
457
479
|
const tuple = schema2;
|
|
458
480
|
const json = { type: "array", prefixItems: [] };
|
|
459
481
|
for (const item of tuple._zod.def.items) {
|
|
460
|
-
json.prefixItems.push(this.#handleArrayItemJsonSchema(this.#convert(item, options2, lazyDepth2), options2));
|
|
482
|
+
json.prefixItems.push(this.#handleArrayItemJsonSchema(this.#convert(item, options2, lazyDepth2, structureDepth + 1), options2));
|
|
461
483
|
}
|
|
462
484
|
if (tuple._zod.def.rest) {
|
|
463
|
-
json.items = this.#handleArrayItemJsonSchema(this.#convert(tuple._zod.def.rest, options2, lazyDepth2), options2);
|
|
485
|
+
json.items = this.#handleArrayItemJsonSchema(this.#convert(tuple._zod.def.rest, options2, lazyDepth2, structureDepth + 1), options2);
|
|
464
486
|
}
|
|
465
487
|
const { minimum, maximum } = tuple._zod.bag;
|
|
466
488
|
if (typeof minimum === "number") {
|
|
@@ -474,36 +496,45 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
474
496
|
case "record": {
|
|
475
497
|
const record = schema2;
|
|
476
498
|
const json = { type: "object" };
|
|
477
|
-
json.propertyNames = this.#convert(record._zod.def.keyType, options2, lazyDepth2)[1];
|
|
478
|
-
json.additionalProperties = this.#convert(record._zod.def.valueType, options2, lazyDepth2)[1];
|
|
499
|
+
json.propertyNames = this.#convert(record._zod.def.keyType, options2, lazyDepth2, structureDepth + 1)[1];
|
|
500
|
+
json.additionalProperties = this.#convert(record._zod.def.valueType, options2, lazyDepth2, structureDepth + 1)[1];
|
|
479
501
|
return [true, json];
|
|
480
502
|
}
|
|
481
503
|
case "map": {
|
|
482
504
|
const map = schema2;
|
|
483
505
|
return [true, {
|
|
484
|
-
type: "array",
|
|
485
|
-
items: {
|
|
506
|
+
"type": "array",
|
|
507
|
+
"items": {
|
|
486
508
|
type: "array",
|
|
487
509
|
prefixItems: [
|
|
488
|
-
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.keyType, options2, lazyDepth2), options2),
|
|
489
|
-
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.valueType, options2, lazyDepth2), options2)
|
|
510
|
+
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.keyType, options2, lazyDepth2, structureDepth + 1), options2),
|
|
511
|
+
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.valueType, options2, lazyDepth2, structureDepth + 1), options2)
|
|
490
512
|
],
|
|
491
513
|
maxItems: 2,
|
|
492
514
|
minItems: 2
|
|
493
|
-
}
|
|
515
|
+
},
|
|
516
|
+
"x-native-type": JsonSchemaXNativeType.Map
|
|
494
517
|
}];
|
|
495
518
|
}
|
|
496
519
|
case "set": {
|
|
497
520
|
const set = schema2;
|
|
498
521
|
return [true, {
|
|
499
|
-
type: "array",
|
|
500
|
-
uniqueItems: true,
|
|
501
|
-
items: this.#handleArrayItemJsonSchema(this.#convert(set._zod.def.valueType, options2, lazyDepth2), options2)
|
|
522
|
+
"type": "array",
|
|
523
|
+
"uniqueItems": true,
|
|
524
|
+
"items": this.#handleArrayItemJsonSchema(this.#convert(set._zod.def.valueType, options2, lazyDepth2, structureDepth + 1), options2),
|
|
525
|
+
"x-native-type": JsonSchemaXNativeType.Set
|
|
502
526
|
}];
|
|
503
527
|
}
|
|
504
528
|
case "enum": {
|
|
505
529
|
const enum_ = schema2;
|
|
506
|
-
|
|
530
|
+
const values = getEnumValues(enum_._zod.def.entries);
|
|
531
|
+
const json = { enum: values };
|
|
532
|
+
if (values.every((v) => typeof v === "string")) {
|
|
533
|
+
json.type = "string";
|
|
534
|
+
} else if (values.every((v) => Number.isFinite(v))) {
|
|
535
|
+
json.type = "number";
|
|
536
|
+
}
|
|
537
|
+
return [true, json];
|
|
507
538
|
}
|
|
508
539
|
case "literal": {
|
|
509
540
|
const literal = schema2;
|
|
@@ -538,12 +569,12 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
538
569
|
}
|
|
539
570
|
case "nullable": {
|
|
540
571
|
const nullable = schema2;
|
|
541
|
-
const [required, json] = this.#convert(nullable._zod.def.innerType, options2, lazyDepth2);
|
|
572
|
+
const [required, json] = this.#convert(nullable._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
542
573
|
return [required, { anyOf: [json, { type: "null" }] }];
|
|
543
574
|
}
|
|
544
575
|
case "nonoptional": {
|
|
545
576
|
const nonoptional = schema2;
|
|
546
|
-
const [, json] = this.#convert(nonoptional._zod.def.innerType, options2, lazyDepth2);
|
|
577
|
+
const [, json] = this.#convert(nonoptional._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
547
578
|
return [true, json];
|
|
548
579
|
}
|
|
549
580
|
case "success": {
|
|
@@ -552,7 +583,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
552
583
|
case "default":
|
|
553
584
|
case "prefault": {
|
|
554
585
|
const default_ = schema2;
|
|
555
|
-
const [, json] = this.#convert(default_._zod.def.innerType, options2, lazyDepth2);
|
|
586
|
+
const [, json] = this.#convert(default_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
556
587
|
return [false, {
|
|
557
588
|
...json,
|
|
558
589
|
default: default_._zod.def.defaultValue
|
|
@@ -560,18 +591,24 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
560
591
|
}
|
|
561
592
|
case "catch": {
|
|
562
593
|
const catch_ = schema2;
|
|
563
|
-
return this.#convert(catch_._zod.def.innerType, options2, lazyDepth2);
|
|
594
|
+
return this.#convert(catch_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
564
595
|
}
|
|
565
596
|
case "nan": {
|
|
566
597
|
return [true, options2.strategy === "input" ? this.unsupportedJsonSchema : { type: "null" }];
|
|
567
598
|
}
|
|
568
599
|
case "pipe": {
|
|
569
600
|
const pipe = schema2;
|
|
570
|
-
return this.#convert(
|
|
601
|
+
return this.#convert(
|
|
602
|
+
// prefer out schema when in schema is preprocess/transform
|
|
603
|
+
options2.strategy === "input" && pipe._zod.def.in._zod.def.type !== "transform" ? pipe._zod.def.in : pipe._zod.def.out,
|
|
604
|
+
options2,
|
|
605
|
+
lazyDepth2,
|
|
606
|
+
structureDepth
|
|
607
|
+
);
|
|
571
608
|
}
|
|
572
609
|
case "readonly": {
|
|
573
610
|
const readonly_ = schema2;
|
|
574
|
-
const [required, json] = this.#convert(readonly_._zod.def.innerType, options2, lazyDepth2);
|
|
611
|
+
const [required, json] = this.#convert(readonly_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
575
612
|
return [required, { ...json, readOnly: true }];
|
|
576
613
|
}
|
|
577
614
|
case "template_literal": {
|
|
@@ -583,15 +620,16 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
583
620
|
}
|
|
584
621
|
case "optional": {
|
|
585
622
|
const optional = schema2;
|
|
586
|
-
const [, json] = this.#convert(optional._zod.def.innerType, options2, lazyDepth2);
|
|
623
|
+
const [, json] = this.#convert(optional._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
|
587
624
|
return [false, json];
|
|
588
625
|
}
|
|
589
626
|
case "lazy": {
|
|
590
627
|
const lazy = schema2;
|
|
591
|
-
|
|
628
|
+
const currentLazyDepth = lazyDepth2 + 1;
|
|
629
|
+
if (currentLazyDepth > this.maxLazyDepth) {
|
|
592
630
|
return [false, this.anyJsonSchema];
|
|
593
631
|
}
|
|
594
|
-
return this.#convert(lazy._zod.def.getter(), options2,
|
|
632
|
+
return this.#convert(lazy._zod.def.getter(), options2, currentLazyDepth, structureDepth);
|
|
595
633
|
}
|
|
596
634
|
default: {
|
|
597
635
|
schema2._zod.def.type;
|
|
@@ -602,18 +640,19 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
602
640
|
);
|
|
603
641
|
}
|
|
604
642
|
#getCustomJsonSchema(schema, options) {
|
|
605
|
-
if (options.strategy === "input" &&
|
|
606
|
-
return
|
|
643
|
+
if (options.strategy === "input" && JSON_SCHEMA_INPUT_REGISTRY.has(schema)) {
|
|
644
|
+
return JSON_SCHEMA_INPUT_REGISTRY.get(schema);
|
|
607
645
|
}
|
|
608
|
-
if (options.strategy === "output" &&
|
|
609
|
-
return
|
|
646
|
+
if (options.strategy === "output" && JSON_SCHEMA_OUTPUT_REGISTRY.has(schema)) {
|
|
647
|
+
return JSON_SCHEMA_OUTPUT_REGISTRY.get(schema);
|
|
610
648
|
}
|
|
611
|
-
if (
|
|
612
|
-
return
|
|
649
|
+
if (JSON_SCHEMA_REGISTRY.has(schema)) {
|
|
650
|
+
return JSON_SCHEMA_REGISTRY.get(schema);
|
|
613
651
|
}
|
|
614
652
|
const global = globalRegistry.get(schema);
|
|
615
653
|
if (global) {
|
|
616
654
|
return {
|
|
655
|
+
title: global.title,
|
|
617
656
|
description: global.description,
|
|
618
657
|
examples: Array.isArray(global.examples) ? global.examples : void 0
|
|
619
658
|
};
|
|
@@ -650,5 +689,10 @@ class experimental_ZodToJsonSchemaConverter {
|
|
|
650
689
|
return Object.values(JSONSchemaContentEncoding).includes(contentEncoding) ? contentEncoding : void 0;
|
|
651
690
|
}
|
|
652
691
|
}
|
|
692
|
+
function getEnumValues(entries) {
|
|
693
|
+
const numericValues = Object.values(entries).filter((v) => typeof v === "number");
|
|
694
|
+
const values = Object.entries(entries).filter(([k, _]) => !numericValues.includes(+k)).map(([_, v]) => v);
|
|
695
|
+
return values;
|
|
696
|
+
}
|
|
653
697
|
|
|
654
|
-
export {
|
|
698
|
+
export { JSON_SCHEMA_INPUT_REGISTRY, JSON_SCHEMA_OUTPUT_REGISTRY, JSON_SCHEMA_REGISTRY, ZodToJsonSchemaConverter, experimental_ZodSmartCoercionPlugin };
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/zod",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-next.
|
|
4
|
+
"version": "0.0.0-next.7605f6c",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"homepage": "https://orpc.
|
|
6
|
+
"homepage": "https://orpc.dev",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/
|
|
9
|
+
"url": "git+https://github.com/middleapi/orpc.git",
|
|
10
10
|
"directory": "packages/zod"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
|
-
"unnoq",
|
|
14
13
|
"orpc"
|
|
15
14
|
],
|
|
15
|
+
"sideEffects": false,
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
18
|
"types": "./dist/index.d.mts",
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
"dist"
|
|
30
30
|
],
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"zod": ">=3.
|
|
33
|
-
"@orpc/contract": "0.0.0-next.
|
|
34
|
-
"@orpc/server": "0.0.0-next.
|
|
32
|
+
"zod": ">=3.25.0",
|
|
33
|
+
"@orpc/contract": "0.0.0-next.7605f6c",
|
|
34
|
+
"@orpc/server": "0.0.0-next.7605f6c"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"escape-string-regexp": "^5.0.0",
|
|
38
|
-
"wildcard-match": "^5.1.
|
|
39
|
-
"@orpc/
|
|
40
|
-
"@orpc/shared": "0.0.0-next.
|
|
38
|
+
"wildcard-match": "^5.1.4",
|
|
39
|
+
"@orpc/json-schema": "0.0.0-next.7605f6c",
|
|
40
|
+
"@orpc/shared": "0.0.0-next.7605f6c",
|
|
41
|
+
"@orpc/openapi": "0.0.0-next.7605f6c"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"zod": "^3.
|
|
44
|
-
"zod-to-json-schema": "^3.24.5"
|
|
44
|
+
"zod": "^4.3.6"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "unbuild",
|