@orpc/server 2.0.0-beta.31 → 2.0.0-beta.33

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  <a href="https://codecov.io/gh/middleapi/orpc">
5
5
  <img alt="codecov" src="https://codecov.io/gh/middleapi/orpc/branch/main/graph/badge.svg">
6
6
  </a>
7
- <a href="https://npmx.dev/package/@orpc/server">
7
+ <a href="https://www.npmjs.com/package/@orpc/server">
8
8
  <img alt="weekly downloads" src="https://img.shields.io/npm/dw/%40orpc%2Fserver?logo=npm" />
9
9
  </a>
10
10
  <a href="https://app.codspeed.io/middleapi/orpc?utm_source=badge">
@@ -29,44 +29,54 @@ You can read the documentation [here](https://orpc.dev).
29
29
 
30
30
  **Core**
31
31
 
32
- - [@orpc/contract](https://npmx.dev/package/@orpc/contract): Define API contract as the single source of truth.
33
- - [@orpc/server](https://npmx.dev/package/@orpc/server): Build APIs or implement contracts.
34
- - [@orpc/client](https://npmx.dev/package/@orpc/client): Consume APIs with end-to-end type safety.
35
- - [@orpc/openapi](https://npmx.dev/package/@orpc/openapi): Add OpenAPI compatibility to APIs.
32
+ | Package | Purpose | Docs |
33
+ | -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
34
+ | [@orpc/contract](https://www.npmjs.com/package/@orpc/contract) | Define API contract as the single source of truth. | [Procedure Contract](https://orpc.dev/docs/contract/procedure), [Contract Router](https://orpc.dev/docs/contract/router), [Implementation](https://orpc.dev/docs/contract/implementation), [Generate from OpenAPI](https://orpc.dev/docs/contract/generate-from-openapi) |
35
+ | [@orpc/server](https://www.npmjs.com/package/@orpc/server) | Build APIs or implement contracts. | [Procedure](https://orpc.dev/docs/procedure), [Router](https://orpc.dev/docs/router), [Middleware](https://orpc.dev/docs/middleware), [Context](https://orpc.dev/docs/context), [RPC Handler](https://orpc.dev/docs/rpc/handler) |
36
+ | [@orpc/client](https://www.npmjs.com/package/@orpc/client) | Consume APIs with end-to-end type safety. | [Client-Side Clients](https://orpc.dev/docs/client/client-side), [Server-Side Clients](https://orpc.dev/docs/client/server-side), [RPC Link](https://orpc.dev/docs/rpc/link), [Error Handling](https://orpc.dev/docs/client/error-handling) |
37
+ | [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi) | Add OpenAPI compatibility to APIs. | [OpenAPI Handler](https://orpc.dev/docs/openapi/handler), [OpenAPI Link](https://orpc.dev/docs/openapi/link), [Specification](https://orpc.dev/docs/openapi/specification), [Scalar](https://orpc.dev/docs/openapi/scalar) |
36
38
 
37
39
  **Schema validation**
38
40
 
39
- - [@orpc/zod](https://npmx.dev/package/@orpc/zod): Integrate with [Zod](https://zod.dev/).
40
- - [@orpc/valibot](https://npmx.dev/package/@orpc/valibot): Integrate with [Valibot](https://valibot.dev/).
41
- - [@orpc/arktype](https://npmx.dev/package/@orpc/arktype): Integrate with [ArkType](https://arktype.io/).
41
+ | Package | Purpose | Docs |
42
+ | ------------------------------------------------------------ | ----------------------------------------------- | ----------------------------------------------------- |
43
+ | [@orpc/zod](https://www.npmjs.com/package/@orpc/zod) | Integrate with [Zod](https://zod.dev/). | [Zod](https://orpc.dev/docs/integrations/zod) |
44
+ | [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot) | Integrate with [Valibot](https://valibot.dev/). | [Valibot](https://orpc.dev/docs/integrations/valibot) |
45
+ | [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype) | Integrate with [ArkType](https://arktype.io/). | [ArkType](https://orpc.dev/docs/integrations/arktype) |
42
46
 
43
47
  **Built-in features**
44
48
 
45
- - [@orpc/publisher](https://npmx.dev/package/@orpc/publisher): Pub/Sub with memory, Redis, and Upstash adapters.
46
- - [@orpc/ratelimit](https://npmx.dev/package/@orpc/ratelimit): Rate limiting with memory, Redis, and Upstash adapters.
47
- - [@orpc/hibernation](https://npmx.dev/package/@orpc/hibernation): Leverage Hibernation APIs like [Cloudflare's Hibernation WebSocket](https://developers.cloudflare.com/durable-objects/best-practices/websockets/#durable-objects-hibernation-websocket-api).
48
- - [@orpc/json-schema](https://npmx.dev/package/@orpc/json-schema): Smart coercion for OpenAPI requests.
49
+ | Package | Purpose | Docs |
50
+ | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
51
+ | [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher) | Pub/Sub with memory, Redis, and Upstash adapters. | [Publisher](https://orpc.dev/docs/helpers/publisher) |
52
+ | [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit) | Rate limiting with memory, Redis, and Upstash adapters. | [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
53
+ | [@orpc/hibernation](https://www.npmjs.com/package/@orpc/hibernation) | Leverage Hibernation APIs like [Cloudflare's Hibernation WebSocket](https://developers.cloudflare.com/durable-objects/best-practices/websockets/#durable-objects-hibernation-websocket-api). | [Hibernation](https://orpc.dev/docs/integrations/hibernation) |
54
+ | [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema) | Smart coercion for OpenAPI requests. | [Smart Coercion](https://orpc.dev/docs/plugins/smart-coercion) |
49
55
 
50
56
  **Framework & ecosystem integrations**
51
57
 
52
- - [@orpc/next](https://npmx.dev/package/@orpc/next): Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data).
53
- - [@orpc/ai-sdk](https://npmx.dev/package/@orpc/ai-sdk): Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools.
54
- - [@orpc/tanstack-query](https://npmx.dev/package/@orpc/tanstack-query): Integrate with [TanStack Query](https://tanstack.com/query/latest).
55
- - [@orpc/pinia-colada](https://npmx.dev/package/@orpc/pinia-colada): Integrate with [Pinia Colada](https://pinia-colada.esm.dev/).
56
- - [@orpc/swr](https://npmx.dev/package/@orpc/swr): Integrate with [SWR](https://swr.vercel.app/).
57
- - [@orpc/experimental-msw](https://npmx.dev/package/@orpc/experimental-msw): Mock procedures with [Mock Service Worker](https://mswjs.io/).
58
- - [@orpc/experimental-effect](https://npmx.dev/package/@orpc/experimental-effect): Integrate with [Effect](https://effect.website/).
59
- - [@orpc/nest](https://npmx.dev/package/@orpc/nest): Implement your contract with [NestJS](https://nestjs.com/).
60
- - [@orpc/node](https://npmx.dev/package/@orpc/node): [Node.js](https://nodejs.org/) plugins for static file serving and large uploads.
61
- - [@orpc/bun](https://npmx.dev/package/@orpc/bun): Adapters for [Bun's Redis](https://bun.sh/).
62
- - [@orpc/cloudflare](https://npmx.dev/package/@orpc/cloudflare): Adapters for [Cloudflare's RateLimit and Durable Objects](https://developers.cloudflare.com/workers/).
63
- - [@orpc/trpc](https://npmx.dev/package/@orpc/trpc): Reuse existing [tRPC](https://trpc.io/) routers within oRPC.
58
+ | Package | Purpose | Docs |
59
+ | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
60
+ | [@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) |
61
+ | [@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) |
62
+ | [@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) |
63
+ | [@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) |
64
+ | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
65
+ | [@orpc/experimental-msw](https://www.npmjs.com/package/@orpc/experimental-msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
66
+ | [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
67
+ | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
68
+ | [@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) |
69
+ | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
70
+ | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare's RateLimit and Durable Objects](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
71
+ | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
64
72
 
65
73
  **Observability**
66
74
 
67
- - [@orpc/opentelemetry](https://npmx.dev/package/@orpc/opentelemetry): Integrate with [OpenTelemetry](https://opentelemetry.io/) for distributed tracing.
68
- - [@orpc/pino](https://npmx.dev/package/@orpc/pino): Integrate with [Pino](https://getpino.io/) for logging.
69
- - [@orpc/evlog](https://npmx.dev/package/@orpc/evlog): Integrate with [Evlog](https://evlog.dev/) for logging.
75
+ | Package | Purpose | Docs |
76
+ | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
77
+ | [@orpc/opentelemetry](https://www.npmjs.com/package/@orpc/opentelemetry) | Integrate with [OpenTelemetry](https://opentelemetry.io/) for distributed tracing. | [OpenTelemetry](https://orpc.dev/docs/integrations/opentelemetry) |
78
+ | [@orpc/pino](https://www.npmjs.com/package/@orpc/pino) | Integrate with [Pino](https://getpino.io/) for logging. | [Pino](https://orpc.dev/docs/integrations/pino) |
79
+ | [@orpc/evlog](https://www.npmjs.com/package/@orpc/evlog) | Integrate with [Evlog](https://evlog.dev/) for logging. | [Evlog](https://orpc.dev/docs/integrations/evlog) |
70
80
 
71
81
  ## Sponsors
72
82
 
@@ -76,6 +86,9 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
76
86
  <tr>
77
87
  <td width="2000"><a href="https://screenshotone.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener" title="The screenshot API for developers"><img src="https://avatars.githubusercontent.com/u/97035603?v=4" width="64" align="left" hspace="12" alt="ScreenshotOne.com"/><b>ScreenshotOne.com</b></a><br /><sub>The screenshot API for developers</sub></td>
78
88
  </tr>
89
+ <tr>
90
+ <td width="2000"><a href="https://yuzu.health/careers?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="We&#39;re hiring NYC based engineers"><img src="https://avatars.githubusercontent.com/u/102488956?v=4" width="64" align="left" hspace="12" alt="Yuzu"/><b>Yuzu</b></a><br /><sub>We&#39;re hiring NYC based engineers</sub></td>
91
+ </tr>
79
92
  <tr>
80
93
  <td width="2000"><a href="https://misskey.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Decentralized microblogging SNS born on Earth"><img src="https://github.com/MisskeyIO.png" width="64" align="left" hspace="12" alt="MisskeyHQ"/><b>MisskeyHQ</b></a><br /><sub>Decentralized microblogging SNS born on Earth</sub></td>
81
94
  </tr>
@@ -113,6 +126,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
113
126
  <td align="center"><a href="https://github.com/itigoore01?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="shota"><img src="https://avatars.githubusercontent.com/u/11831107?u=c976a6dc7e055eb026304c46c99100ed22b0c8e0&amp;v=4" width="139" alt="shota"/><br />shota</a></td>
114
127
  <td align="center"><a href="https://github.com/ellis-driscoll?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Ellis Driscoll"><img src="https://avatars.githubusercontent.com/u/70685966?u=c5f95bc33b5991d9744abe00052542e4a2ed3cb9&amp;v=4" width="139" alt="Ellis Driscoll"/><br />Ellis Driscoll</a></td>
115
128
  <td align="center"><a href="https://github.com/hoangbn?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Hoang Nguyen"><img src="https://avatars.githubusercontent.com/u/38968280?u=c90084c6de65c56facabab7ba13a72a49ddbc3e4&amp;v=4" width="139" alt="Hoang Nguyen"/><br />Hoang Nguyen</a></td>
129
+ <td align="center"><a href="https://opencollective.com/guest-ac41de3b?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Orestis Ioannou"><img src="https://images.opencollective.com/guest-ac41de3b/avatar/460.png" width="139" alt="Orestis Ioannou"/><br />Orestis Ioannou</a></td>
116
130
  </tr>
117
131
  </table>
118
132
 
@@ -121,30 +135,32 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
121
135
  <table>
122
136
  <tr>
123
137
  <td align="center"><a href="https://github.com/rhinodavid?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="David Walsh"><img src="https://avatars.githubusercontent.com/u/5778036?u=b5521f07d2f88c3db2a0dae62b5f2f8357214af0&amp;v=4" width="119" alt="David Walsh"/><br />David Walsh</a></td>
138
+ <td align="center"><a href="https://github.com/IPv4Addr?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="IPv4Addr"><img src="https://avatars.githubusercontent.com/u/100147665?u=59996b72f69bb53063cb7e9ff8b8f898616cd94d&amp;v=4" width="119" alt="IPv4Addr"/><br />IPv4Addr</a></td>
124
139
  <td align="center"><a href="https://robbevaes.be/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Robbe Vaes"><img src="https://avatars.githubusercontent.com/u/44748019?u=e0232402c045ad4eac7cbd217f1f47e083103b89&amp;v=4" width="119" alt="Robbe Vaes"/><br />Robbe Vaes</a></td>
125
140
  <td align="center"><a href="https://github.com/aidansunbury?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Aidan Sunbury"><img src="https://avatars.githubusercontent.com/u/64103161?v=4" width="119" alt="Aidan Sunbury"/><br />Aidan Sunbury</a></td>
126
141
  <td align="center"><a href="https://github.com/soonoo?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="soonoo"><img src="https://avatars.githubusercontent.com/u/5436405?u=5d0b4aa955c87e30e6bda7f0cccae5402da99528&amp;v=4" width="119" alt="soonoo"/><br />soonoo</a></td>
127
142
  <td align="center"><a href="https://kevinporten.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kevin Porten"><img src="https://avatars.githubusercontent.com/u/1839345?u=dc2263d5cfe0d927ce1a0be04a1d55dd6b55405c&amp;v=4" width="119" alt="Kevin Porten"/><br />Kevin Porten</a></td>
128
143
  <td align="center"><a href="https://github.com/pumpkinlink?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Denis"><img src="https://avatars.githubusercontent.com/u/11864620?u=5f47bbe6c65d0f6f5cf011021490238e4b0593d0&amp;v=4" width="119" alt="Denis"/><br />Denis</a></td>
129
- <td align="center"><a href="https://github.com/christopher-kapic?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&amp;v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
130
144
  </tr>
131
145
  <tr>
146
+ <td align="center"><a href="https://github.com/christopher-kapic?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Christopher Kapic"><img src="https://avatars.githubusercontent.com/u/59740769?u=e7ad4b72b5bf6c9eb1644c26dbf3332a8f987377&amp;v=4" width="119" alt="Christopher Kapic"/><br />Christopher Kapic</a></td>
132
147
  <td align="center"><a href="http://ballingt.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Tom Ballinger"><img src="https://avatars.githubusercontent.com/u/458879?u=4b045ac75d721b6ac2b42a74d7d37f61f0414031&amp;v=4" width="119" alt="Tom Ballinger"/><br />Tom Ballinger</a></td>
133
148
  <td align="center"><a href="https://lee-sam.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Sam"><img src="https://avatars.githubusercontent.com/u/102863520?u=3c89611f549d5070be232eb4532f690c8f2e7a65&amp;v=4" width="119" alt="Sam"/><br />Sam</a></td>
134
149
  <td align="center"><a href="https://github.com/Titoine?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Titoine"><img src="https://avatars.githubusercontent.com/u/3514286?u=1bb1e86b0c99c8a1121372e56d51a177eea12191&amp;v=4" width="119" alt="Titoine"/><br />Titoine</a></td>
135
150
  <td align="center"><a href="https://rigtch.fm/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Igor Makowski"><img src="https://avatars.githubusercontent.com/u/56691628?u=ee8c879478f7c151b9156aef6c74243fa3e247a8&amp;v=4" width="119" alt="Igor Makowski"/><br />Igor Makowski</a></td>
136
151
  <td align="center"><a href="https://blog.cwang.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="hanayashiki"><img src="https://avatars.githubusercontent.com/u/26056783?u=06c3b9205a16fd41a871e82da1cc2a09306d53f5&amp;v=4" width="119" alt="hanayashiki"/><br />hanayashiki</a></td>
137
152
  <td align="center"><a href="https://dubinets.io/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Lev Dubinets"><img src="https://avatars.githubusercontent.com/u/3114081?u=f547f5d5012cab54851f1b1ad72d10e537f78fc2&amp;v=4" width="119" alt="Lev Dubinets"/><br />Lev Dubinets</a></td>
138
- <td align="center"><a href="https://bika.ai/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
139
153
  </tr>
140
154
  <tr>
155
+ <td align="center"><a href="https://kellychan.im/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&amp;v=4" width="119" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
141
156
  <td align="center"><a href="https://guyariely.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&amp;v=4" width="119" alt="Guy Ariely"/><br />Guy Ariely</a></td>
157
+ <td align="center"><a href="https://paulsenon.com/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&amp;v=4" width="119" alt="PaulSenon"/><br />PaulSenon</a></td>
142
158
  <td align="center"><a href="https://piscis.dev/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&amp;v=4" width="119" alt="Alex"/><br />Alex</a></td>
143
159
  <td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&amp;v=4" width="119" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
144
160
  </tr>
145
161
  </table>
146
162
 
147
- With thanks to [37 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get oRPC here.
163
+ With thanks to [36 past sponsors](https://htmlpreview.github.io/?https://github.com/middleapi/static/blob/main/sponsors.svg) who helped get oRPC here.
148
164
 
149
165
  ## References
150
166
 
@@ -1,12 +1,12 @@
1
1
  import { sortPlugins, intercept, resolveMaybeOptionalOptions } from '@orpc/shared';
2
2
  import { toStandardLazyRequest, sendStandardResponse } from '@standardserver/aws-lambda';
3
3
  import { r as resolveFriendlyStandardHandlerHandleOptions } from '../../shared/server.W91HSRkE.mjs';
4
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
4
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
5
5
  import '@orpc/client';
6
6
  import '@standardserver/core';
7
- import '../../shared/server.CkButhNT.mjs';
7
+ import '../../shared/server.3Ex_8ISY.mjs';
8
8
  import '@orpc/contract';
9
- import '../../shared/server.Dh77P3ii.mjs';
9
+ import '../../shared/server.S8BnCR3a.mjs';
10
10
 
11
11
  class CompositeAwsLambdaHandlerPlugin {
12
12
  name = "~composite/aws-lambda";
@@ -1,12 +1,12 @@
1
1
  import { resolveMaybeOptionalOptions } from '@orpc/shared';
2
2
  import { ServerPeer, encodePeerMessage, decodePeerMessage, isClientPeerSendMessage } from '@standardserver/peer';
3
3
  import { c as createStandardPeerRequestHandler } from '../../shared/server.CX4vUnDk.mjs';
4
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
4
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
5
5
  import '@orpc/client';
6
6
  import '@standardserver/core';
7
- import '../../shared/server.CkButhNT.mjs';
7
+ import '../../shared/server.3Ex_8ISY.mjs';
8
8
  import '@orpc/contract';
9
- import '../../shared/server.Dh77P3ii.mjs';
9
+ import '../../shared/server.S8BnCR3a.mjs';
10
10
 
11
11
  class experimental_CrosswsHandler {
12
12
  constructor(handler, options = {}) {
@@ -1,12 +1,12 @@
1
1
  import { sortPlugins, intercept, resolveMaybeOptionalOptions } from '@orpc/shared';
2
2
  import { toStandardLazyRequest, sendStandardResponse } from '@standardserver/fastify';
3
3
  import { r as resolveFriendlyStandardHandlerHandleOptions } from '../../shared/server.W91HSRkE.mjs';
4
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
4
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
5
5
  import '@orpc/client';
6
6
  import '@standardserver/core';
7
- import '../../shared/server.CkButhNT.mjs';
7
+ import '../../shared/server.3Ex_8ISY.mjs';
8
8
  import '@orpc/contract';
9
- import '../../shared/server.Dh77P3ii.mjs';
9
+ import '../../shared/server.S8BnCR3a.mjs';
10
10
 
11
11
  class CompositeFastifyHandlerPlugin {
12
12
  name = "~composite/fastify";
@@ -2,12 +2,12 @@ export { R as BodyLimitPlugin } from '../../shared/server.Cd4Z1hpV.mjs';
2
2
  import { sortPlugins, intercept, resolveMaybeOptionalOptions } from '@orpc/shared';
3
3
  import { toStandardLazyRequest, toFetchResponse } from '@standardserver/fetch';
4
4
  import { r as resolveFriendlyStandardHandlerHandleOptions } from '../../shared/server.W91HSRkE.mjs';
5
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
5
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
6
6
  import '@orpc/client';
7
7
  import '@standardserver/core';
8
- import '../../shared/server.CkButhNT.mjs';
8
+ import '../../shared/server.3Ex_8ISY.mjs';
9
9
  import '@orpc/contract';
10
- import '../../shared/server.Dh77P3ii.mjs';
10
+ import '../../shared/server.S8BnCR3a.mjs';
11
11
 
12
12
  class CompositeFetchHandlerPlugin {
13
13
  name = "~composite/fetch";
@@ -2,12 +2,12 @@ import { onMessagePortMessage, onMessagePortClose, postMessagePortMessage } from
2
2
  import { value, resolveMaybeOptionalOptions } from '@orpc/shared';
3
3
  import { ServerPeer, encodePeerMessage, decodePeerMessage, isClientPeerSendMessage, isPeerMessage } from '@standardserver/peer';
4
4
  import { c as createStandardPeerRequestHandler } from '../../shared/server.CX4vUnDk.mjs';
5
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
5
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
6
6
  import '@orpc/client';
7
7
  import '@standardserver/core';
8
- import '../../shared/server.CkButhNT.mjs';
8
+ import '../../shared/server.3Ex_8ISY.mjs';
9
9
  import '@orpc/contract';
10
- import '../../shared/server.Dh77P3ii.mjs';
10
+ import '../../shared/server.S8BnCR3a.mjs';
11
11
 
12
12
  class MessagePortHandler {
13
13
  constructor(handler, options = {}) {
@@ -2,13 +2,13 @@ export { R as BodyLimitPlugin } from '../../shared/server.Cd4Z1hpV.mjs';
2
2
  import { sortPlugins, intercept, resolveMaybeOptionalOptions } from '@orpc/shared';
3
3
  import { toStandardLazyRequest, sendStandardResponse } from '@standardserver/node';
4
4
  import { r as resolveFriendlyStandardHandlerHandleOptions } from '../../shared/server.W91HSRkE.mjs';
5
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
5
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
6
6
  import '@orpc/client';
7
7
  import '@standardserver/core';
8
8
  import '@standardserver/fetch';
9
- import '../../shared/server.CkButhNT.mjs';
9
+ import '../../shared/server.3Ex_8ISY.mjs';
10
10
  import '@orpc/contract';
11
- import '../../shared/server.Dh77P3ii.mjs';
11
+ import '../../shared/server.S8BnCR3a.mjs';
12
12
 
13
13
  class CompositeNodeHttpHandlerPlugin {
14
14
  name = "~composite/node-http";
@@ -1,8 +1,8 @@
1
- export { C as CompositeStandardHandlerPlugin, O as OtelHandlerPlugin, R as RPCHandlerCodec, a as RPCMatcher, b as RPC_DEFAULT_ALLOW_METHODS, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
1
+ export { C as CompositeStandardHandlerPlugin, O as OtelHandlerPlugin, R as RPCHandlerCodec, a as RPCMatcher, b as RPC_DEFAULT_ALLOW_METHODS, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
2
2
  export { r as resolveFriendlyStandardHandlerHandleOptions } from '../../shared/server.W91HSRkE.mjs';
3
3
  import '@orpc/client';
4
4
  import '@orpc/shared';
5
5
  import '@standardserver/core';
6
- import '../../shared/server.CkButhNT.mjs';
6
+ import '../../shared/server.3Ex_8ISY.mjs';
7
7
  import '@orpc/contract';
8
- import '../../shared/server.Dh77P3ii.mjs';
8
+ import '../../shared/server.S8BnCR3a.mjs';
@@ -1,12 +1,12 @@
1
1
  import { toStringOrBytes, resolveMaybeOptionalOptions, sequential, loadBytes } from '@orpc/shared';
2
2
  import { ServerPeer, encodePeerMessage, decodePeerMessage, isClientPeerSendMessage } from '@standardserver/peer';
3
3
  import { c as createStandardPeerRequestHandler } from '../../shared/server.CX4vUnDk.mjs';
4
- import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.DpUGXBi2.mjs';
4
+ import { R as RPCHandlerCodec, S as StandardHandler } from '../../shared/server.7G43pSxo.mjs';
5
5
  import '@orpc/client';
6
6
  import '@standardserver/core';
7
- import '../../shared/server.CkButhNT.mjs';
7
+ import '../../shared/server.3Ex_8ISY.mjs';
8
8
  import '@orpc/contract';
9
- import '../../shared/server.Dh77P3ii.mjs';
9
+ import '../../shared/server.S8BnCR3a.mjs';
10
10
 
11
11
  class WebSocketHandler {
12
12
  constructor(handler, options = {}) {
@@ -1,5 +1,5 @@
1
- import { c as createProcedureClient } from '../shared/server.CkButhNT.mjs';
2
- import { D as DecoratedProcedure } from '../shared/server.eCTV8Vpp.mjs';
1
+ import { c as createProcedureClient } from '../shared/server.3Ex_8ISY.mjs';
2
+ import { D as DecoratedProcedure } from '../shared/server.Cqk3swxs.mjs';
3
3
  import '@orpc/client';
4
4
  import '@orpc/contract';
5
5
  import '@orpc/shared';
package/dist/index.mjs CHANGED
@@ -2,11 +2,11 @@ import { mergeErrorMap, resolveMetaPlugins, getHiddenMetaPlugins, ProcedureContr
2
2
  export { ValidationError, asyncIteratorObject, defineMeta, error, eventIterator, reconcileORPCError, type } from '@orpc/contract';
3
3
  import { toArray, bindMethods, isTypescriptObject, resolveMaybeOptionalOptions } from '@orpc/shared';
4
4
  export { AsyncIteratorClass, asyncIteratorToStream, asyncIteratorToUnproxiedDataStream, asyncIteratorToStream as eventIteratorToStream, asyncIteratorToUnproxiedDataStream as eventIteratorToUnproxiedDataStream, onAsyncIteratorObjectError, onError, onFinish, onReadableStreamError, onStart, onSuccess, streamToAsyncIteratorObject, streamToAsyncIteratorObject as streamToEventIterator } from '@orpc/shared';
5
- import { L as Lazy, P as Procedure, c as createProcedureClient } from './shared/server.CkButhNT.mjs';
6
- export { u as unlazy } from './shared/server.CkButhNT.mjs';
7
- import { D as DecoratedProcedure } from './shared/server.eCTV8Vpp.mjs';
8
- import { b as augmentRouter, d as augmentImplementedRouter, e as withHiddenRouterContract, f as createGuardedProcedureLazy, g as getRouter } from './shared/server.Dh77P3ii.mjs';
9
- export { a as DEFAULT_ERROR_STATUS, D as DEFAULT_SUCCESS_STATUS, h as call, c as createContractProcedure, i as getHiddenRouterContract, u as unlazyRouter, j as walkProcedureContractsAsync, w as walkProcedureContractsSync } from './shared/server.Dh77P3ii.mjs';
5
+ import { L as Lazy, P as Procedure, c as createProcedureClient } from './shared/server.3Ex_8ISY.mjs';
6
+ export { u as unlazy } from './shared/server.3Ex_8ISY.mjs';
7
+ import { D as DecoratedProcedure } from './shared/server.Cqk3swxs.mjs';
8
+ import { b as augmentRouter, d as augmentImplementedRouter, e as withHiddenRouterContract, f as createGuardedProcedureLazy, g as getRouter } from './shared/server.S8BnCR3a.mjs';
9
+ export { a as DEFAULT_ERROR_STATUS, D as DEFAULT_SUCCESS_STATUS, h as call, c as createContractProcedure, i as getHiddenRouterContract, u as unlazyRouter, j as walkProcedureContractsAsync, w as walkProcedureContractsSync } from './shared/server.S8BnCR3a.mjs';
10
10
  import { RECURSIVE_CLIENT_UNWRAP_KEYS } from '@orpc/client';
11
11
  export { COMMON_ERROR_STATUS_MAP, ORPCError, RPCJsonSerializer, RPCSerializer, cloneORPCError, isDefinedError, isInferableError, safe, toORPCError } from '@orpc/client';
12
12
  export { ErrorEvent, getEventMeta, unwrapEvent, withEventMeta } from '@standardserver/core';
@@ -151,6 +151,8 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
151
151
  * secure as unsafe ones such as `POST`. It rejects `GET` requests arriving as top-level
152
152
  * navigations initiated cross-site or from outside the browser, the only context where
153
153
  * another site can make a browser attach `SameSite=Lax` cookies to a safe-method request.
154
+ * Requests matching no procedure stay unmatched, so they can fall through to whatever
155
+ * serves the rest of the site.
154
156
  *
155
157
  * @remarks
156
158
  * **Note**: Requests browsers send without `SameSite=Lax` cookies, such as cross-site `fetch`
@@ -162,8 +164,6 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
162
164
  */
163
165
  declare class GetMethodCsrfProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
164
166
  name: string;
165
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
166
- after: string[];
167
167
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
168
168
  private isAllowed;
169
169
  }
@@ -204,6 +204,30 @@ declare class MethodOverrideHandlerPlugin<T extends Context> implements Standard
204
204
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
205
205
  }
206
206
 
207
+ /**
208
+ * Rejects requests whose decoded input contains prototype-polluting keys: an own
209
+ * `__proto__` key, or an own `constructor` key holding a `prototype` key. oRPC's own
210
+ * decoding never assigns through the prototype chain, so this plugin exists to stop such
211
+ * keys from reaching application code that merges, clones, or path-sets input with a
212
+ * library vulnerable to prototype pollution. An `AsyncIteratorObject` input is checked
213
+ * value by value as it arrives, and a polluting value fails that iteration instead.
214
+ *
215
+ * @see {@link https://orpc.dev/docs/plugins/prototype-pollution-protection | Prototype Pollution Protection Plugin}
216
+ */
217
+ declare class PrototypePollutionProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
218
+ name: string;
219
+ init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
220
+ private rejectPollutingInput;
221
+ /**
222
+ * Walks the containers the built-in codecs can produce: arrays, maps, sets, and plain
223
+ * objects, including null-prototype ones. Other objects, such as files and dates, carry
224
+ * no attacker-authored keys and are left alone. The walk is iterative, so input nested
225
+ * deeper than the call stack allows still gets the intended verdict instead of a
226
+ * `RangeError`.
227
+ */
228
+ private containsPollutingKey;
229
+ }
230
+
207
231
  /**
208
232
  * Decompresses incoming request bodies based on the Content-Encoding header,
209
233
  * supporting gzip, deflate, and deflate-raw.
@@ -241,7 +265,7 @@ declare class RequestHeadersHandlerPlugin<T extends RequestHeadersHandlerPluginC
241
265
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
242
266
  }
243
267
 
244
- interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
268
+ interface ResponseCompressionHandlerPluginOptions<T extends Context> {
245
269
  /**
246
270
  * The compression schemes to use for response compression.
247
271
  * Schemes are prioritized by their order in this array and
@@ -258,6 +282,14 @@ interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
258
282
  * @default 1024 (1KB)
259
283
  */
260
284
  threshold?: number;
285
+ /**
286
+ * Determines whether a response with the given Content-Type should be compressed.
287
+ * Only consulted for binary transfers (streams, files, and file form-data parts).
288
+ * Also receives the routing interceptor options for per-request decisions.
289
+ *
290
+ * @default isCompressibleContentType (covers common text-based formats)
291
+ */
292
+ isCompressibleContentType?: (contentType: string | null | undefined, options: StandardHandlerRoutingInterceptorOptions<T>) => boolean;
261
293
  }
262
294
  /**
263
295
  * Compresses response bodies based on the client's Accept-Encoding header.
@@ -274,6 +306,7 @@ declare class ResponseCompressionHandlerPlugin<T extends Context> implements Sta
274
306
  after: string[];
275
307
  private readonly encodings;
276
308
  private readonly threshold;
309
+ private readonly isCompressibleContentType;
277
310
  constructor(options?: ResponseCompressionHandlerPluginOptions<T>);
278
311
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
279
312
  }
@@ -371,5 +404,5 @@ declare class TimeoutHandlerPlugin<T extends Context> implements StandardHandler
371
404
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
372
405
  }
373
406
 
374
- export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
407
+ export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, PrototypePollutionProtectionHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
375
408
  export type { BatchHandlerPluginOptions, CORSHandlerPluginOptions, MethodOverrideHandlerPluginOptions, RequestHeadersHandlerPluginContext, RequestHeadersHandlerPluginContext as RequestHeadersPluginContext, ResponseCompressionHandlerPluginOptions, ResponseHeadersHandlerPluginContext, ResponseHeadersHandlerPluginContext as ResponseHeadersPluginContext, RethrowHandlerPluginOptions, TimeoutHandlerPluginOptions };
@@ -151,6 +151,8 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
151
151
  * secure as unsafe ones such as `POST`. It rejects `GET` requests arriving as top-level
152
152
  * navigations initiated cross-site or from outside the browser, the only context where
153
153
  * another site can make a browser attach `SameSite=Lax` cookies to a safe-method request.
154
+ * Requests matching no procedure stay unmatched, so they can fall through to whatever
155
+ * serves the rest of the site.
154
156
  *
155
157
  * @remarks
156
158
  * **Note**: Requests browsers send without `SameSite=Lax` cookies, such as cross-site `fetch`
@@ -162,8 +164,6 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
162
164
  */
163
165
  declare class GetMethodCsrfProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
164
166
  name: string;
165
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
166
- after: string[];
167
167
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
168
168
  private isAllowed;
169
169
  }
@@ -204,6 +204,30 @@ declare class MethodOverrideHandlerPlugin<T extends Context> implements Standard
204
204
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
205
205
  }
206
206
 
207
+ /**
208
+ * Rejects requests whose decoded input contains prototype-polluting keys: an own
209
+ * `__proto__` key, or an own `constructor` key holding a `prototype` key. oRPC's own
210
+ * decoding never assigns through the prototype chain, so this plugin exists to stop such
211
+ * keys from reaching application code that merges, clones, or path-sets input with a
212
+ * library vulnerable to prototype pollution. An `AsyncIteratorObject` input is checked
213
+ * value by value as it arrives, and a polluting value fails that iteration instead.
214
+ *
215
+ * @see {@link https://orpc.dev/docs/plugins/prototype-pollution-protection | Prototype Pollution Protection Plugin}
216
+ */
217
+ declare class PrototypePollutionProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
218
+ name: string;
219
+ init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
220
+ private rejectPollutingInput;
221
+ /**
222
+ * Walks the containers the built-in codecs can produce: arrays, maps, sets, and plain
223
+ * objects, including null-prototype ones. Other objects, such as files and dates, carry
224
+ * no attacker-authored keys and are left alone. The walk is iterative, so input nested
225
+ * deeper than the call stack allows still gets the intended verdict instead of a
226
+ * `RangeError`.
227
+ */
228
+ private containsPollutingKey;
229
+ }
230
+
207
231
  /**
208
232
  * Decompresses incoming request bodies based on the Content-Encoding header,
209
233
  * supporting gzip, deflate, and deflate-raw.
@@ -241,7 +265,7 @@ declare class RequestHeadersHandlerPlugin<T extends RequestHeadersHandlerPluginC
241
265
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
242
266
  }
243
267
 
244
- interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
268
+ interface ResponseCompressionHandlerPluginOptions<T extends Context> {
245
269
  /**
246
270
  * The compression schemes to use for response compression.
247
271
  * Schemes are prioritized by their order in this array and
@@ -258,6 +282,14 @@ interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
258
282
  * @default 1024 (1KB)
259
283
  */
260
284
  threshold?: number;
285
+ /**
286
+ * Determines whether a response with the given Content-Type should be compressed.
287
+ * Only consulted for binary transfers (streams, files, and file form-data parts).
288
+ * Also receives the routing interceptor options for per-request decisions.
289
+ *
290
+ * @default isCompressibleContentType (covers common text-based formats)
291
+ */
292
+ isCompressibleContentType?: (contentType: string | null | undefined, options: StandardHandlerRoutingInterceptorOptions<T>) => boolean;
261
293
  }
262
294
  /**
263
295
  * Compresses response bodies based on the client's Accept-Encoding header.
@@ -274,6 +306,7 @@ declare class ResponseCompressionHandlerPlugin<T extends Context> implements Sta
274
306
  after: string[];
275
307
  private readonly encodings;
276
308
  private readonly threshold;
309
+ private readonly isCompressibleContentType;
277
310
  constructor(options?: ResponseCompressionHandlerPluginOptions<T>);
278
311
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
279
312
  }
@@ -371,5 +404,5 @@ declare class TimeoutHandlerPlugin<T extends Context> implements StandardHandler
371
404
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
372
405
  }
373
406
 
374
- export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
407
+ export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, PrototypePollutionProtectionHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
375
408
  export type { BatchHandlerPluginOptions, CORSHandlerPluginOptions, MethodOverrideHandlerPluginOptions, RequestHeadersHandlerPluginContext, RequestHeadersHandlerPluginContext as RequestHeadersPluginContext, ResponseCompressionHandlerPluginOptions, ResponseHeadersHandlerPluginContext, ResponseHeadersHandlerPluginContext as ResponseHeadersPluginContext, RethrowHandlerPluginOptions, TimeoutHandlerPluginOptions };
@@ -1,9 +1,9 @@
1
- import { toArray, value, isNoTransformCacheControl, parseAcceptEncodingQualities, isCompressibleContentType, varyByAcceptEncoding, isAsyncIteratorObject, stringifyJSON, anyAbortSignal, override, wrapAsyncIterator, wrapReadableStream, AbortError } from '@orpc/shared';
1
+ import { toArray, value, isPlainObject, isTypescriptObject, isAsyncIteratorObject, override, wrapAsyncIterator, isCompressibleContentType, isNoTransformCacheControl, parseAcceptEncodingQualities, varyByAcceptEncoding, stringifyJSON, anyAbortSignal, wrapReadableStream, AbortError } from '@orpc/shared';
2
2
  import { flattenStandardHeader, parseStandardUrl, generateContentDisposition, mergeStandardHeaders } from '@standardserver/core';
3
3
  import { isClientPeerSendMessage, ServerPeer, encodePeerMessage } from '@standardserver/peer';
4
+ import { ORPCError } from '@orpc/client';
4
5
  import { toFetchHeaders, toStandardBody, toStandardHeaders } from '@standardserver/fetch';
5
6
  export { R as RequestLimitHandlerPlugin } from '../shared/server.Cd4Z1hpV.mjs';
6
- import '@orpc/client';
7
7
 
8
8
  const BATCH_CONTENT_TYPE = "application/vnd.orpc.batch";
9
9
  class BatchHandlerPlugin {
@@ -299,21 +299,16 @@ class CORSHandlerPlugin {
299
299
 
300
300
  class GetMethodCsrfProtectionHandlerPlugin {
301
301
  name = "~get-method-csrf-protection";
302
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
303
- after = ["~batch"];
304
302
  init(options) {
305
- const routingInterceptor = (interceptorOptions) => {
303
+ const interceptor = (interceptorOptions) => {
306
304
  if (this.isAllowed(interceptorOptions)) {
307
305
  return interceptorOptions.next();
308
306
  }
309
- return Promise.resolve({
310
- matched: true,
311
- response: { status: 403, headers: {}, body: "Request blocked by CSRF protection." }
312
- });
307
+ throw new ORPCError("FORBIDDEN", { message: "Request blocked by CSRF protection." });
313
308
  };
314
309
  return {
315
310
  ...options,
316
- routingInterceptors: [routingInterceptor, ...toArray(options.routingInterceptors)]
311
+ interceptors: [interceptor, ...toArray(options.interceptors)]
317
312
  };
318
313
  }
319
314
  isAllowed({ request }) {
@@ -375,6 +370,78 @@ class MethodOverrideHandlerPlugin {
375
370
  }
376
371
  }
377
372
 
373
+ class PrototypePollutionProtectionHandlerPlugin {
374
+ name = "~prototype-pollution-protection";
375
+ init(options) {
376
+ const interceptor = (interceptorOptions) => {
377
+ const input = interceptorOptions.input;
378
+ if (isAsyncIteratorObject(input)) {
379
+ const guardedInput = override(input, wrapAsyncIterator(input, {
380
+ mapResult: (result) => {
381
+ this.rejectPollutingInput(result.value);
382
+ return result;
383
+ }
384
+ }));
385
+ return interceptorOptions.next({ ...interceptorOptions, input: guardedInput });
386
+ }
387
+ this.rejectPollutingInput(input);
388
+ return interceptorOptions.next();
389
+ };
390
+ return {
391
+ ...options,
392
+ clientInterceptors: [interceptor, ...toArray(options.clientInterceptors)]
393
+ };
394
+ }
395
+ rejectPollutingInput(input) {
396
+ if (this.containsPollutingKey(input)) {
397
+ throw new ORPCError("BAD_REQUEST", { message: "Request blocked by prototype pollution protection." });
398
+ }
399
+ }
400
+ /**
401
+ * Walks the containers the built-in codecs can produce: arrays, maps, sets, and plain
402
+ * objects, including null-prototype ones. Other objects, such as files and dates, carry
403
+ * no attacker-authored keys and are left alone. The walk is iterative, so input nested
404
+ * deeper than the call stack allows still gets the intended verdict instead of a
405
+ * `RangeError`.
406
+ */
407
+ containsPollutingKey(root) {
408
+ const visited = /* @__PURE__ */ new WeakSet();
409
+ const stack = [root];
410
+ while (stack.length !== 0) {
411
+ const value = stack.pop();
412
+ if (typeof value !== "object" || value === null || visited.has(value)) {
413
+ continue;
414
+ }
415
+ visited.add(value);
416
+ if (Array.isArray(value)) {
417
+ for (const item of value) {
418
+ stack.push(item);
419
+ }
420
+ continue;
421
+ }
422
+ if (value instanceof Map || value instanceof Set) {
423
+ for (const entry of value) {
424
+ stack.push(entry);
425
+ }
426
+ continue;
427
+ }
428
+ if (!isPlainObject(value)) {
429
+ continue;
430
+ }
431
+ if (Object.hasOwn(value, "__proto__")) {
432
+ return true;
433
+ }
434
+ if (Object.hasOwn(value, "constructor") && isTypescriptObject(value.constructor) && Object.hasOwn(value.constructor, "prototype")) {
435
+ return true;
436
+ }
437
+ for (const key of Object.keys(value)) {
438
+ stack.push(value[key]);
439
+ }
440
+ }
441
+ return false;
442
+ }
443
+ }
444
+
378
445
  class RequestCompressionHandlerPlugin {
379
446
  name = "~request-compression";
380
447
  /**
@@ -470,9 +537,11 @@ class ResponseCompressionHandlerPlugin {
470
537
  after = ["~batch", "~response-headers"];
471
538
  encodings;
472
539
  threshold;
540
+ isCompressibleContentType;
473
541
  constructor(options = {}) {
474
542
  this.encodings = options.encodings ?? ["gzip", "deflate"];
475
543
  this.threshold = options.threshold ?? 1024;
544
+ this.isCompressibleContentType = options.isCompressibleContentType ?? isCompressibleContentType;
476
545
  }
477
546
  init(options) {
478
547
  const routingInterceptor = async ({ next, ...interceptorOptions }) => {
@@ -502,7 +571,7 @@ class ResponseCompressionHandlerPlugin {
502
571
  const headers = response.headers;
503
572
  if (body instanceof ReadableStream) {
504
573
  const contentLength = Number(flattenStandardHeader(headers["content-length"]));
505
- if ((!Number.isFinite(contentLength) || contentLength >= this.threshold) && isCompressibleContentType(flattenStandardHeader(headers["content-type"]))) {
574
+ if ((!Number.isFinite(contentLength) || contentLength >= this.threshold) && this.isCompressibleContentType(flattenStandardHeader(headers["content-type"]), interceptorOptions)) {
506
575
  return {
507
576
  ...result,
508
577
  response: {
@@ -519,7 +588,7 @@ class ResponseCompressionHandlerPlugin {
519
588
  };
520
589
  }
521
590
  } else if (body instanceof Blob) {
522
- if ((!Number.isFinite(body.size) || body.size >= this.threshold) && isCompressibleContentType(body.type)) {
591
+ if ((!Number.isFinite(body.size) || body.size >= this.threshold) && this.isCompressibleContentType(body.type, interceptorOptions)) {
523
592
  const contentDisposition = headers["content-disposition"] ?? generateContentDisposition(
524
593
  body instanceof File ? body.name : "blob"
525
594
  );
@@ -547,13 +616,13 @@ class ResponseCompressionHandlerPlugin {
547
616
  contentLength += PART_OVERHEAD + key.length;
548
617
  if (value instanceof Blob) {
549
618
  if (!Number.isFinite(value.size)) {
550
- if (!isCompressibleContentType(value.type)) {
619
+ if (!this.isCompressibleContentType(value.type, interceptorOptions)) {
551
620
  contentLength = -Infinity;
552
621
  break;
553
622
  }
554
623
  contentLength = Infinity;
555
624
  } else {
556
- contentLength += isCompressibleContentType(value.type) ? value.size : -value.size;
625
+ contentLength += this.isCompressibleContentType(value.type, interceptorOptions) ? value.size : -value.size;
557
626
  }
558
627
  } else {
559
628
  contentLength += value.length * AVG_BYTES_PER_CHAR;
@@ -766,4 +835,4 @@ class TimeoutHandlerPlugin {
766
835
  }
767
836
  }
768
837
 
769
- export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
838
+ export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, PrototypePollutionProtectionHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin };
@@ -123,6 +123,7 @@ async function executeProcedureInternal(procedure, options) {
123
123
  const orderedMiddlewares = procedure["~orpc"].orderedMiddlewares;
124
124
  const next = async (midIndex, context, input) => {
125
125
  let currentInput = input;
126
+ let middlewareInput = input;
126
127
  const startInputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].inputSchemasLengthAtUse ?? 0;
127
128
  const endInputIndex = midIndex === orderedMiddlewares.length ? inputSchemas.length : orderedMiddlewares[midIndex].inputSchemasLengthAtUse ?? 0;
128
129
  if (!procedure["~orpc"].disableInputValidation) {
@@ -134,6 +135,7 @@ async function executeProcedureInternal(procedure, options) {
134
135
  );
135
136
  currentInput = i !== 0 ? mergeTwoLevels(currentInput, validated) : validated;
136
137
  }
138
+ middlewareInput = endInputIndex > 0 && endInputIndex < inputSchemas.length ? mergeTwoLevels(options.input, currentInput) : currentInput;
137
139
  }
138
140
  let currentOutput;
139
141
  let currentContext = context;
@@ -156,7 +158,7 @@ async function executeProcedureInternal(procedure, options) {
156
158
  },
157
159
  lastEventId: options.lastEventId
158
160
  },
159
- currentInput,
161
+ middlewareInput,
160
162
  middlewareDone
161
163
  );
162
164
  });
@@ -1,8 +1,8 @@
1
1
  import { ORPCError, toORPCError, RPCSerializer, COMMON_ERROR_STATUS_MAP } from '@orpc/client';
2
2
  import { sortPlugins, getOpenTelemetryConfig, runWithSpan, toArray, matchesHttpPathPrefix, intercept, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, recordSpanError, pathToHttpPath, normalizeHttpPath, value, parseEmptyableJSON, getOwn } from '@orpc/shared';
3
3
  import { flattenStandardHeader, parseStandardUrl } from '@standardserver/core';
4
- import { c as createProcedureClient, u as unlazy, P as Procedure } from './server.CkButhNT.mjs';
5
- import { w as walkProcedureContractsSync, g as getRouter, c as createContractProcedure, D as DEFAULT_SUCCESS_STATUS, a as DEFAULT_ERROR_STATUS } from './server.Dh77P3ii.mjs';
4
+ import { c as createProcedureClient, u as unlazy, P as Procedure } from './server.3Ex_8ISY.mjs';
5
+ import { w as walkProcedureContractsSync, g as getRouter, c as createContractProcedure, D as DEFAULT_SUCCESS_STATUS, a as DEFAULT_ERROR_STATUS } from './server.S8BnCR3a.mjs';
6
6
 
7
7
  class CompositeStandardHandlerPlugin {
8
8
  name = "~composite";
@@ -1,5 +1,5 @@
1
1
  import { resolveMetaPlugins, mergeErrorMap, getHiddenMetaPlugins } from '@orpc/contract';
2
- import { P as Procedure } from './server.CkButhNT.mjs';
2
+ import { P as Procedure } from './server.3Ex_8ISY.mjs';
3
3
 
4
4
  class DecoratedProcedure extends Procedure {
5
5
  meta(...plugins) {
@@ -1,4 +1,4 @@
1
- import { c as createProcedureClient, P as Procedure, L as Lazy, u as unlazy } from './server.CkButhNT.mjs';
1
+ import { c as createProcedureClient, P as Procedure, L as Lazy, u as unlazy } from './server.3Ex_8ISY.mjs';
2
2
  import { resolveMetaPlugins, mergeErrorMap, ProcedureContract } from '@orpc/contract';
3
3
  import { omit, isTypescriptObject } from '@orpc/shared';
4
4
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/server",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.31",
4
+ "version": "2.0.0-beta.33",
5
5
  "description": "Build typesafe APIs with oRPC: RPC and OpenAPI support, middleware, and adapters for Node.js, Bun, Deno, Fetch, Fastify, WebSocket, AWS Lambda, and more",
6
6
  "license": "MIT",
7
7
  "funding": [
@@ -117,25 +117,24 @@
117
117
  }
118
118
  },
119
119
  "dependencies": {
120
- "@standardserver/aws-lambda": "^0.8.0",
121
- "@standardserver/core": "^0.8.0",
122
- "@standardserver/fastify": "^0.8.0",
123
- "@standardserver/fetch": "^0.8.0",
124
- "@standardserver/node": "^0.8.0",
125
- "@standardserver/peer": "^0.8.0",
126
- "cookie": "^2.0.1",
127
- "@orpc/contract": "2.0.0-beta.31",
128
- "@orpc/client": "2.0.0-beta.31",
129
- "@orpc/shared": "2.0.0-beta.31"
120
+ "@orpc/client": "2.0.0-beta.33",
121
+ "@orpc/contract": "2.0.0-beta.33",
122
+ "@orpc/shared": "2.0.0-beta.33",
123
+ "@standardserver/aws-lambda": "^0.8.3",
124
+ "@standardserver/core": "^0.8.3",
125
+ "@standardserver/fastify": "^0.8.3",
126
+ "@standardserver/fetch": "^0.8.3",
127
+ "@standardserver/node": "^0.8.3",
128
+ "@standardserver/peer": "^0.8.3",
129
+ "cookie": "^2.0.1"
130
130
  },
131
131
  "devDependencies": {
132
132
  "crossws": "^0.4.6",
133
133
  "fastify": "^5.12.1",
134
134
  "supertest": "^7.2.2",
135
- "zod": "^4.4.3"
135
+ "zod": "^4.5.4"
136
136
  },
137
137
  "scripts": {
138
- "build": "unbuild",
139
138
  "type:check": "tsc -b"
140
139
  }
141
140
  }