@orpc/server 2.0.0-beta.44 → 2.0.0-beta.46

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.
Files changed (42) hide show
  1. package/README.md +100 -62
  2. package/dist/adapters/aws-lambda/index.d.mts +1 -0
  3. package/dist/adapters/aws-lambda/index.d.ts +1 -0
  4. package/dist/adapters/aws-lambda/index.mjs +3 -3
  5. package/dist/adapters/crossws/index.mjs +3 -3
  6. package/dist/adapters/fastify/index.mjs +3 -3
  7. package/dist/adapters/fetch/index.d.mts +2 -2
  8. package/dist/adapters/fetch/index.d.ts +2 -2
  9. package/dist/adapters/fetch/index.mjs +3 -3
  10. package/dist/adapters/message-port/index.d.mts +1 -1
  11. package/dist/adapters/message-port/index.d.ts +1 -1
  12. package/dist/adapters/message-port/index.mjs +3 -3
  13. package/dist/adapters/node/index.d.mts +1 -1
  14. package/dist/adapters/node/index.d.ts +1 -1
  15. package/dist/adapters/node/index.mjs +3 -3
  16. package/dist/adapters/standard/index.d.mts +8 -7
  17. package/dist/adapters/standard/index.d.ts +8 -7
  18. package/dist/adapters/standard/index.mjs +3 -3
  19. package/dist/adapters/websocket/index.mjs +3 -3
  20. package/dist/extensions/callable.mjs +2 -2
  21. package/dist/helpers/index.mjs +2 -8
  22. package/dist/index.d.mts +18 -33
  23. package/dist/index.d.ts +18 -33
  24. package/dist/index.mjs +12 -10
  25. package/dist/plugins/index.d.mts +57 -32
  26. package/dist/plugins/index.d.ts +57 -32
  27. package/dist/plugins/index.mjs +189 -48
  28. package/dist/shared/{server.DJNkZPfD.d.ts → server.9B1jEm5a.d.mts} +6 -16
  29. package/dist/shared/{server.FEqy7Hrj.mjs → server.BB464y-6.mjs} +6 -4
  30. package/dist/shared/{server.DD1roZl9.d.mts → server.BC5BIu02.d.mts} +1 -1
  31. package/dist/shared/{server.UG_xdTub.d.mts → server.BSYGskId.d.ts} +3 -3
  32. package/dist/shared/{server.DFEuNUt4.d.ts → server.BvG3boBj.d.mts} +3 -3
  33. package/dist/shared/{server.BllfVJLm.d.mts → server.CTV_mC2P.d.mts} +2 -2
  34. package/dist/shared/{server.BgvqVW_v.mjs → server.CYbIpHbH.mjs} +17 -5
  35. package/dist/shared/{server.COfbQ0D8.d.ts → server.CgBF3Vj1.d.ts} +2 -2
  36. package/dist/shared/{server.B34dZrzY.mjs → server.Chq5FpXf.mjs} +4 -10
  37. package/dist/shared/{server.BEdOJs6S.d.mts → server.DFPxP2v3.d.mts} +11 -8
  38. package/dist/shared/{server.BEdOJs6S.d.ts → server.DFPxP2v3.d.ts} +11 -8
  39. package/dist/shared/{server.CVO0hWyj.d.mts → server.DOg7ke6y.d.ts} +6 -16
  40. package/dist/shared/{server.DZeVx8K9.d.ts → server.Dz7j9BEh.d.ts} +1 -1
  41. package/dist/shared/{server.AVQWL-DI.mjs → server.sBQSgqK3.mjs} +1 -1
  42. package/package.json +12 -12
@@ -1,7 +1,9 @@
1
1
  import { ORPCError } from '@orpc/client';
2
- import { toArray, value, promiseWithResolvers, isAsyncIteratorObject, isCompressibleContentType, isNoTransformCacheControl, parseAcceptEncodingQualities, isAcceptableEncoding, varyByAcceptEncoding, stringifyJSON, anyAbortSignal, override, wrapAsyncIterator, wrapReadableStream, AbortError } from '@orpc/shared';
2
+ import { DEFAULT_BATCH_MAX_SIZE, BATCH_HEADER } from '@orpc/client/plugins';
3
+ export { BATCH_HEADER, DEFAULT_BATCH_MAX_SIZE } from '@orpc/client/plugins';
4
+ import { toArray, value, promiseWithResolvers, isAsyncIteratorObject, isCompressibleContentType, isNoTransformCacheControl, parseAcceptEncodingQualities, isAcceptableEncoding, varyByAcceptEncoding, stringifyJSON, anyAbortSignal, override, AsyncIteratorClass, runWithSignal, AbortError, wrapAsyncIterator, wrapReadableStream } from '@orpc/shared';
3
5
  import { flattenStandardHeader, parseStandardUrl, generateContentDisposition, mergeStandardHeaders } from '@standard-server/core';
4
- import { isClientPeerSendMessage, ServerPeer, encodePeerMessage } from '@standard-server/peer';
6
+ import { ServerPeer, isPeerMessage, isClientPeerSendMessage, encodePeerMessage } from '@standard-server/peer';
5
7
  import { toFetchHeaders, toStandardBody, toStandardHeaders } from '@standard-server/fetch';
