@orpc/server 2.0.0-beta.30 → 2.0.0-beta.32

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,44 @@ 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
+ - [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Define API contract as the single source of truth.
33
+ - [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build APIs or implement contracts.
34
+ - [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume APIs with end-to-end type safety.
35
+ - [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Add OpenAPI compatibility to APIs.
36
36
 
37
37
  **Schema validation**
38
38
 
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/).
39
+ - [@orpc/zod](https://www.npmjs.com/package/@orpc/zod): Integrate with [Zod](https://zod.dev/).
40
+ - [@orpc/valibot](https://www.npmjs.com/package/@orpc/valibot): Integrate with [Valibot](https://valibot.dev/).
41
+ - [@orpc/arktype](https://www.npmjs.com/package/@orpc/arktype): Integrate with [ArkType](https://arktype.io/).
42
42
 
43
43
  **Built-in features**
44
44
 
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.
45
+ - [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher): Pub/Sub with memory, Redis, and Upstash adapters.
46
+ - [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit): Rate limiting with memory, Redis, and Upstash adapters.
47
+ - [@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).
48
+ - [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema): Smart coercion for OpenAPI requests.
49
49
 
50
50
  **Framework & ecosystem integrations**
51
51
 
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.
52
+ - [@orpc/next](https://www.npmjs.com/package/@orpc/next): Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data).
53
+ - [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk): Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools.
54
+ - [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query): Integrate with [TanStack Query](https://tanstack.com/query/latest).
55
+ - [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada): Integrate with [Pinia Colada](https://pinia-colada.esm.dev/).
56
+ - [@orpc/swr](https://www.npmjs.com/package/@orpc/swr): Integrate with [SWR](https://swr.vercel.app/).
57
+ - [@orpc/experimental-msw](https://www.npmjs.com/package/@orpc/experimental-msw): Mock procedures with [Mock Service Worker](https://mswjs.io/).
58
+ - [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect): Integrate with [Effect](https://effect.website/).
59
+ - [@orpc/nest](https://www.npmjs.com/package/@orpc/nest): Implement your contract with [NestJS](https://nestjs.com/).
60
+ - [@orpc/node](https://www.npmjs.com/package/@orpc/node): [Node.js](https://nodejs.org/) plugins for static file serving and large uploads.
61
+ - [@orpc/bun](https://www.npmjs.com/package/@orpc/bun): Adapters for [Bun's Redis](https://bun.sh/).
62
+ - [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare): Adapters for [Cloudflare's RateLimit and Durable Objects](https://developers.cloudflare.com/workers/).
63
+ - [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc): Reuse existing [tRPC](https://trpc.io/) routers within oRPC.
64
64
 
65
65
  **Observability**
66
66
 
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.
67
+ - [@orpc/opentelemetry](https://www.npmjs.com/package/@orpc/opentelemetry): Integrate with [OpenTelemetry](https://opentelemetry.io/) for distributed tracing.
68
+ - [@orpc/pino](https://www.npmjs.com/package/@orpc/pino): Integrate with [Pino](https://getpino.io/) for logging.
69
+ - [@orpc/evlog](https://www.npmjs.com/package/@orpc/evlog): Integrate with [Evlog](https://evlog.dev/) for logging.
70
70
 
71
71
  ## Sponsors
72
72
 
@@ -113,6 +113,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
113
113
  <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
114
  <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
115
  <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>
116
+ <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
117
  </tr>
117
118
  </table>
118
119
 
@@ -135,7 +136,7 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
135
136
  <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
137
  <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
138
  <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
+ <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>
139
140
  </tr>
140
141
  <tr>
141
142
  <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>
@@ -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.D9VprDph.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.D9VprDph.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.D9VprDph.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.D9VprDph.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.D9VprDph.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.D9VprDph.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.D9VprDph.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.D9VprDph.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.d.mts CHANGED
@@ -314,7 +314,7 @@ declare class Builder<TInitialContext extends Context, TErrorMap extends ErrorMa
314
314
  * Overrides the procedure configuration, such as disabling runtime
315
315
  * input/output validation.
316
316
  *
317
- * @see {@link https://orpc.dev/docs/advanced/validation-customization | Validation Customization}
317
+ * @see {@link https://orpc.dev/docs/recipes/validation-customization | Validation Customization}
318
318
  */
319
319
  $config(config: ProcedureConfig): Builder<TInitialContext, TErrorMap>;
320
320
  /**
package/dist/index.d.ts CHANGED
@@ -314,7 +314,7 @@ declare class Builder<TInitialContext extends Context, TErrorMap extends ErrorMa
314
314
  * Overrides the procedure configuration, such as disabling runtime
315
315
  * input/output validation.
316
316
  *
317
- * @see {@link https://orpc.dev/docs/advanced/validation-customization | Validation Customization}
317
+ * @see {@link https://orpc.dev/docs/recipes/validation-customization | Validation Customization}
318
318
  */
319
319
  $config(config: ProcedureConfig): Builder<TInitialContext, TErrorMap>;
320
320
  /**
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';
@@ -119,7 +119,7 @@ class Builder {
119
119
  * Overrides the procedure configuration, such as disabling runtime
120
120
  * input/output validation.
121
121
  *
122
- * @see {@link https://orpc.dev/docs/advanced/validation-customization | Validation Customization}
122
+ * @see {@link https://orpc.dev/docs/recipes/validation-customization | Validation Customization}
123
123
  */
124
124
  $config(config) {
125
125
  return new Builder({
@@ -24,7 +24,8 @@ interface BatchHandlerPluginOptions<T extends Context> {
24
24
  /**
25
25
  * Map each subrequest in the batch before it is processed.
26
26
  *
27
- * @default merges the batch request headers into the subrequest and remove `orpc-batch` header to prevent nested batching
27
+ * @default merges the batch request headers into the subrequest, giving them priority over
28
+ * the subrequest headers, and removes the `orpc-batch` header to prevent nested batching
28
29
  */
29
30
  mapSubrequest?: (subrequest: StandardLazyRequest, batchOptions: StandardHandlerRoutingInterceptorOptions<T>) => StandardLazyRequest;
30
31
  /**
@@ -92,18 +93,16 @@ declare class BatchHandlerPlugin<T extends Context> implements StandardHandlerPl
92
93
  interface CORSHandlerPluginOptions<T extends Context> {
93
94
  /**
94
95
  * Configures the `Access-Control-Allow-Origin` header.
95
- * Can be a string, an array of allowed origins, or a function that returns the allowed origin(s).
96
+ * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
96
97
  *
97
- * @default (origin) => origin
98
+ * @default '*'
98
99
  */
99
- origin?: Value<string | readonly string[] | null | undefined, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
100
+ origin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
100
101
  /**
101
102
  * Configures the `Timing-Allow-Origin` header.
102
- * Can be a string, an array of allowed origins, or a function that returns the allowed origin(s).
103
- *
104
- * @default undefined
103
+ * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
105
104
  */
106
- timingOrigin?: Value<string | readonly string[] | null | undefined, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
105
+ timingOrigin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
107
106
  /**
108
107
  * Configures the `Access-Control-Allow-Methods` header for preflight requests.
109
108
  *
@@ -113,26 +112,18 @@ interface CORSHandlerPluginOptions<T extends Context> {
113
112
  /**
114
113
  * Configures the `Access-Control-Allow-Headers` header for preflight requests.
115
114
  * Falls back to the request's `Access-Control-Request-Headers` if not set.
116
- *
117
- * @default undefined
118
115
  */
119
116
  allowHeaders?: readonly string[];
120
117
  /**
121
118
  * Configures the `Access-Control-Max-Age` header (in seconds) for preflight requests.
122
- *
123
- * @default undefined
124
119
  */
125
120
  maxAge?: number;
126
121
  /**
127
122
  * Configures the `Access-Control-Allow-Credentials` header.
128
- *
129
- * @default undefined
130
123
  */
131
124
  credentials?: boolean;
132
125
  /**
133
126
  * Configures the `Access-Control-Expose-Headers` header.
134
- *
135
- * @default undefined
136
127
  */
137
128
  exposeHeaders?: readonly string[];
138
129
  }
@@ -160,6 +151,8 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
160
151
  * secure as unsafe ones such as `POST`. It rejects `GET` requests arriving as top-level
161
152
  * navigations initiated cross-site or from outside the browser, the only context where
162
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.
163
156
  *
164
157
  * @remarks
165
158
  * **Note**: Requests browsers send without `SameSite=Lax` cookies, such as cross-site `fetch`
@@ -171,8 +164,6 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
171
164
  */
172
165
  declare class GetMethodCsrfProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
173
166
  name: string;
174
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
175
- after: string[];
176
167
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
177
168
  private isAllowed;
178
169
  }
@@ -213,6 +204,30 @@ declare class MethodOverrideHandlerPlugin<T extends Context> implements Standard
213
204
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
214
205
  }
215
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
+
216
231
  /**
217
232
  * Decompresses incoming request bodies based on the Content-Encoding header,
218
233
  * supporting gzip, deflate, and deflate-raw.
@@ -250,7 +265,7 @@ declare class RequestHeadersHandlerPlugin<T extends RequestHeadersHandlerPluginC
250
265
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
251
266
  }
252
267
 
253
- interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
268
+ interface ResponseCompressionHandlerPluginOptions<T extends Context> {
254
269
  /**
255
270
  * The compression schemes to use for response compression.
256
271
  * Schemes are prioritized by their order in this array and
@@ -267,6 +282,14 @@ interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
267
282
  * @default 1024 (1KB)
268
283
  */
269
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;
270
293
  }
271
294
  /**
272
295
  * Compresses response bodies based on the client's Accept-Encoding header.
@@ -283,6 +306,7 @@ declare class ResponseCompressionHandlerPlugin<T extends Context> implements Sta
283
306
  after: string[];
284
307
  private readonly encodings;
285
308
  private readonly threshold;
309
+ private readonly isCompressibleContentType;
286
310
  constructor(options?: ResponseCompressionHandlerPluginOptions<T>);
287
311
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
288
312
  }
@@ -380,5 +404,5 @@ declare class TimeoutHandlerPlugin<T extends Context> implements StandardHandler
380
404
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
381
405
  }
382
406
 
383
- 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 };
384
408
  export type { BatchHandlerPluginOptions, CORSHandlerPluginOptions, MethodOverrideHandlerPluginOptions, RequestHeadersHandlerPluginContext, RequestHeadersHandlerPluginContext as RequestHeadersPluginContext, ResponseCompressionHandlerPluginOptions, ResponseHeadersHandlerPluginContext, ResponseHeadersHandlerPluginContext as ResponseHeadersPluginContext, RethrowHandlerPluginOptions, TimeoutHandlerPluginOptions };
@@ -24,7 +24,8 @@ interface BatchHandlerPluginOptions<T extends Context> {
24
24
  /**
25
25
  * Map each subrequest in the batch before it is processed.
26
26
  *
27
- * @default merges the batch request headers into the subrequest and remove `orpc-batch` header to prevent nested batching
27
+ * @default merges the batch request headers into the subrequest, giving them priority over
28
+ * the subrequest headers, and removes the `orpc-batch` header to prevent nested batching
28
29
  */
29
30
  mapSubrequest?: (subrequest: StandardLazyRequest, batchOptions: StandardHandlerRoutingInterceptorOptions<T>) => StandardLazyRequest;
30
31
  /**
@@ -92,18 +93,16 @@ declare class BatchHandlerPlugin<T extends Context> implements StandardHandlerPl
92
93
  interface CORSHandlerPluginOptions<T extends Context> {
93
94
  /**
94
95
  * Configures the `Access-Control-Allow-Origin` header.
95
- * Can be a string, an array of allowed origins, or a function that returns the allowed origin(s).
96
+ * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
96
97
  *
97
- * @default (origin) => origin
98
+ * @default '*'
98
99
  */
99
- origin?: Value<string | readonly string[] | null | undefined, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
100
+ origin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
100
101
  /**
101
102
  * Configures the `Timing-Allow-Origin` header.
102
- * Can be a string, an array of allowed origins, or a function that returns the allowed origin(s).
103
- *
104
- * @default undefined
103
+ * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
105
104
  */
106
- timingOrigin?: Value<string | readonly string[] | null | undefined, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
105
+ timingOrigin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string | undefined, options: StandardHandlerRoutingInterceptorOptions<T>]>;
107
106
  /**
108
107
  * Configures the `Access-Control-Allow-Methods` header for preflight requests.
109
108
  *
@@ -113,26 +112,18 @@ interface CORSHandlerPluginOptions<T extends Context> {
113
112
  /**
114
113
  * Configures the `Access-Control-Allow-Headers` header for preflight requests.
115
114
  * Falls back to the request's `Access-Control-Request-Headers` if not set.
116
- *
117
- * @default undefined
118
115
  */
119
116
  allowHeaders?: readonly string[];
120
117
  /**
121
118
  * Configures the `Access-Control-Max-Age` header (in seconds) for preflight requests.
122
- *
123
- * @default undefined
124
119
  */
125
120
  maxAge?: number;
126
121
  /**
127
122
  * Configures the `Access-Control-Allow-Credentials` header.
128
- *
129
- * @default undefined
130
123
  */
131
124
  credentials?: boolean;
132
125
  /**
133
126
  * Configures the `Access-Control-Expose-Headers` header.
134
- *
135
- * @default undefined
136
127
  */
137
128
  exposeHeaders?: readonly string[];
138
129
  }
@@ -160,6 +151,8 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
160
151
  * secure as unsafe ones such as `POST`. It rejects `GET` requests arriving as top-level
161
152
  * navigations initiated cross-site or from outside the browser, the only context where
162
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.
163
156
  *
164
157
  * @remarks
165
158
  * **Note**: Requests browsers send without `SameSite=Lax` cookies, such as cross-site `fetch`
@@ -171,8 +164,6 @@ declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlu
171
164
  */
172
165
  declare class GetMethodCsrfProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
173
166
  name: string;
174
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
175
- after: string[];
176
167
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
177
168
  private isAllowed;
178
169
  }
@@ -213,6 +204,30 @@ declare class MethodOverrideHandlerPlugin<T extends Context> implements Standard
213
204
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
214
205
  }
215
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
+
216
231
  /**
217
232
  * Decompresses incoming request bodies based on the Content-Encoding header,
218
233
  * supporting gzip, deflate, and deflate-raw.
@@ -250,7 +265,7 @@ declare class RequestHeadersHandlerPlugin<T extends RequestHeadersHandlerPluginC
250
265
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
251
266
  }
252
267
 
253
- interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
268
+ interface ResponseCompressionHandlerPluginOptions<T extends Context> {
254
269
  /**
255
270
  * The compression schemes to use for response compression.
256
271
  * Schemes are prioritized by their order in this array and
@@ -267,6 +282,14 @@ interface ResponseCompressionHandlerPluginOptions<_T extends Context> {
267
282
  * @default 1024 (1KB)
268
283
  */
269
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;
270
293
  }
271
294
  /**
272
295
  * Compresses response bodies based on the client's Accept-Encoding header.
@@ -283,6 +306,7 @@ declare class ResponseCompressionHandlerPlugin<T extends Context> implements Sta
283
306
  after: string[];
284
307
  private readonly encodings;
285
308
  private readonly threshold;
309
+ private readonly isCompressibleContentType;
286
310
  constructor(options?: ResponseCompressionHandlerPluginOptions<T>);
287
311
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
288
312
  }
@@ -380,5 +404,5 @@ declare class TimeoutHandlerPlugin<T extends Context> implements StandardHandler
380
404
  init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
381
405
  }
382
406
 
383
- 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 };
384
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 {
@@ -24,8 +24,13 @@ class BatchHandlerPlugin {
24
24
  this.mapSubrequest = options.mapSubrequest ?? ((subRequest, { request: batchRequest }) => ({
25
25
  ...subRequest,
26
26
  headers: {
27
- ...batchRequest.headers,
28
27
  ...subRequest.headers,
28
+ /**
29
+ * The batch request headers win over the subrequest ones. They are the only ones the
30
+ * transport actually saw, so headers the browser injects on its own, such as `cookie`
31
+ * or `origin`, cannot be overridden by a subrequest, which is just request payload.
32
+ */
33
+ ...batchRequest.headers,
29
34
  "orpc-batch": void 0
30
35
  // useful in case batch plugin is used multiple times
31
36
  }
@@ -215,7 +220,7 @@ class CORSHandlerPlugin {
215
220
  after = ["~opentelemetry", "~batch"];
216
221
  constructor(options = {}) {
217
222
  const defaults = {
218
- origin: (origin) => origin,
223
+ origin: "*",
219
224
  allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH", "QUERY"]
220
225
  };
221
226
  this.options = {
@@ -231,7 +236,7 @@ class CORSHandlerPlugin {
231
236
  }
232
237
  const resHeaders = { ...result.response.headers };
233
238
  const origin = flattenStandardHeader(interceptorOptions.request.headers.origin);
234
- const allowedOrigins = toArray(value(this.options.origin, origin, interceptorOptions));
239
+ const allowedOrigins = toArray(await value(this.options.origin, origin, interceptorOptions));
235
240
  if (allowedOrigins.includes("*")) {
236
241
  resHeaders["access-control-allow-origin"] = "*";
237
242
  } else {
@@ -243,7 +248,7 @@ class CORSHandlerPlugin {
243
248
  resHeaders.vary = existingVary ? `${existingVary}, Origin` : "Origin";
244
249
  }
245
250
  }
246
- const allowedTimingOrigins = toArray(value(this.options.timingOrigin, origin, interceptorOptions));
251
+ const allowedTimingOrigins = toArray(await value(this.options.timingOrigin, origin, interceptorOptions));
247
252
  if (allowedTimingOrigins.includes("*")) {
248
253
  resHeaders["timing-allow-origin"] = "*";
249
254
  } else if (origin !== void 0 && allowedTimingOrigins.includes(origin)) {
@@ -294,21 +299,16 @@ class CORSHandlerPlugin {
294
299
 
295
300
  class GetMethodCsrfProtectionHandlerPlugin {
296
301
  name = "~get-method-csrf-protection";
297
- /** Judge the real request, before batch splits it into client-authored sub-requests. */
298
- after = ["~batch"];
299
302
  init(options) {
300
- const routingInterceptor = (interceptorOptions) => {
303
+ const interceptor = (interceptorOptions) => {
301
304
  if (this.isAllowed(interceptorOptions)) {
302
305
  return interceptorOptions.next();
303
306
  }
304
- return Promise.resolve({
305
- matched: true,
306
- response: { status: 403, headers: {}, body: "Request blocked by CSRF protection." }
307
- });
307
+ throw new ORPCError("FORBIDDEN", { message: "Request blocked by CSRF protection." });
308
308
  };
309
309
  return {
310
310
  ...options,
311
- routingInterceptors: [routingInterceptor, ...toArray(options.routingInterceptors)]
311
+ interceptors: [interceptor, ...toArray(options.interceptors)]
312
312
  };
313
313
  }
314
314
  isAllowed({ request }) {
@@ -370,6 +370,78 @@ class MethodOverrideHandlerPlugin {
370
370
  }
371
371
  }
372
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
+
373
445
  class RequestCompressionHandlerPlugin {
374
446
  name = "~request-compression";
375
447
  /**
@@ -465,9 +537,11 @@ class ResponseCompressionHandlerPlugin {
465
537
  after = ["~batch", "~response-headers"];
466
538
  encodings;
467
539
  threshold;
540
+ isCompressibleContentType;
468
541
  constructor(options = {}) {
469
542
  this.encodings = options.encodings ?? ["gzip", "deflate"];
470
543
  this.threshold = options.threshold ?? 1024;
544
+ this.isCompressibleContentType = options.isCompressibleContentType ?? isCompressibleContentType;
471
545
  }
472
546
  init(options) {
473
547
  const routingInterceptor = async ({ next, ...interceptorOptions }) => {
@@ -497,7 +571,7 @@ class ResponseCompressionHandlerPlugin {
497
571
  const headers = response.headers;
498
572
  if (body instanceof ReadableStream) {
499
573
  const contentLength = Number(flattenStandardHeader(headers["content-length"]));
500
- 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)) {
501
575
  return {
502
576
  ...result,
503
577
  response: {
@@ -514,7 +588,7 @@ class ResponseCompressionHandlerPlugin {
514
588
  };
515
589
  }
516
590
  } else if (body instanceof Blob) {
517
- 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)) {
518
592
  const contentDisposition = headers["content-disposition"] ?? generateContentDisposition(
519
593
  body instanceof File ? body.name : "blob"
520
594
  );
@@ -542,13 +616,13 @@ class ResponseCompressionHandlerPlugin {
542
616
  contentLength += PART_OVERHEAD + key.length;
543
617
  if (value instanceof Blob) {
544
618
  if (!Number.isFinite(value.size)) {
545
- if (!isCompressibleContentType(value.type)) {
619
+ if (!this.isCompressibleContentType(value.type, interceptorOptions)) {
546
620
  contentLength = -Infinity;
547
621
  break;
548
622
  }
549
623
  contentLength = Infinity;
550
624
  } else {
551
- contentLength += isCompressibleContentType(value.type) ? value.size : -value.size;
625
+ contentLength += this.isCompressibleContentType(value.type, interceptorOptions) ? value.size : -value.size;
552
626
  }
553
627
  } else {
554
628
  contentLength += value.length * AVG_BYTES_PER_CHAR;
@@ -761,4 +835,4 @@ class TimeoutHandlerPlugin {
761
835
  }
762
836
  }
763
837
 
764
- 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
- import { sortPlugins, getOpenTelemetryConfig, runWithSpan, toArray, matchesHttpPathPrefix, intercept, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, recordSpanError, pathToHttpPath, normalizeHttpPath, value, parseEmptyableJSON } from '@orpc/shared';
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";
@@ -292,7 +292,7 @@ class RPCHandlerCodec {
292
292
  };
293
293
  }
294
294
  encodeError(error, _procedure, _path, _options) {
295
- const status = this.errorStatusMap[error.code] ?? DEFAULT_ERROR_STATUS;
295
+ const status = getOwn(this.errorStatusMap, error.code) ?? DEFAULT_ERROR_STATUS;
296
296
  return {
297
297
  headers: {},
298
298
  status,
@@ -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.30",
4
+ "version": "2.0.0-beta.32",
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,16 +117,16 @@
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/client": "2.0.0-beta.30",
128
- "@orpc/shared": "2.0.0-beta.30",
129
- "@orpc/contract": "2.0.0-beta.30"
120
+ "@orpc/client": "2.0.0-beta.32",
121
+ "@orpc/contract": "2.0.0-beta.32",
122
+ "@orpc/shared": "2.0.0-beta.32",
123
+ "@standardserver/aws-lambda": "^0.8.2",
124
+ "@standardserver/core": "^0.8.2",
125
+ "@standardserver/fastify": "^0.8.2",
126
+ "@standardserver/fetch": "^0.8.2",
127
+ "@standardserver/node": "^0.8.2",
128
+ "@standardserver/peer": "^0.8.2",
129
+ "cookie": "^2.0.1"
130
130
  },
131
131
  "devDependencies": {
132
132
  "crossws": "^0.4.6",