@orpc/json-schema 2.0.0-beta.43 → 2.0.0-beta.45
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 +56 -57
- package/dist/index.d.mts +40 -6
- package/dist/index.d.ts +40 -6
- package/dist/index.mjs +146 -27
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<img alt="Discord" src="https://img.shields.io/discord/1308966753044398161?color=7389D8&label&logo=discord&logoColor=ffffff" />
|
|
18
18
|
</a>
|
|
19
19
|
<a href="https://deepwiki.com/middleapi/orpc">
|
|
20
|
-
<img src="https://
|
|
20
|
+
<img alt="Ask DeepWiki" src="https://img.shields.io/badge/Ask-DeepWiki-blue" />
|
|
21
21
|
</a>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -60,10 +60,11 @@ You can read the documentation [here](https://orpc.dev).
|
|
|
60
60
|
| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
61
61
|
| [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
|
|
62
62
|
| [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
|
|
63
|
+
| [@orpc/mcp](https://www.npmjs.com/package/@orpc/mcp) | Expose procedures as [MCP](https://modelcontextprotocol.io/) tools. | [MCP](https://orpc.dev/docs/integrations/mcp) |
|
|
63
64
|
| [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
|
|
64
65
|
| [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
|
|
65
66
|
| [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
|
|
66
|
-
| [@orpc/
|
|
67
|
+
| [@orpc/msw](https://www.npmjs.com/package/@orpc/msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
|
|
67
68
|
| [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
|
|
68
69
|
| [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
|
|
69
70
|
| [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
|
|
@@ -95,27 +96,11 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
95
96
|
</tr>
|
|
96
97
|
</table>
|
|
97
98
|
|
|
98
|
-
### Special Sponsors
|
|
99
|
-
|
|
100
|
-
<table>
|
|
101
|
-
<tr>
|
|
102
|
-
<td align="center"><a href="http://twitter.com/rauchg?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guillermo Rauch"><img src="https://avatars.githubusercontent.com/u/13041?u=1ee8d111657cdd02ff6d253df00978d17ee6d722&v=4" width="279" alt="Guillermo Rauch"/><br />Guillermo Rauch</a></td>
|
|
103
|
-
</tr>
|
|
104
|
-
</table>
|
|
105
|
-
|
|
106
|
-
### Premium Sponsors
|
|
107
|
-
|
|
108
|
-
<table>
|
|
109
|
-
<tr>
|
|
110
|
-
<td align="center"><a href="https://github.com/nexa-ca?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Nexa"><img src="https://avatars.githubusercontent.com/u/199146462?v=4" width="209" alt="Nexa"/><br />Nexa</a></td>
|
|
111
|
-
</tr>
|
|
112
|
-
</table>
|
|
113
|
-
|
|
114
99
|
### Organization Sponsors
|
|
115
100
|
|
|
116
101
|
<table>
|
|
117
102
|
<tr>
|
|
118
|
-
<td align="center"><a href="https://lnmarkets.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="LN Markets"><img src="https://avatars.githubusercontent.com/u/70597625?v=4" width="
|
|
103
|
+
<td align="center"><a href="https://lnmarkets.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="LN Markets"><img src="https://avatars.githubusercontent.com/u/70597625?v=4" width="209" alt="LN Markets"/><br />LN Markets</a></td>
|
|
119
104
|
</tr>
|
|
120
105
|
</table>
|
|
121
106
|
|
|
@@ -123,27 +108,29 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
123
108
|
|
|
124
109
|
<table>
|
|
125
110
|
<tr>
|
|
126
|
-
<td align="center"><a href="https://github.com/hrmcdonald?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Reece McDonald"><img src="https://avatars.githubusercontent.com/u/39349270?v=4" width="
|
|
127
|
-
<td align="center"><a href="https://soymilk.party/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="あわわわとーにゅ"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&v=4" width="
|
|
128
|
-
<td align="center"><a href="https://github.com/nicognaW?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&v=4" width="
|
|
129
|
-
<td align="center"><a href="https://supastarter.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="
|
|
130
|
-
<td align="center"><a href="https://github.com/herrfugbaum?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&v=4" width="
|
|
131
|
-
<td align="center"><a href="https://laststance.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
|
|
111
|
+
<td align="center"><a href="https://github.com/hrmcdonald?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Reece McDonald"><img src="https://avatars.githubusercontent.com/u/39349270?v=4" width="167" alt="Reece McDonald"/><br />Reece McDonald</a></td>
|
|
112
|
+
<td align="center"><a href="https://soymilk.party/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="あわわわとーにゅ"><img src="https://avatars.githubusercontent.com/u/17376330?u=de3353804be889f009f7e0a1582daf04d0ab292d&v=4" width="167" alt="あわわわとーにゅ"/><br />あわわわとーにゅ</a></td>
|
|
113
|
+
<td align="center"><a href="https://github.com/nicognaW?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="nk"><img src="https://avatars.githubusercontent.com/u/66731869?u=4699bda3a9092d3ec34fbd959450767bcc8b8b6d&v=4" width="167" alt="nk"/><br />nk</a></td>
|
|
114
|
+
<td align="center"><a href="https://supastarter.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="supastarter"><img src="https://avatars.githubusercontent.com/u/110960143?v=4" width="167" alt="supastarter"/><br />supastarter</a></td>
|
|
115
|
+
<td align="center"><a href="https://github.com/herrfugbaum?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="herrfugbaum"><img src="https://avatars.githubusercontent.com/u/12859776?u=644dc1666d0220bc0468eb0de3c56b919f635b16&v=4" width="167" alt="herrfugbaum"/><br />herrfugbaum</a></td>
|
|
132
116
|
</tr>
|
|
133
117
|
<tr>
|
|
134
|
-
<td align="center"><a href="https://
|
|
135
|
-
<td align="center"><a href="https://
|
|
136
|
-
<td align="center"><a href="https://
|
|
137
|
-
<td align="center"><a href="https://
|
|
138
|
-
<td align="center"><a href="https://
|
|
139
|
-
<td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" 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>
|
|
118
|
+
<td align="center"><a href="https://laststance.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryota Murakami"><img src="https://avatars.githubusercontent.com/u/5501268?u=599389e03340734325726ca3f8f423c021d47d7f&v=4" width="167" alt="Ryota Murakami"/><br />Ryota Murakami</a></td>
|
|
119
|
+
<td align="center"><a href="https://cra.mr/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Cramer"><img src="https://avatars.githubusercontent.com/u/23610?v=4" width="167" alt="David Cramer"/><br />David Cramer</a></td>
|
|
120
|
+
<td align="center"><a href="https://valerii15298.github.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Valerii Petryniak"><img src="https://avatars.githubusercontent.com/u/44531564?u=88ac74d9bacd20401518441907acad21063cd397&v=4" width="167" alt="Valerii Petryniak"/><br />Valerii Petryniak</a></td>
|
|
121
|
+
<td align="center"><a href="https://letstri.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Valerii Strilets"><img src="https://avatars.githubusercontent.com/u/13253748?u=c7b10399ccc8f8081e24db94ec32cd9858e86ac3&v=4" width="167" alt="Valerii Strilets"/><br />Valerii Strilets</a></td>
|
|
122
|
+
<td align="center"><a href="https://blacklight.sh/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kyle Mistele"><img src="https://avatars.githubusercontent.com/u/18430555?u=3afebeb81de666e35aaac3ed46f14159d7603ffb&v=4" width="167" alt="Kyle Mistele"/><br />Kyle Mistele</a></td>
|
|
140
123
|
</tr>
|
|
141
124
|
<tr>
|
|
142
|
-
<td align="center"><a href="https://github.com/
|
|
143
|
-
<td align="center"><a href="https://github.com/
|
|
144
|
-
<td align="center"><a href="https://github.com/
|
|
145
|
-
<td align="center"><a href="https://
|
|
146
|
-
<td align="center"><a href="https://
|
|
125
|
+
<td align="center"><a href="https://github.com/christ12938?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="christ12938"><img src="https://avatars.githubusercontent.com/u/25758598?v=4" width="167" alt="christ12938"/><br />christ12938</a></td>
|
|
126
|
+
<td align="center"><a href="https://github.com/Ryanjso?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ryan Soderberg"><img src="https://avatars.githubusercontent.com/u/39172778?u=5ed913c31d57e7221b75784abcad48c7ebddde27&v=4" width="167" alt="Ryan Soderberg"/><br />Ryan Soderberg</a></td>
|
|
127
|
+
<td align="center"><a href="https://github.com/itigoore01?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&v=4" width="167" alt="shota"/><br />shota</a></td>
|
|
128
|
+
<td align="center"><a href="https://github.com/ellis-driscoll?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ellis Driscoll"><img src="https://avatars.githubusercontent.com/u/70685966?u=c5f95bc33b5991d9744abe00052542e4a2ed3cb9&v=4" width="167" alt="Ellis Driscoll"/><br />Ellis Driscoll</a></td>
|
|
129
|
+
<td align="center"><a href="https://github.com/hoangbn?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&v=4" width="167" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
|
|
130
|
+
</tr>
|
|
131
|
+
<tr>
|
|
132
|
+
<td align="center"><a href="https://opencollective.com/guest-ac41de3b?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Orestis Ioannou"><img src="https://images.opencollective.com/guest-ac41de3b/avatar/460.png" width="167" alt="Orestis Ioannou"/><br />Orestis Ioannou</a></td>
|
|
133
|
+
<td align="center"><a href="https://automatio.ai/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Stefan Smiljkovic"><img src="https://avatars.githubusercontent.com/u/1984909?u=b7bf5bc40ed49df3c22f69d2da7b8d78709c49ed&v=4" width="167" alt="Stefan Smiljkovic"/><br />Stefan Smiljkovic</a></td>
|
|
147
134
|
</tr>
|
|
148
135
|
</table>
|
|
149
136
|
|
|
@@ -151,34 +138,46 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
151
138
|
|
|
152
139
|
<table>
|
|
153
140
|
<tr>
|
|
154
|
-
<td align="center"><a href="https://github.com/rhinodavid?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&v=4" width="
|
|
155
|
-
<td align="center"><a href="https://github.com/IPv4Addr?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="IPv4Addr"><img src="https://avatars.githubusercontent.com/u/100147665?u=59996b72f69bb53063cb7e9ff8b8f898616cd94d&v=4" width="
|
|
156
|
-
<td align="center"><a href="https://robbevaes.be/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&v=4" width="
|
|
157
|
-
<td align="center"><a href="https://github.com/aidansunbury?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="
|
|
158
|
-
<td align="center"><a href="https://github.com/soonoo?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&v=4" width="
|
|
159
|
-
<td align="center"><a href="https://kevinporten.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kevin Porten"><img src="https://avatars.githubusercontent.com/u/1839345?u=dc2263d5cfe0d927ce1a0be04a1d55dd6b55405c&v=4" width="
|
|
160
|
-
|
|
141
|
+
<td align="center"><a href="https://github.com/rhinodavid?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&v=4" width="139" alt="David Walsh"/><br />David Walsh</a></td>
|
|
142
|
+
<td align="center"><a href="https://github.com/IPv4Addr?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="IPv4Addr"><img src="https://avatars.githubusercontent.com/u/100147665?u=59996b72f69bb53063cb7e9ff8b8f898616cd94d&v=4" width="139" alt="IPv4Addr"/><br />IPv4Addr</a></td>
|
|
143
|
+
<td align="center"><a href="https://robbevaes.be/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&v=4" width="139" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>
|
|
144
|
+
<td align="center"><a href="https://github.com/aidansunbury?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="139" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>
|
|
145
|
+
<td align="center"><a href="https://github.com/soonoo?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&v=4" width="139" alt="soonoo"/><br />soonoo</a></td>
|
|
146
|
+
<td align="center"><a href="https://kevinporten.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kevin Porten"><img src="https://avatars.githubusercontent.com/u/1839345?u=dc2263d5cfe0d927ce1a0be04a1d55dd6b55405c&v=4" width="139" alt="Kevin Porten"/><br />Kevin Porten</a></td>
|
|
147
|
+
</tr>
|
|
148
|
+
<tr>
|
|
149
|
+
<td align="center"><a href="https://github.com/pumpkinlink?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&v=4" width="139" alt="Denis"/><br />Denis</a></td>
|
|
150
|
+
<td align="center"><a href="https://github.com/christopher-kapic?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&v=4" width="139" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
|
|
151
|
+
<td align="center"><a href="http://ballingt.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Tom Ballinger"><img src="https://avatars.githubusercontent.com/u/458879?u=4b045ac75d721b6ac2b42a74d7d37f61f0414031&v=4" width="139" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>
|
|
152
|
+
<td align="center"><a href="https://lee-sam.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&v=4" width="139" alt="Sam"/><br />Sam</a></td>
|
|
153
|
+
<td align="center"><a href="https://github.com/Titoine?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Titoine"><img src="https://avatars.githubusercontent.com/u/3514286?u=1bb1e86b0c99c8a1121372e56d51a177eea12191&v=4" width="139" alt="Titoine"/><br />Titoine</a></td>
|
|
154
|
+
<td align="center"><a href="https://rigtch.fm/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Igor Makowski"><img src="https://avatars.githubusercontent.com/u/56691628?u=ee8c879478f7c151b9156aef6c74243fa3e247a8&v=4" width="139" alt="Igor Makowski"/><br />Igor Makowski</a></td>
|
|
161
155
|
</tr>
|
|
162
156
|
<tr>
|
|
163
|
-
<td align="center"><a href="https://
|
|
164
|
-
<td align="center"><a href="
|
|
165
|
-
<td align="center"><a href="https://
|
|
166
|
-
<td align="center"><a href="https://
|
|
167
|
-
<td align="center"><a href="https://
|
|
168
|
-
<td align="center"><a href="https://
|
|
169
|
-
<td align="center"><a href="https://dubinets.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Lev Dubinets"><img src="https://avatars.githubusercontent.com/u/3114081?u=f547f5d5012cab54851f1b1ad72d10e537f78fc2&v=4" width="119" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
|
|
157
|
+
<td align="center"><a href="https://blog.cwang.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="hanayashiki"><img src="https://avatars.githubusercontent.com/u/26056783?u=06c3b9205a16fd41a871e82da1cc2a09306d53f5&v=4" width="139" alt="hanayashiki"/><br />hanayashiki</a></td>
|
|
158
|
+
<td align="center"><a href="https://dubinets.io/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Lev Dubinets"><img src="https://avatars.githubusercontent.com/u/3114081?u=f547f5d5012cab54851f1b1ad72d10e537f78fc2&v=4" width="139" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
|
|
159
|
+
<td align="center"><a href="https://kellychan.im/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&v=4" width="139" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
|
|
160
|
+
<td align="center"><a href="https://guyariely.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&v=4" width="139" alt="Guy Ariely"/><br />Guy Ariely</a></td>
|
|
161
|
+
<td align="center"><a href="https://paulsenon.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&v=4" width="139" alt="PaulSenon"/><br />PaulSenon</a></td>
|
|
162
|
+
<td align="center"><a href="https://nakasyou.how/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Shotaro Nakamura"><img src="https://avatars.githubusercontent.com/u/79000684?u=f644df3f29f0e8677a90967115774564f1d9d6ab&v=4" width="139" alt="Shotaro Nakamura"/><br />Shotaro Nakamura</a></td>
|
|
170
163
|
</tr>
|
|
171
164
|
<tr>
|
|
172
|
-
<td align="center"><a href="https://
|
|
173
|
-
<td align="center"><a href="https://
|
|
174
|
-
<td align="center"><a href="https://paulsenon.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&v=4" width="119" alt="PaulSenon"/><br />PaulSenon</a></td>
|
|
175
|
-
<td align="center"><a href="https://nakasyou.how/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Shotaro Nakamura"><img src="https://avatars.githubusercontent.com/u/79000684?u=f644df3f29f0e8677a90967115774564f1d9d6ab&v=4" width="119" alt="Shotaro Nakamura"/><br />Shotaro Nakamura</a></td>
|
|
176
|
-
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="119" alt="Alex"/><br />Alex</a></td>
|
|
177
|
-
<td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
|
|
165
|
+
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="139" alt="Alex"/><br />Alex</a></td>
|
|
166
|
+
<td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&v=4" width="139" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
|
|
178
167
|
</tr>
|
|
179
168
|
</table>
|
|
180
169
|
|
|
181
|
-
With thanks to [
|
|
170
|
+
With thanks to [40 past sponsors](https://orpc.dev/sponsors#past-sponsors) who helped get oRPC here.
|
|
171
|
+
|
|
172
|
+
## Open Source Programs
|
|
173
|
+
|
|
174
|
+
[middleapi](https://github.com/middleapi) is supported by these open source programs:
|
|
175
|
+
|
|
176
|
+
<table>
|
|
177
|
+
<tr>
|
|
178
|
+
<td align="center"><a href="https://claude.com/contact-sales/claude-for-oss" target="_blank" rel="noopener" title="Claude for Open Source"><img src="https://cdn.simpleicons.org/claude" width="64" alt="Claude"/><br />Claude for Open Source</a></td>
|
|
179
|
+
</tr>
|
|
180
|
+
</table>
|
|
182
181
|
|
|
183
182
|
## References
|
|
184
183
|
|
package/dist/index.d.mts
CHANGED
|
@@ -60,9 +60,33 @@ declare enum JsonSchemaXNativeType {
|
|
|
60
60
|
Map = "map"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface JsonSchemaCoercerOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Maximum digits, excluding a leading `-`, of a string coerced to `bigint`. Longer strings are left unchanged.
|
|
66
|
+
* `Number.POSITIVE_INFINITY` disables it.
|
|
67
|
+
*
|
|
68
|
+
* @default 4300
|
|
69
|
+
*/
|
|
70
|
+
maxBigIntDigits?: number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum coercion steps per input value, where a step applies one schema to one value.
|
|
73
|
+
* Inputs with fewer than 100 values are budgeted as 100. Past the budget the whole input is left uncoerced,
|
|
74
|
+
* so validation still runs and reports any mismatch.
|
|
75
|
+
*
|
|
76
|
+
* @default 1000
|
|
77
|
+
*/
|
|
78
|
+
maxStepsPerValue?: number | undefined;
|
|
79
|
+
}
|
|
63
80
|
declare class JsonSchemaCoercer {
|
|
81
|
+
private readonly nativeCoerceOptions;
|
|
82
|
+
private readonly maxStepsPerValue;
|
|
83
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
84
|
+
private idleContext;
|
|
85
|
+
constructor(options?: JsonSchemaCoercerOptions);
|
|
64
86
|
coerce([schema, optional]: [schema: JsonSchema, optional: boolean], value: unknown): unknown;
|
|
65
87
|
private coerceInternal;
|
|
88
|
+
private coerceRef;
|
|
89
|
+
private extendBudget;
|
|
66
90
|
}
|
|
67
91
|
|
|
68
92
|
/**
|
|
@@ -79,6 +103,10 @@ type JsonFileSchema = JsonSchema & object & {
|
|
|
79
103
|
* Returns true when the schema is a file-like string schema.
|
|
80
104
|
*/
|
|
81
105
|
declare function isJsonFileSchema(schema: JsonSchema): schema is JsonFileSchema;
|
|
106
|
+
/**
|
|
107
|
+
* Returns true when a file schema appears anywhere in the schema, such as in a property, a composition, or a def.
|
|
108
|
+
*/
|
|
109
|
+
declare function containsJsonFileSchema(schema: JsonSchema): boolean;
|
|
82
110
|
type JsonObjectSchema = JsonSchema & object & {
|
|
83
111
|
type: 'object';
|
|
84
112
|
};
|
|
@@ -120,6 +148,12 @@ declare function combineJsonObjectSchemaEntries(entries: JsonObjectSchemaEntry[]
|
|
|
120
148
|
* Parses an object schema, or a composition of object schemas, into property entries.
|
|
121
149
|
*/
|
|
122
150
|
declare function extractJsonObjectSchemaEntries(schema: JsonSchema): JsonObjectSchemaEntry[] | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* Returns true when an object can stand for every value the schema describes: the schema constrains objects,
|
|
153
|
+
* by `type` or object keywords, composes only such schemas, or is unconstrained, since an object satisfies it.
|
|
154
|
+
* Unlike {@link extractJsonObjectSchemaEntries}, an unconstrained schema counts as object-like.
|
|
155
|
+
*/
|
|
156
|
+
declare function isJsonObjectLikeSchema(schema: JsonSchema): boolean;
|
|
123
157
|
/**
|
|
124
158
|
* Flattens `anyOf` and `oneOf` unions when they are the only active constraints.
|
|
125
159
|
*/
|
|
@@ -203,8 +237,8 @@ declare function hoistRecursiveRefToDef(schema: JsonSchema): JsonSchema;
|
|
|
203
237
|
*/
|
|
204
238
|
declare function resolveJsonSchemaRootLocalRef(schema: JsonSchema, $defs?: Exclude<JsonSchema, boolean>['$defs']): JsonSchema;
|
|
205
239
|
|
|
206
|
-
interface SmartCoercionHandlerPluginOptions {
|
|
207
|
-
converters?:
|
|
240
|
+
interface SmartCoercionHandlerPluginOptions extends JsonSchemaCoercerOptions {
|
|
241
|
+
converters?: JsonSchemaConverter[] | undefined;
|
|
208
242
|
}
|
|
209
243
|
/**
|
|
210
244
|
* Coerces incoming request data to match the expected `.input` schema types before validation,
|
|
@@ -222,8 +256,8 @@ declare class SmartCoercionHandlerPlugin<T extends Context> implements StandardH
|
|
|
222
256
|
private coerceValue;
|
|
223
257
|
}
|
|
224
258
|
|
|
225
|
-
interface SmartCoercionLinkPluginOptions {
|
|
226
|
-
converters?:
|
|
259
|
+
interface SmartCoercionLinkPluginOptions extends JsonSchemaCoercerOptions {
|
|
260
|
+
converters?: JsonSchemaConverter[] | undefined;
|
|
227
261
|
}
|
|
228
262
|
/**
|
|
229
263
|
* Coerces server responses to match the expected `.output` or `.errors` schema types before validation,
|
|
@@ -259,5 +293,5 @@ declare class StandardJsonSchemaConverter implements JsonSchemaConverter {
|
|
|
259
293
|
convertInternal(schema: StandardJSONSchemaV1 & AnySchema, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean];
|
|
260
294
|
}
|
|
261
295
|
|
|
262
|
-
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
263
|
-
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
|
296
|
+
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, containsJsonFileSchema, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectLikeSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
297
|
+
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaCoercerOptions, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
package/dist/index.d.ts
CHANGED
|
@@ -60,9 +60,33 @@ declare enum JsonSchemaXNativeType {
|
|
|
60
60
|
Map = "map"
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
interface JsonSchemaCoercerOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Maximum digits, excluding a leading `-`, of a string coerced to `bigint`. Longer strings are left unchanged.
|
|
66
|
+
* `Number.POSITIVE_INFINITY` disables it.
|
|
67
|
+
*
|
|
68
|
+
* @default 4300
|
|
69
|
+
*/
|
|
70
|
+
maxBigIntDigits?: number | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum coercion steps per input value, where a step applies one schema to one value.
|
|
73
|
+
* Inputs with fewer than 100 values are budgeted as 100. Past the budget the whole input is left uncoerced,
|
|
74
|
+
* so validation still runs and reports any mismatch.
|
|
75
|
+
*
|
|
76
|
+
* @default 1000
|
|
77
|
+
*/
|
|
78
|
+
maxStepsPerValue?: number | undefined;
|
|
79
|
+
}
|
|
63
80
|
declare class JsonSchemaCoercer {
|
|
81
|
+
private readonly nativeCoerceOptions;
|
|
82
|
+
private readonly maxStepsPerValue;
|
|
83
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
84
|
+
private idleContext;
|
|
85
|
+
constructor(options?: JsonSchemaCoercerOptions);
|
|
64
86
|
coerce([schema, optional]: [schema: JsonSchema, optional: boolean], value: unknown): unknown;
|
|
65
87
|
private coerceInternal;
|
|
88
|
+
private coerceRef;
|
|
89
|
+
private extendBudget;
|
|
66
90
|
}
|
|
67
91
|
|
|
68
92
|
/**
|
|
@@ -79,6 +103,10 @@ type JsonFileSchema = JsonSchema & object & {
|
|
|
79
103
|
* Returns true when the schema is a file-like string schema.
|
|
80
104
|
*/
|
|
81
105
|
declare function isJsonFileSchema(schema: JsonSchema): schema is JsonFileSchema;
|
|
106
|
+
/**
|
|
107
|
+
* Returns true when a file schema appears anywhere in the schema, such as in a property, a composition, or a def.
|
|
108
|
+
*/
|
|
109
|
+
declare function containsJsonFileSchema(schema: JsonSchema): boolean;
|
|
82
110
|
type JsonObjectSchema = JsonSchema & object & {
|
|
83
111
|
type: 'object';
|
|
84
112
|
};
|
|
@@ -120,6 +148,12 @@ declare function combineJsonObjectSchemaEntries(entries: JsonObjectSchemaEntry[]
|
|
|
120
148
|
* Parses an object schema, or a composition of object schemas, into property entries.
|
|
121
149
|
*/
|
|
122
150
|
declare function extractJsonObjectSchemaEntries(schema: JsonSchema): JsonObjectSchemaEntry[] | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* Returns true when an object can stand for every value the schema describes: the schema constrains objects,
|
|
153
|
+
* by `type` or object keywords, composes only such schemas, or is unconstrained, since an object satisfies it.
|
|
154
|
+
* Unlike {@link extractJsonObjectSchemaEntries}, an unconstrained schema counts as object-like.
|
|
155
|
+
*/
|
|
156
|
+
declare function isJsonObjectLikeSchema(schema: JsonSchema): boolean;
|
|
123
157
|
/**
|
|
124
158
|
* Flattens `anyOf` and `oneOf` unions when they are the only active constraints.
|
|
125
159
|
*/
|
|
@@ -203,8 +237,8 @@ declare function hoistRecursiveRefToDef(schema: JsonSchema): JsonSchema;
|
|
|
203
237
|
*/
|
|
204
238
|
declare function resolveJsonSchemaRootLocalRef(schema: JsonSchema, $defs?: Exclude<JsonSchema, boolean>['$defs']): JsonSchema;
|
|
205
239
|
|
|
206
|
-
interface SmartCoercionHandlerPluginOptions {
|
|
207
|
-
converters?:
|
|
240
|
+
interface SmartCoercionHandlerPluginOptions extends JsonSchemaCoercerOptions {
|
|
241
|
+
converters?: JsonSchemaConverter[] | undefined;
|
|
208
242
|
}
|
|
209
243
|
/**
|
|
210
244
|
* Coerces incoming request data to match the expected `.input` schema types before validation,
|
|
@@ -222,8 +256,8 @@ declare class SmartCoercionHandlerPlugin<T extends Context> implements StandardH
|
|
|
222
256
|
private coerceValue;
|
|
223
257
|
}
|
|
224
258
|
|
|
225
|
-
interface SmartCoercionLinkPluginOptions {
|
|
226
|
-
converters?:
|
|
259
|
+
interface SmartCoercionLinkPluginOptions extends JsonSchemaCoercerOptions {
|
|
260
|
+
converters?: JsonSchemaConverter[] | undefined;
|
|
227
261
|
}
|
|
228
262
|
/**
|
|
229
263
|
* Coerces server responses to match the expected `.output` or `.errors` schema types before validation,
|
|
@@ -259,5 +293,5 @@ declare class StandardJsonSchemaConverter implements JsonSchemaConverter {
|
|
|
259
293
|
convertInternal(schema: StandardJSONSchemaV1 & AnySchema, direction: JsonSchemaConverterDirection): [jsonSchema: JsonSchema, optional: boolean];
|
|
260
294
|
}
|
|
261
295
|
|
|
262
|
-
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
263
|
-
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
|
296
|
+
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, containsJsonFileSchema, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectLikeSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
297
|
+
export type { JsonArraySchema, JsonFileSchema, JsonObjectSchema, JsonObjectSchemaEntry, JsonSchema, JsonSchemaCoercerOptions, JsonSchemaConverter, JsonSchemaConverterDirection, JsonSchemaKeywords, SmartCoercionHandlerPluginOptions, SmartCoercionLinkPluginOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setOwn, get, isPlainObject, tryOrUndefined, getOwn, toArray, isDeepEqual, omit
|
|
1
|
+
import { setOwn, get, DEFAULT_MAX_BIGINT_DIGITS, isPlainObject, tryOrUndefined, getOwn, toArray, isTypescriptObject, parseBigIntString, findDeepMatches, isDeepEqual, omit } from '@orpc/shared';
|
|
2
2
|
import { ORPCError, cloneORPCError } from '@orpc/client';
|
|
3
3
|
import { getProcedureContractOrThrow } from '@orpc/contract';
|
|
4
4
|
|
|
@@ -215,7 +215,7 @@ const NATIVE_TYPES = /* @__PURE__ */ new Map([
|
|
|
215
215
|
[JsonSchemaXNativeType.BigInt, {
|
|
216
216
|
types: ["string", "integer", "number"],
|
|
217
217
|
is: (value) => typeof value === "bigint",
|
|
218
|
-
coerce: (value) => typeof value === "string" ? stringToBigInt(value) : typeof value === "number" ? numberToBigInt(value) : value
|
|
218
|
+
coerce: (value, { maxBigIntDigits }) => typeof value === "string" ? stringToBigInt(value, maxBigIntDigits) : typeof value === "number" ? numberToBigInt(value) : value
|
|
219
219
|
}],
|
|
220
220
|
[JsonSchemaXNativeType.Url, {
|
|
221
221
|
types: ["string"],
|
|
@@ -238,21 +238,58 @@ const NATIVE_TYPES = /* @__PURE__ */ new Map([
|
|
|
238
238
|
function minSatisfaction(a, b) {
|
|
239
239
|
return a < b ? a : b;
|
|
240
240
|
}
|
|
241
|
+
const MIN_BUDGETED_VALUES = 100;
|
|
242
|
+
function createContext() {
|
|
243
|
+
return { rootSchema: true, memo: void 0, memoize: false, steps: 0, maxSteps: 0, input: void 0 };
|
|
244
|
+
}
|
|
245
|
+
class CoercionBudgetExceededError extends Error {
|
|
246
|
+
}
|
|
241
247
|
class JsonSchemaCoercer {
|
|
248
|
+
nativeCoerceOptions;
|
|
249
|
+
maxStepsPerValue;
|
|
250
|
+
/** Reused between calls, since building a context is slow until V8 warms up. */
|
|
251
|
+
idleContext = createContext();
|
|
252
|
+
constructor(options = {}) {
|
|
253
|
+
this.nativeCoerceOptions = {
|
|
254
|
+
maxBigIntDigits: options.maxBigIntDigits ?? DEFAULT_MAX_BIGINT_DIGITS
|
|
255
|
+
};
|
|
256
|
+
this.maxStepsPerValue = options.maxStepsPerValue ?? 1e3;
|
|
257
|
+
}
|
|
242
258
|
coerce([schema, optional], value) {
|
|
243
259
|
if (optional && value === void 0) {
|
|
244
260
|
return value;
|
|
245
261
|
}
|
|
246
|
-
const
|
|
247
|
-
|
|
262
|
+
const context = this.idleContext ?? createContext();
|
|
263
|
+
this.idleContext = void 0;
|
|
264
|
+
context.rootSchema = schema;
|
|
265
|
+
context.memoize = false;
|
|
266
|
+
context.steps = 0;
|
|
267
|
+
context.maxSteps = this.maxStepsPerValue * MIN_BUDGETED_VALUES;
|
|
268
|
+
context.input = value;
|
|
269
|
+
try {
|
|
270
|
+
const [, coerced] = this.coerceInternal(context, schema, value);
|
|
271
|
+
return coerced;
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (error instanceof CoercionBudgetExceededError) {
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
276
|
+
throw error;
|
|
277
|
+
} finally {
|
|
278
|
+
context.memo = void 0;
|
|
279
|
+
context.input = void 0;
|
|
280
|
+
this.idleContext = context;
|
|
281
|
+
}
|
|
248
282
|
}
|
|
249
|
-
coerceInternal(
|
|
283
|
+
coerceInternal(context, schema, value, appliedRefs) {
|
|
284
|
+
if (++context.steps > context.maxSteps) {
|
|
285
|
+
this.extendBudget(context);
|
|
286
|
+
}
|
|
250
287
|
if (typeof schema === "boolean") {
|
|
251
288
|
return [schema ? SATISFIED : UNSATISFIED, value];
|
|
252
289
|
}
|
|
253
290
|
if (Array.isArray(schema.type)) {
|
|
254
291
|
return this.coerceInternal(
|
|
255
|
-
|
|
292
|
+
context,
|
|
256
293
|
{ anyOf: schema.type.map((type) => ({ ...schema, type })) },
|
|
257
294
|
value,
|
|
258
295
|
appliedRefs
|
|
@@ -261,12 +298,12 @@ class JsonSchemaCoercer {
|
|
|
261
298
|
let coerced = value;
|
|
262
299
|
let satisfied = SATISFIED;
|
|
263
300
|
if (typeof schema.$ref === "string") {
|
|
264
|
-
const resolved = schema.$ref.startsWith("#/") ? get(rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? rootSchema : void 0;
|
|
301
|
+
const resolved = schema.$ref.startsWith("#/") ? get(context.rootSchema, schema.$ref.slice("#/".length).split("/").map(decodeJsonPointerSegment)) : schema.$ref === "#" ? context.rootSchema : void 0;
|
|
265
302
|
if (resolved !== void 0 && !appliedRefs?.has(resolved)) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
303
|
+
if (schema.type === "object" || schema.type === "array") {
|
|
304
|
+
context.memoize = true;
|
|
305
|
+
}
|
|
306
|
+
const [subSatisfied, subCoerced] = this.coerceRef(context, resolved, coerced, appliedRefs);
|
|
270
307
|
coerced = subCoerced;
|
|
271
308
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
272
309
|
}
|
|
@@ -292,7 +329,7 @@ class JsonSchemaCoercer {
|
|
|
292
329
|
const declaredNativeType = NATIVE_TYPES.get(schema["x-native-type"]);
|
|
293
330
|
const nativeType = schema.type === void 0 || declaredNativeType?.types.includes(schema.type) ? declaredNativeType : void 0;
|
|
294
331
|
if (nativeType && !nativeType.afterTypeCheck) {
|
|
295
|
-
coerced = nativeType.coerce(coerced);
|
|
332
|
+
coerced = nativeType.coerce(coerced, this.nativeCoerceOptions);
|
|
296
333
|
}
|
|
297
334
|
if (schema.type && !nativeType?.is(coerced)) {
|
|
298
335
|
switch (schema.type) {
|
|
@@ -346,7 +383,7 @@ class JsonSchemaCoercer {
|
|
|
346
383
|
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
347
384
|
return item;
|
|
348
385
|
}
|
|
349
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
386
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, item);
|
|
350
387
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
351
388
|
if (subCoerced !== item) {
|
|
352
389
|
shouldUseCoercedItems = true;
|
|
@@ -383,7 +420,7 @@ class JsonSchemaCoercer {
|
|
|
383
420
|
if (subSchema === void 0) {
|
|
384
421
|
satisfied = minSatisfaction(satisfied, LOOSELY_SATISFIED);
|
|
385
422
|
} else {
|
|
386
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
423
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, value2);
|
|
387
424
|
coercedItems[key] = subCoerced;
|
|
388
425
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
389
426
|
if (subCoerced !== value2) {
|
|
@@ -407,24 +444,26 @@ class JsonSchemaCoercer {
|
|
|
407
444
|
}
|
|
408
445
|
if (nativeType) {
|
|
409
446
|
if (nativeType.afterTypeCheck) {
|
|
410
|
-
coerced = nativeType.coerce(coerced);
|
|
447
|
+
coerced = nativeType.coerce(coerced, this.nativeCoerceOptions);
|
|
411
448
|
}
|
|
412
449
|
if (!nativeType.is(coerced)) {
|
|
413
450
|
satisfied = UNSATISFIED;
|
|
414
451
|
}
|
|
415
452
|
}
|
|
416
453
|
if (schema.allOf) {
|
|
454
|
+
context.memoize = true;
|
|
417
455
|
for (const subSchema of schema.allOf) {
|
|
418
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
456
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, coerced, appliedRefs);
|
|
419
457
|
coerced = subCoerced;
|
|
420
458
|
satisfied = minSatisfaction(satisfied, subSatisfied);
|
|
421
459
|
}
|
|
422
460
|
}
|
|
423
461
|
for (const key of ["anyOf", "oneOf"]) {
|
|
424
462
|
if (schema[key]) {
|
|
463
|
+
context.memoize = true;
|
|
425
464
|
let best;
|
|
426
465
|
for (const subSchema of schema[key]) {
|
|
427
|
-
const [subSatisfied, subCoerced] = this.coerceInternal(
|
|
466
|
+
const [subSatisfied, subCoerced] = this.coerceInternal(context, subSchema, coerced, appliedRefs);
|
|
428
467
|
if (subSatisfied === UNSATISFIED) {
|
|
429
468
|
continue;
|
|
430
469
|
}
|
|
@@ -445,13 +484,64 @@ class JsonSchemaCoercer {
|
|
|
445
484
|
}
|
|
446
485
|
}
|
|
447
486
|
if (typeof schema.not !== "undefined") {
|
|
448
|
-
|
|
487
|
+
context.memoize = true;
|
|
488
|
+
const [notSatisfied] = this.coerceInternal(context, schema.not, coerced, appliedRefs);
|
|
449
489
|
if (notSatisfied !== UNSATISFIED) {
|
|
450
490
|
satisfied = UNSATISFIED;
|
|
451
491
|
}
|
|
452
492
|
}
|
|
453
493
|
return [satisfied, coerced];
|
|
454
494
|
}
|
|
495
|
+
coerceRef(context, resolved, value, appliedRefs) {
|
|
496
|
+
let memo;
|
|
497
|
+
if (context.memoize && !appliedRefs?.size && isTypescriptObject(value)) {
|
|
498
|
+
context.memo ??= /* @__PURE__ */ new Map();
|
|
499
|
+
memo = context.memo.get(resolved);
|
|
500
|
+
if (!memo) {
|
|
501
|
+
memo = /* @__PURE__ */ new Map();
|
|
502
|
+
context.memo.set(resolved, memo);
|
|
503
|
+
}
|
|
504
|
+
const cached = memo.get(value);
|
|
505
|
+
if (cached) {
|
|
506
|
+
return cached;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
appliedRefs ??= /* @__PURE__ */ new Set();
|
|
510
|
+
appliedRefs.add(resolved);
|
|
511
|
+
const result = this.coerceInternal(context, resolved, value, appliedRefs);
|
|
512
|
+
appliedRefs.delete(resolved);
|
|
513
|
+
memo?.set(value, result);
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
extendBudget(context) {
|
|
517
|
+
const limit = 2 * context.steps / this.maxStepsPerValue;
|
|
518
|
+
context.maxSteps = this.maxStepsPerValue * Math.max(countValues(context.input, limit), MIN_BUDGETED_VALUES);
|
|
519
|
+
if (context.steps > context.maxSteps) {
|
|
520
|
+
throw new CoercionBudgetExceededError();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function countValues(input, limit) {
|
|
525
|
+
const walked = /* @__PURE__ */ new Set();
|
|
526
|
+
const stack = [input];
|
|
527
|
+
let count = 1;
|
|
528
|
+
while (stack.length) {
|
|
529
|
+
const value = stack.pop();
|
|
530
|
+
if ((Array.isArray(value) || isPlainObject(value)) && !walked.has(value)) {
|
|
531
|
+
walked.add(value);
|
|
532
|
+
const items = Array.isArray(value) ? value : Object.values(value);
|
|
533
|
+
for (let i = 0; i < items.length; i++) {
|
|
534
|
+
if (++count >= limit) {
|
|
535
|
+
return count;
|
|
536
|
+
}
|
|
537
|
+
const item = items[i];
|
|
538
|
+
if (isTypescriptObject(item)) {
|
|
539
|
+
stack.push(item);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return count;
|
|
455
545
|
}
|
|
456
546
|
const NUMBER_PATTERN = /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/;
|
|
457
547
|
function stringToNumber(value) {
|
|
@@ -475,11 +565,8 @@ function stringToInteger(value) {
|
|
|
475
565
|
}
|
|
476
566
|
return num;
|
|
477
567
|
}
|
|
478
|
-
function stringToBigInt(value) {
|
|
479
|
-
|
|
480
|
-
return value;
|
|
481
|
-
}
|
|
482
|
-
return BigInt(value);
|
|
568
|
+
function stringToBigInt(value, maxDigits) {
|
|
569
|
+
return parseBigIntString(value, maxDigits) ?? value;
|
|
483
570
|
}
|
|
484
571
|
function numberToBigInt(value) {
|
|
485
572
|
if (!Number.isInteger(value)) {
|
|
@@ -497,7 +584,7 @@ function stringToBoolean(value) {
|
|
|
497
584
|
}
|
|
498
585
|
return value;
|
|
499
586
|
}
|
|
500
|
-
const DATE_TIME_PATTERN = /^(?!-0{6})(?:[+-]\d{2})?\d{4}-\d{2}-\d{2}(?:[T ]
|
|
587
|
+
const DATE_TIME_PATTERN = /^(?!-0{6})(?:[+-]\d{2})?\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/;
|
|
501
588
|
const DAYS_IN_MONTH = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
502
589
|
function stringToDate(value) {
|
|
503
590
|
if (!DATE_TIME_PATTERN.test(value)) {
|
|
@@ -560,6 +647,9 @@ function isJsonPrimitiveSchema(schema) {
|
|
|
560
647
|
function isJsonFileSchema(schema) {
|
|
561
648
|
return typeof schema !== "boolean" && schema.type === "string" && (typeof schema.contentMediaType === "string" || schema.format === "binary" || schema.contentEncoding === "binary");
|
|
562
649
|
}
|
|
650
|
+
function containsJsonFileSchema(schema) {
|
|
651
|
+
return findDeepMatches((v) => isPlainObject(v) && isJsonFileSchema(v), schema).values.length > 0;
|
|
652
|
+
}
|
|
563
653
|
function isJsonObjectSchema(schema) {
|
|
564
654
|
return typeof schema !== "boolean" && schema.type === "object";
|
|
565
655
|
}
|
|
@@ -675,6 +765,35 @@ function extractJsonObjectSchemaEntries(schema) {
|
|
|
675
765
|
}
|
|
676
766
|
return result.entries.map(([n, s, ...r]) => [n, withRootDefs(s, schema.$defs), ...r]);
|
|
677
767
|
}
|
|
768
|
+
const JSON_SCHEMA_OBJECT_KEYWORDS = ["properties", "patternProperties", "additionalProperties", "required", "propertyNames", "minProperties", "maxProperties"];
|
|
769
|
+
function isJsonObjectLikeSchema(schema) {
|
|
770
|
+
return isJsonObjectLikeSchemaInternal(schema, typeof schema === "object" ? schema.$defs : void 0, /* @__PURE__ */ new Set());
|
|
771
|
+
}
|
|
772
|
+
function isJsonObjectLikeSchemaInternal(schema, $defs, followedRefs) {
|
|
773
|
+
if (typeof schema === "object" && typeof schema.$ref === "string") {
|
|
774
|
+
if (followedRefs.has(schema.$ref)) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
followedRefs = new Set(followedRefs).add(schema.$ref);
|
|
778
|
+
}
|
|
779
|
+
const resolved = resolveJsonSchemaRootLocalRef(schema, $defs);
|
|
780
|
+
if (typeof resolved === "boolean") {
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
if (resolved.type !== void 0) {
|
|
784
|
+
return resolved.type === "object";
|
|
785
|
+
}
|
|
786
|
+
if (JSON_SCHEMA_OBJECT_KEYWORDS.some((keyword) => keyword in resolved)) {
|
|
787
|
+
return true;
|
|
788
|
+
}
|
|
789
|
+
for (const keyword of ["allOf", "anyOf", "oneOf"]) {
|
|
790
|
+
const members = resolved[keyword];
|
|
791
|
+
if (Array.isArray(members) && members.length > 0) {
|
|
792
|
+
return members.every((member) => isJsonObjectLikeSchemaInternal(member, $defs, followedRefs));
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return isUnconstrainedSchema(resolved);
|
|
796
|
+
}
|
|
678
797
|
function extractJsonObjectSchemaEntriesInternal(schema, $defs, resolvingRefs) {
|
|
679
798
|
if (typeof schema !== "object") {
|
|
680
799
|
return { entries: [], objectLike: false };
|
|
@@ -902,7 +1021,7 @@ class SmartCoercionHandlerPlugin {
|
|
|
902
1021
|
...toArray(options.converters),
|
|
903
1022
|
new StandardJsonSchemaConverter()
|
|
904
1023
|
]);
|
|
905
|
-
this.coercer = new JsonSchemaCoercer();
|
|
1024
|
+
this.coercer = new JsonSchemaCoercer(options);
|
|
906
1025
|
}
|
|
907
1026
|
init(options) {
|
|
908
1027
|
return {
|
|
@@ -940,7 +1059,7 @@ class SmartCoercionLinkPlugin {
|
|
|
940
1059
|
...toArray(options.converters),
|
|
941
1060
|
new StandardJsonSchemaConverter()
|
|
942
1061
|
]);
|
|
943
|
-
this.coercer = new JsonSchemaCoercer();
|
|
1062
|
+
this.coercer = new JsonSchemaCoercer(options);
|
|
944
1063
|
}
|
|
945
1064
|
name = "~smart-coercion";
|
|
946
1065
|
/**
|
|
@@ -995,4 +1114,4 @@ class SmartCoercionLinkPlugin {
|
|
|
995
1114
|
}
|
|
996
1115
|
}
|
|
997
1116
|
|
|
998
|
-
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
|
1117
|
+
export { DelegatingJsonSchemaConverter, JsonSchemaCoercer, JsonSchemaFormat, JsonSchemaType, JsonSchemaXNativeType, SmartCoercionHandlerPlugin, SmartCoercionLinkPlugin, StandardJsonSchemaConverter, combineJsonObjectSchemaEntries, combineJsonSchemasWithComposition, containsJsonFileSchema, decodeJsonPointerSegment, deduplicateJsonSchemas, encodeJsonPointerSegment, ensureJsonSchemaObject, extractJsonObjectSchemaEntries, flattenJsonUnionSchema, hoistRecursiveRefToDef, isJsonArraySchema, isJsonFileSchema, isJsonObjectLikeSchema, isJsonObjectSchema, isJsonPrimitiveSchema, isStandardSchemaOptional, isUnconstrainedSchema, mapJsonSchemaRefs, matchArrayableJsonSchema, resolveJsonSchemaRootLocalRef, visitJsonSchemaRefs };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orpc/json-schema",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.45",
|
|
5
5
|
"description": "JSON Schema conversion and smart request coercion for oRPC and OpenAPI",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": [
|
|
@@ -36,14 +36,14 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@openapi-spec/types": "~0.3.0",
|
|
39
|
-
"@orpc/client": "2.0.0-beta.
|
|
40
|
-
"@orpc/contract": "2.0.0-beta.
|
|
41
|
-
"@orpc/server": "2.0.0-beta.
|
|
42
|
-
"@orpc/shared": "2.0.0-beta.
|
|
39
|
+
"@orpc/client": "2.0.0-beta.45",
|
|
40
|
+
"@orpc/contract": "2.0.0-beta.45",
|
|
41
|
+
"@orpc/server": "2.0.0-beta.45",
|
|
42
|
+
"@orpc/shared": "2.0.0-beta.45",
|
|
43
43
|
"@standard-schema/spec": "^1.1.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"zod": "^4.
|
|
46
|
+
"zod": "^4.6.7"
|
|
47
47
|
},
|
|
48
48
|
"scripts": {
|
|
49
49
|
"type:check": "tsc -b"
|