6
8
  export { R as RequestLimitHandlerPlugin } from '../shared/server.1ExWFMze.mjs';
7
9
 
@@ -17,6 +19,48 @@ async function encodeFrame(message) {
17
19
  const bytes = typeof encoded === "string" ? textEncoder.encode(encoded) : encoded;
18
20
  return [encodeLengthPrefix(bytes.byteLength), bytes];
19
21
  }
22
+ function isBodyHeader(name) {
23
+ return name.startsWith("content-") || name === "standard-server";
24
+ }
25
+ function isClientPeerSendMessages(maybe) {
26
+ return Array.isArray(maybe) && maybe.every((m) => isPeerMessage(m) && isClientPeerSendMessage(m));
27
+ }
28
+ function internalError(err) {
29
+ Promise.reject(err);
30
+ return { status: 500, headers: {}, body: "Internal server error" };
31
+ }
32
+ function liftSubresponseHeaders(batchHeaders, subresponseHeaders) {
33
+ const [first = {}, ...rest] = subresponseHeaders;
34
+ const shared = {};
35
+ for (const [name, value2] of Object.entries(first)) {
36
+ if (value2 === void 0 || isBodyHeader(name)) {
37
+ continue;
38
+ }
39
+ const flattened = flattenStandardHeader(value2);
40
+ if (rest.every((other) => flattenStandardHeader(other[name]) === flattened)) {
41
+ shared[name] = value2;
42
+ }
43
+ }
44
+ const headers = { ...shared, ...batchHeaders };
45
+ const cookies = new Set([batchHeaders, ...subresponseHeaders].flatMap((other) => toArray(other["set-cookie"])));
46
+ if (cookies.size > 0) {
47
+ headers["set-cookie"] = [...cookies];
48
+ }
49
+ const varies = /* @__PURE__ */ new Map();
50
+ for (const value2 of [batchHeaders, ...subresponseHeaders].flatMap((other) => toArray(other.vary))) {
51
+ for (const field of value2.split(",")) {
52
+ const name = field.trim();
53
+ const key = name.toLowerCase();
54
+ if (name && !varies.has(key)) {
55
+ varies.set(key, name);
56
+ }
57
+ }
58
+ }
59
+ if (varies.size > 0) {
60
+ headers.vary = varies.has("*") ? "*" : [...varies.values()].join(", ");
61
+ }
62
+ return headers;
63
+ }
20
64
  class BatchHandlerPlugin {
21
65
  name = "~batch";
22
66
  /**
@@ -26,12 +70,13 @@ class BatchHandlerPlugin {
26
70
  after = ["~tracing"];
27
71
  maxSize;
28
72
  mapSubrequest;
73
+ mapSubresponse;
29
74
  successStatus;
30
75
  headers;
31
76
  keepAliveEnabled;
32
77
  keepAliveInterval;
33
78
  constructor(options = {}) {
34
- this.maxSize = options.maxSize ?? 10;
79
+ this.maxSize = options.maxSize ?? DEFAULT_BATCH_MAX_SIZE;
35
80
  this.mapSubrequest = options.mapSubrequest ?? ((subRequest, { request: batchRequest }) => ({
36
81
  ...subRequest,
37
82
  headers: {
@@ -42,10 +87,19 @@ class BatchHandlerPlugin {
42
87
  * or `origin`, cannot be overridden by a subrequest, which is just request payload.
43
88
  */
44
89
  ...batchRequest.headers,
45
- "orpc-batch": void 0
90
+ [BATCH_HEADER]: void 0
46
91
  // useful in case batch plugin is used multiple times
47
92
  }
48
93
  }));
94
+ this.mapSubresponse = options.mapSubresponse ?? ((subresponse, { headers: batchHeaders }) => {
95
+ const headers = {};
96
+ for (const [name, value2] of Object.entries(subresponse.headers)) {
97
+ if (name !== "set-cookie" && flattenStandardHeader(value2) !== flattenStandardHeader(batchHeaders[name])) {
98
+ headers[name] = value2;
99
+ }
100
+ }
101
+ return { ...subresponse, headers };
102
+ });
49
103
  this.successStatus = options.successStatus ?? 207;
50
104
  this.headers = options.headers ?? {};
51
105
  this.keepAliveEnabled = options.keepAlive?.enabled ?? true;
@@ -53,11 +107,9 @@ class BatchHandlerPlugin {
53
107
  }
54
108
  init(options) {
55
109
  const routingInterceptor = async (interceptorOptions) => {
56
- const batchHeader = flattenStandardHeader(interceptorOptions.request.headers["orpc-batch"]);
57
- if (batchHeader === void 0) {
110
+ if (flattenStandardHeader(interceptorOptions.request.headers[BATCH_HEADER]) === void 0) {
58
111
  return interceptorOptions.next();
59
112
  }
60
- const mode = batchHeader === "buffered" ? "buffered" : "streaming";
61
113
  let messages;
62
114
  try {
63
115
  if (interceptorOptions.request.method === "GET") {
@@ -71,7 +123,7 @@ class BatchHandlerPlugin {
71
123
  };
72
124
  }
73
125
  const mightBeMessages = JSON.parse(data);
74
- if (!Array.isArray(mightBeMessages) || mightBeMessages.some((m) => !isClientPeerSendMessage(m))) {
126
+ if (!isClientPeerSendMessages(mightBeMessages)) {
75
127
  return {
76
128
  matched: true,
77
129
  response: { status: 400, headers: {}, body: "Invalid batch request data parameter" }
@@ -80,7 +132,7 @@ class BatchHandlerPlugin {
80
132
  messages = mightBeMessages;
81
133
  } else {
82
134
  const mightBeMessages = await interceptorOptions.request.resolveBody();
83
- if (!Array.isArray(mightBeMessages) || mightBeMessages.some((m) => !isClientPeerSendMessage(m))) {
135
+ if (!isClientPeerSendMessages(mightBeMessages)) {
84
136
  return {
85
137
  matched: true,
86
138
  response: { status: 400, headers: {}, body: "Invalid batch request body" }
@@ -117,6 +169,14 @@ class BatchHandlerPlugin {
117
169
  const bufferedMessages = [];
118
170
  let streamController;
119
171
  let keepAliveTimer;
172
+ const ready = messages.map(() => promiseWithResolvers());
173
+ const lifting = Promise.all(ready.map(({ promise }) => promise)).then((all) => {
174
+ const heads = all.filter((head) => head !== void 0);
175
+ return {
176
+ batchHeaders: liftSubresponseHeaders(headers, heads.map((head) => head.headers)),
177
+ streams: heads.some((head) => head.stream)
178
+ };
179
+ });
120
180
  const clearKeepAlive = () => {
121
181
  if (keepAliveTimer !== void 0) {
122
182
  clearInterval(keepAliveTimer);
@@ -143,50 +203,37 @@ class BatchHandlerPlugin {
143
203
  scheduleKeepAlive();
144
204
  };
145
205
  const peer = new ServerPeer(async (message) => {
146
- if (mode === "streaming") {
147
- startStreaming();
148
- }
149
206
  if (streamController === void 0) {
150
207
  bufferedMessages.push(message);
151
208
  } else {
152
209
  await enqueueMessage(message);
153
210
  }
154
211
  });
155
- const streaming = promiseWithResolvers();
156
- function startStreaming() {
157
- if (streamController !== void 0) {
158
- return;
212
+ const handleIndividualRequest = async (request, markReady) => {
213
+ let response;
214
+ try {
215
+ request = this.mapSubrequest(request, interceptorOptions);
216
+ const result = await interceptorOptions.next({ ...interceptorOptions, request });
217
+ response = result.matched ? result.response : { status: 404, headers: {}, body: "No procedure matched" };
218
+ } catch (err) {
219
+ response = internalError(err);
159
220
  }
160
- const body = new ReadableStream({
161
- start(controller) {
162
- streamController = controller;
163
- scheduleKeepAlive();
164
- },
165
- async cancel(reason) {
166
- clearKeepAlive();
167
- await peer.close(reason);
168
- }
221
+ markReady({
222
+ headers: response.headers,
223
+ stream: response.body instanceof ReadableStream || isAsyncIteratorObject(response.body)
169
224
  });
170
- streaming.resolve({ body, flushed: Promise.all(bufferedMessages.splice(0).map(enqueueMessage)) });
171
- }
172
- const handleIndividualRequest = async (request) => {
225
+ const { batchHeaders: batchHeaders2 } = await lifting;
173
226
  try {
174
- request = this.mapSubrequest(request, interceptorOptions);
175
- const { matched, response } = await interceptorOptions.next({ ...interceptorOptions, request });
176
- if (!matched) {
177
- return { status: 404, headers: {}, body: "No procedure matched" };
178
- }
179
- if (response.body instanceof ReadableStream || isAsyncIteratorObject(response.body)) {
180
- startStreaming();
181
- }
182
- return response;
227
+ return this.mapSubresponse(response, { status, headers: batchHeaders2 }, interceptorOptions);
183
228
  } catch (err) {
184
- Promise.reject(err);
185
- return { status: 500, headers: {}, body: "Internal server error" };
229
+ return internalError(err);
186
230
  }
187
231
  };
188
232
  const runSubrequests = async () => {
189
- const promise = Promise.all(messages.map((msg) => peer.message(msg, handleIndividualRequest)));
233
+ const promise = Promise.all(messages.map((msg, i) => {
234
+ const { resolve } = ready[i];
235
+ return peer.message(msg, (request) => handleIndividualRequest(request, resolve)).finally(() => resolve(void 0));
236
+ }));
190
237
  const signal = interceptorOptions.request.signal;
191
238
  const closePeer = () => peer.close(signal?.reason);
192
239
  if (signal?.aborted) {
@@ -200,8 +247,9 @@ class BatchHandlerPlugin {
200
247
  }
201
248
  };
202
249
  const subrequests = runSubrequests();
203
- const started = await Promise.race([streaming.promise, subrequests.then(() => void 0)]);
204
- if (started === void 0) {
250
+ const { batchHeaders, streams } = await lifting;
251
+ if (!streams) {
252
+ await subrequests;
205
253
  await peer.close();
206
254
  if (bufferedMessages.some((msg) => msg.binary !== void 0)) {
207
255
  const chunks = (await Promise.all(bufferedMessages.map(encodeFrame))).flat();
@@ -209,17 +257,28 @@ class BatchHandlerPlugin {
209
257
  matched: true,
210
258
  response: {
211
259
  status,
212
- headers,
260
+ headers: batchHeaders,
213
261
  body: new Blob(chunks, { type: BATCH_CONTENT_TYPE })
214
262
  }
215
263
  };
216
264
  }
217
265
  return {
218
266
  matched: true,
219
- response: { status, headers, body: bufferedMessages }
267
+ response: { status, headers: batchHeaders, body: bufferedMessages }
220
268
  };
221
269
  }
222
- Promise.all([started.flushed, subrequests]).then(async () => {
270
+ const body = new ReadableStream({
271
+ start(controller) {
272
+ streamController = controller;
273
+ scheduleKeepAlive();
274
+ },
275
+ async cancel(reason) {
276
+ clearKeepAlive();
277
+ await peer.close(reason);
278
+ }
279
+ });
280
+ const flushed = Promise.all(bufferedMessages.splice(0).map(enqueueMessage));
281
+ Promise.all([flushed, subrequests]).then(async () => {
223
282
  clearKeepAlive();
224
283
  streamController.close();
225
284
  await peer.close();
@@ -232,8 +291,8 @@ class BatchHandlerPlugin {
232
291
  matched: true,
233
292
  response: {
234
293
  status,
235
- headers: { ...headers, "content-type": BATCH_CONTENT_TYPE },
236
- body: started.body
294
+ headers: { ...batchHeaders, "content-type": BATCH_CONTENT_TYPE },
295
+ body
237
296
  }
238
297
  };
239
298
  };
@@ -774,6 +833,88 @@ class RethrowHandlerPlugin {
774
833
  }
775
834
  }
776
835
 
836
+ class SignalSyncHandlerPlugin {
837
+ name = "~signal-sync";
838
+ init(options) {
839
+ const clientInterceptor = async (interceptorOptions) => {
840
+ const controller = new AbortController();
841
+ const signal = anyAbortSignal([interceptorOptions.signal, controller.signal]);
842
+ const cancel = () => controller.abort(new AbortError("The response body was cancelled"));
843
+ const output = await interceptorOptions.next({ ...interceptorOptions, signal });
844
+ if (isAsyncIteratorObject(output)) {
845
+ return override(output, syncAsyncIterator(output, signal, cancel));
846
+ }
847
+ if (output instanceof ReadableStream) {
848
+ return override(output, syncReadableStream(output, signal, cancel));
849
+ }
850
+ return output;
851
+ };
852
+ return { ...options, clientInterceptors: [clientInterceptor, ...toArray(options.clientInterceptors)] };
853
+ }
854
+ }
855
+ function listenAbort(signal, onAbort) {
856
+ if (signal.aborted) {
857
+ onAbort();
858
+ } else {
859
+ signal.addEventListener("abort", onAbort, { once: true });
860
+ }
861
+ return () => signal.removeEventListener("abort", onAbort);
862
+ }
863
+ function syncAsyncIterator(iterator, signal, cancel) {
864
+ let cancelling;
865
+ const unlisten = listenAbort(signal, () => {
866
+ cancelling = (async () => iterator.return?.())();
867
+ cancelling.catch(() => {
868
+ });
869
+ });
870
+ return new AsyncIteratorClass(
871
+ () => runWithSignal(signal, () => iterator.next()),
872
+ async ({ kind }) => {
873
+ if (kind === "cancelled") {
874
+ cancel();
875
+ await cancelling;
876
+ }
877
+ unlisten();
878
+ }
879
+ );
880
+ }
881
+ function syncReadableStream(stream, signal, cancel) {
882
+ const reader = stream.getReader();
883
+ let cancelling;
884
+ let unlisten;
885
+ return new ReadableStream({
886
+ start(controller) {
887
+ unlisten = listenAbort(signal, () => {
888
+ controller.error(signal.reason);
889
+ cancelling = reader.cancel(signal.reason);
890
+ cancelling.catch(() => {
891
+ });
892
+ });
893
+ },
894
+ async pull(controller) {
895
+ try {
896
+ const { done, value } = await reader.read();
897
+ if (signal.aborted) {
898
+ return;
899
+ }
900
+ if (done) {
901
+ unlisten();
902
+ controller.close();
903
+ } else {
904
+ controller.enqueue(value);
905
+ }
906
+ } catch (error) {
907
+ unlisten();
908
+ throw error;
909
+ }
910
+ },
911
+ async cancel() {
912
+ cancel();
913
+ await cancelling;
914
+ }
915
+ }, { highWaterMark: 0 });
916
+ }
917
+
777
918
  class TimeoutHandlerPlugin {
778
919
  timeout;
779
920
  streamingTimeout;
@@ -823,4 +964,4 @@ class TimeoutHandlerPlugin {
823
964
  }
824
965
  }
825
966
 
826
- export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, TimeoutHandlerPlugin, negotiateResponseCompressionEncoding, toCompressedHeaders };
967
+ export { BATCH_CONTENT_TYPE, BatchHandlerPlugin, CORSHandlerPlugin, CORSHandlerPlugin as CORSPlugin, GetMethodCsrfProtectionHandlerPlugin, MethodOverrideHandlerPlugin, RequestCompressionHandlerPlugin, RequestHeadersHandlerPlugin, RequestHeadersHandlerPlugin as RequestHeadersPlugin, ResponseCompressionHandlerPlugin, ResponseHeadersHandlerPlugin, ResponseHeadersHandlerPlugin as ResponseHeadersPlugin, RethrowHandlerPlugin, SignalSyncHandlerPlugin, TimeoutHandlerPlugin, negotiateResponseCompressionEncoding, toCompressedHeaders };
@@ -1,7 +1,7 @@
1
1
  import { AnyORPCError } from '@orpc/client';
2
2
  import { OrderablePlugin, Value, Promisable, Interceptor } from '@orpc/shared';
3
3
  import { StandardLazyRequest, StandardResponse } from '@standard-server/core';
4
- import { C as Context, c as ProcedureClientInterceptor, A as AnyProcedure } from './server.BEdOJs6S.js';
4
+ import { C as Context, c as ProcedureClientInterceptor, A as AnyProcedure } from './server.DFPxP2v3.mjs';
5
5
  import { Schema, ErrorMap } from '@orpc/contract';
6
6
 
7
7
  interface StandardHandlerPlugin<T extends Context> extends OrderablePlugin {
@@ -27,12 +27,6 @@ interface StandardHandlerPlugin<T extends Context> extends OrderablePlugin {
27
27
  */
28
28
  init?(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
29
29
  }
30
- declare class CompositeStandardHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
31
- readonly name = "~composite";
32
- protected readonly plugins: StandardHandlerPlugin<T>[];
33
- constructor(plugins?: StandardHandlerPlugin<T>[]);
34
- init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
35
- }
36
30
 
37
31
  interface StandardHandlerHandleOptions<T extends Context> {
38
32
  prefix?: `/${string}` | undefined;
@@ -73,19 +67,19 @@ interface StandardHandlerOptions<TContext extends Context> {
73
67
  * - batch plugins - separate one request into multiple and call multiple next
74
68
  * - openapi spec plugin - to intercept a request and early response
75
69
  */
76
- routingInterceptors?: StandardHandlerRoutingInterceptor<TContext>[];
70
+ routingInterceptors?: StandardHandlerRoutingInterceptor<TContext>[] | undefined;
77
71
  /**
78
72
  * interceptor run after routing and before error handler,
79
73
  * useful for error handling, logging, metrics, etc.
80
74
  */
81
- interceptors?: StandardHandlerInterceptor<TContext>[];
75
+ interceptors?: StandardHandlerInterceptor<TContext>[] | undefined;
82
76
  /**
83
77
  *
84
78
  * ClientInterceptor equivalent with createRouterClient.interceptors / createProcedure.interceptors
85
79
  * useful for error handling, logging, metrics, etc. (not counting encoding/decoding)
86
80
  */
87
- clientInterceptors?: ProcedureClientInterceptor<TContext, Schema<unknown>, ErrorMap>[];
88
- plugins?: StandardHandlerPlugin<TContext>[];
81
+ clientInterceptors?: ProcedureClientInterceptor<TContext, Schema<unknown>, ErrorMap>[] | undefined;
82
+ plugins?: StandardHandlerPlugin<TContext>[] | undefined;
89
83
  }
90
84
  declare class StandardHandler<T extends Context> {
91
85
  private readonly codec;
@@ -95,10 +89,6 @@ declare class StandardHandler<T extends Context> {
95
89
  constructor(codec: StandardHandlerCodec<T>, options: StandardHandlerOptions<T>);
96
90
  handle(request: StandardLazyRequest, options: StandardHandlerHandleOptions<T>): Promise<StandardHandlerHandleResult>;
97
91
  }
98
- declare class TracingHandlerPlugin implements StandardHandlerPlugin<any> {
99
- name: string;
100
- init(options: StandardHandlerOptions<any>): StandardHandlerOptions<any>;
101
- }
102
92
 
103
93
  interface StandardHandlerCodecResolvedProcedure {
104
94
  path: string[];
@@ -111,5 +101,5 @@ interface StandardHandlerCodec<T extends Context> {
111
101
  encodeError(error: AnyORPCError, procedure: AnyProcedure, path: string[], options: ResolvedStandardHandlerHandleOptions<T>): Promisable<StandardResponse>;
112
102
  }
113
103
 
114
- export { CompositeStandardHandlerPlugin as C, StandardHandler as S, TracingHandlerPlugin as T };
104
+ export { StandardHandler as S };
115
105
  export type { ResolvedStandardHandlerHandleOptions as R, StandardHandlerHandleOptions as a, StandardHandlerPlugin as b, StandardHandlerOptions as c, StandardHandlerRoutingInterceptorOptions as d, StandardHandlerInterceptorOptions as e, StandardHandlerCodec as f, StandardHandlerCodecResolvedProcedure as g, StandardHandlerHandleResult as h, StandardHandlerInterceptor as i, StandardHandlerRoutingInterceptor as j };
@@ -120,7 +120,7 @@ async function executeProcedureInternal(procedure, options) {
120
120
  const inputSchemas = toArray(procedure["~orpc"].inputSchemas);
121
121
  const outputSchemas = toArray(procedure["~orpc"].outputSchemas);
122
122
  const orderedMiddlewares = procedure["~orpc"].orderedMiddlewares;
123
- const next = async (midIndex, context, input) => {
123
+ const next = async (midIndex, context, input, signal) => {
124
124
  let currentInput = input;
125
125
  let middlewareInput = input;
126
126
  const startInputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].inputSchemasLengthAtUse ?? 0;
@@ -146,13 +146,15 @@ async function executeProcedureInternal(procedure, options) {
146
146
  {
147
147
  ...options,
148
148
  context,
149
+ signal,
149
150
  next: (...rest) => {
150
151
  const nextOptions = resolveMaybeOptionalOptions(rest);
151
152
  const nextContext = nextOptions.context ?? {};
152
153
  return next(
153
154
  midIndex + 1,
154
155
  { ...context, ...nextContext },
155
- currentInput
156
+ currentInput,
157
+ nextOptions.signal ?? signal
156
158
  );
157
159
  },
158
160
  lastEventId: options.lastEventId
@@ -166,7 +168,7 @@ async function executeProcedureInternal(procedure, options) {
166
168
  } else {
167
169
  currentOutput = await runWithSpan(
168
170
  "handler",
169
- () => procedure["~orpc"].handler({ ...options, context, input: currentInput }, currentInput)
171
+ () => procedure["~orpc"].handler({ ...options, context, input: currentInput, signal }, currentInput)
170
172
  );
171
173
  }
172
174
  const startOutputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].outputSchemasLengthAtUse ?? 0;
@@ -178,7 +180,7 @@ async function executeProcedureInternal(procedure, options) {
178
180
  }
179
181
  return { output: currentOutput, context: currentContext };
180
182
  };
181
- const { output } = await next(0, options.context, options.input);
183
+ const { output } = await next(0, options.context, options.input, options.signal);
182
184
  return output;
183
185
  }
184
186
 
@@ -1,5 +1,5 @@
1
1
  import { RouterContract, ProcedureContract, ORPCErrorFromErrorMap, ThrowableError, InferSchemaInput, InferSchemaOutput } from '@orpc/contract';
2
- import { C as Context, a as Procedure, L as Lazyable, M as MergedContext } from './server.BEdOJs6S.mjs';
2
+ import { C as Context, a as Procedure, L as Lazyable, M as MergedContext } from './server.DFPxP2v3.mjs';
3
3
 
4
4
  type Router<TInitialContext extends Context> = Procedure<TInitialContext, any, any, any, any> | {
5
5
  [k: string]: Lazyable<Router<TInitialContext>>;
@@ -1,10 +1,10 @@
1
1
  import { Value, Promisable } from '@orpc/shared';
2
2
  import { StandardLazyRequest } from '@standard-server/core';
3
- import { C as Context } from './server.BEdOJs6S.mjs';
4
- import { a as StandardHandlerHandleOptions } from './server.CVO0hWyj.mjs';
3
+ import { C as Context } from './server.DFPxP2v3.js';
4
+ import { a as StandardHandlerHandleOptions } from './server.DOg7ke6y.js';
5
5
 
6
6
  type FriendlyStandardHandlerHandleOptions<T extends Context> = Omit<StandardHandlerHandleOptions<T>, 'context'> & (object extends T ? {
7
- context?: Value<Promisable<T>, [request: StandardLazyRequest]>;
7
+ context?: Value<Promisable<T>, [request: StandardLazyRequest]> | undefined;
8
8
  } : {
9
9
  context: Value<Promisable<T>, [request: StandardLazyRequest]>;
10
10
  });
@@ -1,10 +1,10 @@
1
1
  import { Value, Promisable } from '@orpc/shared';
2
2
  import { StandardLazyRequest } from '@standard-server/core';
3
- import { C as Context } from './server.BEdOJs6S.js';
4
- import { a as StandardHandlerHandleOptions } from './server.DJNkZPfD.js';
3
+ import { C as Context } from './server.DFPxP2v3.mjs';
4
+ import { a as StandardHandlerHandleOptions } from './server.9B1jEm5a.mjs';
5
5
 
6
6
  type FriendlyStandardHandlerHandleOptions<T extends Context> = Omit<StandardHandlerHandleOptions<T>, 'context'> & (object extends T ? {
7
- context?: Value<Promisable<T>, [request: StandardLazyRequest]>;
7
+ context?: Value<Promisable<T>, [request: StandardLazyRequest]> | undefined;
8
8
  } : {
9
9
  context: Value<Promisable<T>, [request: StandardLazyRequest]>;
10
10
  });
@@ -1,5 +1,5 @@
1
- import { C as Context } from './server.BEdOJs6S.mjs';
2
- import { b as StandardHandlerPlugin, c as StandardHandlerOptions } from './server.CVO0hWyj.mjs';
1
+ import { C as Context } from './server.DFPxP2v3.mjs';
2
+ import { b as StandardHandlerPlugin, c as StandardHandlerOptions } from './server.9B1jEm5a.mjs';
3
3
 
4
4
  interface RequestLimitHandlerPluginOptions {
5
5
  /**
@@ -1,9 +1,9 @@
1
- import { c as createProcedureClient, P as Procedure, L as Lazy, u as unlazy } from './server.FEqy7Hrj.mjs';
2
- import { resolveMetaPlugins, mergeErrorMap, ProcedureContract } from '@orpc/contract';
3
- import { omit, isTypescriptObject, getOwn } from '@orpc/shared';
1
+ import { ProcedureContract, resolveMetaPlugins, mergeErrorMap } from '@orpc/contract';
2
+ import { isTypescriptObject, getOwn, omit } from '@orpc/shared';
3
+ import { c as createProcedureClient, L as Lazy, u as unlazy, P as Procedure } from './server.BB464y-6.mjs';
4
4
 
5
5
  const DEFAULT_SUCCESS_STATUS = 200;
6
- const DEFAULT_ERROR_STATUS = 500;
6
+ const DEFAULT_ERROR_STATUS = 400;
7
7
 
8
8
  function createGuardedProcedureLazy(lazy) {
9
9
  const guarded = new Lazy({
@@ -130,6 +130,18 @@ function augmentImplementedRouter(router, options) {
130
130
  }
131
131
  return enhanced;
132
132
  }
133
+ async function resolveContractProcedure(router, contract, path) {
134
+ if (contract instanceof Procedure) {
135
+ return contract;
136
+ }
137
+ const { default: maybeProcedure } = await unlazy(getRouter(router, path));
138
+ if (!(maybeProcedure instanceof Procedure)) {
139
+ throw new TypeError(
140
+ `[Contract-First] Missing or invalid implementation for procedure at path: "${path.join(".")}". Ensure the procedure is correctly implemented and matches its contract.`
141
+ );
142
+ }
143
+ return createContractProcedure(maybeProcedure, contract);
144
+ }
133
145
  function getRouter(router, path) {
134
146
  let current = router;
135
147
  for (let i = 0; i < path.length; i++) {
@@ -224,4 +236,4 @@ async function unlazyRouter(router) {
224
236
  return unlazied;
225
237
  }
226
238
 
227
- export { DEFAULT_SUCCESS_STATUS as D, DEFAULT_ERROR_STATUS as a, augmentRouter as b, createContractProcedure as c, augmentImplementedRouter as d, withHiddenRouterContract as e, createGuardedProcedureLazy as f, getRouter as g, call as h, getHiddenRouterContract as i, walkProcedureContractsAsync as j, unlazyRouter as u, walkProcedureContractsSync as w };
239
+ export { DEFAULT_SUCCESS_STATUS as D, DEFAULT_ERROR_STATUS as a, augmentRouter as b, augmentImplementedRouter as c, withHiddenRouterContract as d, createGuardedProcedureLazy as e, call as f, getRouter as g, walkProcedureContractsAsync as h, resolveContractProcedure as r, unlazyRouter as u, walkProcedureContractsSync as w };
@@ -1,5 +1,5 @@
1
- import { C as Context } from './server.BEdOJs6S.js';
2
- import { b as StandardHandlerPlugin, c as StandardHandlerOptions } from './server.DJNkZPfD.js';
1
+ import { C as Context } from './server.DFPxP2v3.js';
2
+ import { b as StandardHandlerPlugin, c as StandardHandlerOptions } from './server.DOg7ke6y.js';
3
3
 
4
4
  interface RequestLimitHandlerPluginOptions {
5
5
  /**
@@ -1,8 +1,8 @@
1
1
  import { ORPCError, toORPCError, RPCSerializer, COMMON_ERROR_STATUS_MAP } from '@orpc/client';
2
2
  import { sortPlugins, toArray, matchesHttpPathPrefix, value, intercept, getTracer, runWithSpan, ORPC_NAME, isAsyncIteratorObject, override, traceAsyncIterator, traceReadableStream, recordSpanError, wrapAsyncIterator, toTracingException, wrapReadableStream, pathToHttpPath, normalizeHttpPath, parseEmptyableJSON, getOwn } from '@orpc/shared';
3
3
  import { flattenStandardHeader, parseStandardUrl, ErrorEvent } from '@standard-server/core';
4
- import { c as createProcedureClient, u as unlazy, P as Procedure } from './server.FEqy7Hrj.mjs';
5
- import { w as walkProcedureContractsSync, g as getRouter, c as createContractProcedure, D as DEFAULT_SUCCESS_STATUS, a as DEFAULT_ERROR_STATUS } from './server.BgvqVW_v.mjs';
4
+ import { c as createProcedureClient, u as unlazy, P as Procedure } from './server.BB464y-6.mjs';
5
+ import { w as walkProcedureContractsSync, r as resolveContractProcedure, D as DEFAULT_SUCCESS_STATUS, a as DEFAULT_ERROR_STATUS } from './server.CYbIpHbH.mjs';
6
6
 
7
7
  class CompositeStandardHandlerPlugin {
8
8
  name = "~composite";
@@ -298,13 +298,7 @@ class RPCMatcher {
298
298
  this.pendingLazyRouters.delete(httpPathPrefix);
299
299
  }
300
300
  async resolveProcedure(entry) {
301
- const { default: maybeProcedure } = await unlazy(getRouter(this.rootRouter, entry.path));
302
- if (!(maybeProcedure instanceof Procedure)) {
303
- throw new TypeError(
304
- `[Contract-First] Missing or invalid implementation for procedure at path: "${entry.path.join(".")}". Ensure the procedure is correctly implemented and matches its contract.`
305
- );
306
- }
307
- entry.procedure = createContractProcedure(maybeProcedure, entry.contract);
301
+ entry.procedure = await resolveContractProcedure(this.rootRouter, entry.contract, entry.path);
308
302
  return entry.procedure;
309
303
  }
310
304
  }
@@ -356,4 +350,4 @@ class RPCHandlerCodec {
356
350
  }
357
351
  }
358
352
 
359
- export { CompositeStandardHandlerPlugin as C, RPCHandlerCodec as R, StandardHandler as S, TracingHandlerPlugin as T, RPCMatcher as a, RPC_DEFAULT_ALLOW_METHODS as b };
353
+ export { RPCHandlerCodec as R, StandardHandler as S, RPCMatcher as a, RPC_DEFAULT_ALLOW_METHODS as b };
@@ -12,16 +12,19 @@ type MiddlewareResult<TOutContext extends Context, TOutput> = Promisable<{
12
12
  output: TOutput;
13
13
  context: TOutContext;
14
14
  }>;
15
- type MiddlewareNextOptions<TOutContext extends Context> = object extends TOutContext ? {
16
- context?: TOutContext;
15
+ type MiddlewareNextOptions<TOutContext extends Context> = (object extends TOutContext ? {
16
+ context?: TOutContext | undefined;
17
17
  } : {
18
18
  context: TOutContext;
19
+ }) & {
20
+ /** Overrides the signal for the rest of the chain. */
21
+ signal?: AbortSignal | undefined;
19
22
  };
20
23
  interface MiddlewareNext<TOutput> {
21
24
  <T extends Context = object>(...rest: MaybeOptionalOptions<MiddlewareNextOptions<T>>): MiddlewareResult<T, TOutput>;
22
25
  }
23
26
  type MiddlewareDoneOptions<TOutContext, TOutput> = (object extends TOutContext ? {
24
- context?: TOutContext;
27
+ context?: TOutContext | undefined;
25
28
  } : {
26
29
  context: TOutContext;
27
30
  }) & {
@@ -150,14 +153,14 @@ interface ProcedureClientInterceptorOptions<TInitialContext extends Context, TEr
150
153
  }
151
154
  type ProcedureClientInterceptor<TInitialContext extends Context, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> = Interceptor<ProcedureClientInterceptorOptions<TInitialContext, TErrorMap>, PromiseWithError<InferSchemaOutput<TOutputSchema>, ORPCErrorFromErrorMap<TErrorMap> | ThrowableError>>;
152
155
  type ProcedureClientOptions<TInitialContext extends Context, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TClientContext extends ClientContext> = {
153
- path?: string[];
154
- interceptors?: ProcedureClientInterceptor<TInitialContext, TOutputSchema, TErrorMap>[];
156
+ path?: string[] | undefined;
157
+ interceptors?: ProcedureClientInterceptor<TInitialContext, TOutputSchema, TErrorMap>[] | undefined;
155
158
  } & (object extends TInitialContext ? {
156
- context?: Value<Promisable<TInitialContext>, [clientContext: TClientContext]>;
159
+ context?: Value<Promisable<TInitialContext>, [clientContext: TClientContext]> | undefined;
157
160
  } : {
158
161
  context: Value<Promisable<TInitialContext>, [clientContext: TClientContext]>;
159
162
  });
160
163
  declare function createProcedureClient<TInitialContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap, TClientContext extends ClientContext = object>(lazyableProcedure: Lazyable<Procedure<TInitialContext, any, TInputSchema, TOutputSchema, TErrorMap>>, ...rest: MaybeOptionalOptions<ProcedureClientOptions<TInitialContext, TOutputSchema, TErrorMap, TClientContext>>): ProcedureClient<TClientContext, TInputSchema, TOutputSchema, TErrorMap>;
161
164
 
162
- export { Procedure as a, Lazy as h, createProcedureClient as u, unlazy as v };
163
- export type { AnyProcedure as A, Context as C, Lazyable as L, MergedContext as M, OrderedMiddleware as O, ProcedureClientOptions as P, ProcedureClient as b, ProcedureClientInterceptor as c, Middleware as d, MergedInitialContext as e, ProcedureConfig as f, AnyMiddleware as g, ProcedureHandler as i, LazyDefinition as j, MiddlewareDefinition as k, MiddlewareDone as l, MiddlewareDoneOptions as m, MiddlewareNext as n, MiddlewareNextOptions as o, MiddlewareOptions as p, MiddlewareResult as q, ProcedureClientInterceptorOptions as r, ProcedureDefinition as s, ProcedureHandlerOptions as t };
165
+ export { Procedure as a, Lazy as f, createProcedureClient as u, unlazy as v };
166
+ export type { AnyProcedure as A, Context as C, Lazyable as L, MergedContext as M, OrderedMiddleware as O, ProcedureClientOptions as P, ProcedureClient as b, ProcedureClientInterceptor as c, Middleware as d, MergedInitialContext as e, ProcedureHandler as g, ProcedureConfig as h, AnyMiddleware as i, LazyDefinition as j, MiddlewareDefinition as k, MiddlewareDone as l, MiddlewareDoneOptions as m, MiddlewareNext as n, MiddlewareNextOptions as o, MiddlewareOptions as p, MiddlewareResult as q, ProcedureClientInterceptorOptions as r, ProcedureDefinition as s, ProcedureHandlerOptions as t };