@orpc/server 0.0.0-next.350a165 → 0.0.0-next.35fabdb

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 (71) hide show
  1. package/README.md +20 -23
  2. package/dist/adapters/aws-lambda/index.d.mts +46 -0
  3. package/dist/adapters/aws-lambda/index.d.ts +46 -0
  4. package/dist/adapters/aws-lambda/index.mjs +42 -0
  5. package/dist/adapters/bun-ws/index.d.mts +36 -0
  6. package/dist/adapters/bun-ws/index.d.ts +36 -0
  7. package/dist/adapters/bun-ws/index.mjs +47 -0
  8. package/dist/adapters/crossws/index.d.mts +33 -0
  9. package/dist/adapters/crossws/index.d.ts +33 -0
  10. package/dist/adapters/crossws/index.mjs +45 -0
  11. package/dist/adapters/fetch/index.d.mts +74 -8
  12. package/dist/adapters/fetch/index.d.ts +74 -8
  13. package/dist/adapters/fetch/index.mjs +179 -8
  14. package/dist/adapters/message-port/index.d.mts +31 -0
  15. package/dist/adapters/message-port/index.d.ts +31 -0
  16. package/dist/adapters/message-port/index.mjs +39 -0
  17. package/dist/adapters/node/index.d.mts +50 -8
  18. package/dist/adapters/node/index.d.ts +50 -8
  19. package/dist/adapters/node/index.mjs +79 -19
  20. package/dist/adapters/standard/index.d.mts +8 -13
  21. package/dist/adapters/standard/index.d.ts +8 -13
  22. package/dist/adapters/standard/index.mjs +5 -3
  23. package/dist/adapters/standard-peer/index.d.mts +18 -0
  24. package/dist/adapters/standard-peer/index.d.ts +18 -0
  25. package/dist/adapters/standard-peer/index.mjs +7 -0
  26. package/dist/adapters/websocket/index.d.mts +54 -0
  27. package/dist/adapters/websocket/index.d.ts +54 -0
  28. package/dist/adapters/websocket/index.mjs +67 -0
  29. package/dist/adapters/ws/index.d.mts +31 -0
  30. package/dist/adapters/ws/index.d.ts +31 -0
  31. package/dist/adapters/ws/index.mjs +37 -0
  32. package/dist/helpers/index.d.mts +134 -0
  33. package/dist/helpers/index.d.ts +134 -0
  34. package/dist/helpers/index.mjs +188 -0
  35. package/dist/hibernation/index.d.mts +44 -0
  36. package/dist/hibernation/index.d.ts +44 -0
  37. package/dist/hibernation/index.mjs +65 -0
  38. package/dist/index.d.mts +563 -51
  39. package/dist/index.d.ts +563 -51
  40. package/dist/index.mjs +139 -13
  41. package/dist/plugins/index.d.mts +112 -11
  42. package/dist/plugins/index.d.ts +112 -11
  43. package/dist/plugins/index.mjs +145 -58
  44. package/dist/shared/{server.C37gDhSZ.mjs → server.7jWaIryJ.mjs} +109 -57
  45. package/dist/shared/server.B7b2w3_i.d.ts +12 -0
  46. package/dist/shared/server.BEFBl-Cb.d.mts +12 -0
  47. package/dist/shared/server.BHZCyRuJ.mjs +219 -0
  48. package/dist/shared/server.BU4WI18A.d.mts +32 -0
  49. package/dist/shared/server.BW-nUGgA.mjs +36 -0
  50. package/dist/shared/{server.DfyOFejj.d.ts → server.Bmh5xd4n.d.ts} +18 -17
  51. package/dist/shared/{server.DLt5njUb.d.mts → server.CYNGeoCm.d.mts} +60 -9
  52. package/dist/shared/{server.DLt5njUb.d.ts → server.CYNGeoCm.d.ts} +60 -9
  53. package/dist/shared/server.D0H-iaY3.d.ts +32 -0
  54. package/dist/shared/{server.BVwwTHyO.mjs → server.DZ5BIITo.mjs} +1 -1
  55. package/dist/shared/server.DhJj-1X9.d.mts +42 -0
  56. package/dist/shared/server.UVMTOWrk.mjs +26 -0
  57. package/dist/shared/{server.Dm5DEJl5.d.mts → server.gqRxT-yN.d.mts} +18 -17
  58. package/dist/shared/server.jMTkVNIb.d.ts +42 -0
  59. package/package.json +71 -20
  60. package/dist/adapters/hono/index.d.mts +0 -22
  61. package/dist/adapters/hono/index.d.ts +0 -22
  62. package/dist/adapters/hono/index.mjs +0 -32
  63. package/dist/adapters/next/index.d.mts +0 -29
  64. package/dist/adapters/next/index.d.ts +0 -29
  65. package/dist/adapters/next/index.mjs +0 -29
  66. package/dist/shared/server.C56IpPNj.d.mts +0 -10
  67. package/dist/shared/server.C78d5yfh.mjs +0 -173
  68. package/dist/shared/server.CSIDw0mq.mjs +0 -106
  69. package/dist/shared/server.CyrwhzzU.d.ts +0 -8
  70. package/dist/shared/server.DgrNIRDf.d.mts +0 -8
  71. package/dist/shared/server.DnuwaDJo.d.ts +0 -10
@@ -1,5 +1,10 @@
1
- import { value } from '@orpc/shared';
1
+ import { runWithSpan, value, setSpanError, isAsyncIteratorObject, clone } from '@orpc/shared';
2
+ import { flattenHeader } from '@orpc/standard-server';
2
3
  import { parseBatchRequest, toBatchResponse } from '@orpc/standard-server/batch';
4
+ import { toFetchHeaders } from '@orpc/standard-server-fetch';
5
+ import { ORPCError } from '@orpc/client';
6
+ export { S as StrictGetMethodPlugin } from '../shared/server.BW-nUGgA.mjs';
7
+ import '@orpc/contract';
3
8
 
4
9
  class BatchHandlerPlugin {
5
10
  maxSize;
@@ -22,61 +27,80 @@ class BatchHandlerPlugin {
22
27
  init(options) {
23
28
  options.rootInterceptors ??= [];
24
29
  options.rootInterceptors.unshift(async (options2) => {
25
- if (options2.request.headers["x-orpc-batch"] !== "1") {
30
+ const xHeader = flattenHeader(options2.request.headers["x-orpc-batch"]);
31
+ if (xHeader === void 0) {
26
32
  return options2.next();
27
33
  }
28
34
  let isParsing = false;
29
35
  try {
30
- isParsing = true;
31
- const parsed = parseBatchRequest({ ...options2.request, body: await options2.request.body() });
32
- isParsing = false;
33
- const maxSize = await value(this.maxSize, options2);
34
- if (parsed.length > maxSize) {
35
- return {
36
- matched: true,
37
- response: {
38
- status: 413,
39
- headers: {},
40
- body: "Batch request size exceeds the maximum allowed size"
41
- }
42
- };
43
- }
44
- const responses = parsed.map(
45
- (request, index) => {
46
- const mapped = this.mapRequestItem(request, options2);
47
- return options2.next({ ...options2, request: { ...mapped, body: () => Promise.resolve(mapped.body) } }).then(({ response: response2, matched }) => {
48
- if (matched) {
49
- return { ...response2, index };
36
+ return await runWithSpan({ name: "handle_batch_request" }, async (span) => {
37
+ const mode = xHeader === "buffered" ? "buffered" : "streaming";
38
+ isParsing = true;
39
+ const parsed = parseBatchRequest({ ...options2.request, body: await options2.request.body() });
40
+ isParsing = false;
41
+ span?.setAttribute("batch.mode", mode);
42
+ span?.setAttribute("batch.size", parsed.length);
43
+ const maxSize = await value(this.maxSize, options2);
44
+ if (parsed.length > maxSize) {
45
+ const message = "Batch request size exceeds the maximum allowed size";
46
+ setSpanError(span, message);
47
+ return {
48
+ matched: true,
49
+ response: {
50
+ status: 413,
51
+ headers: {},
52
+ body: message
50
53
  }
51
- return { index, status: 404, headers: {}, body: "No procedure matched" };
52
- }).catch(() => {
53
- return { index, status: 500, headers: {}, body: "Internal server error" };
54
- });
54
+ };
55
55
  }
56
- );
57
- await Promise.race(responses);
58
- const status = await value(this.successStatus, responses, options2);
59
- const headers = await value(this.headers, responses, options2);
60
- const response = toBatchResponse({
61
- status,
62
- headers,
63
- body: async function* () {
64
- const promises = [...responses];
65
- while (true) {
66
- const handling = promises.filter((p) => p !== void 0);
67
- if (handling.length === 0) {
68
- return;
69
- }
70
- const result = await Promise.race(handling);
71
- promises[result.index] = void 0;
72
- yield result;
56
+ const responses = parsed.map(
57
+ (request, index) => {
58
+ const mapped = this.mapRequestItem(request, options2);
59
+ return options2.next({ ...options2, request: { ...mapped, body: () => Promise.resolve(mapped.body) } }).then(({ response: response2, matched }) => {
60
+ span?.addEvent(`response.${index}.${matched ? "success" : "not_matched"}`);
61
+ if (matched) {
62
+ if (response2.body instanceof Blob || response2.body instanceof FormData || isAsyncIteratorObject(response2.body)) {
63
+ return {
64
+ index,
65
+ status: 500,
66
+ headers: {},
67
+ body: "Batch responses do not support file/blob, or event-iterator. Please call this procedure separately outside of the batch request."
68
+ };
69
+ }
70
+ return { ...response2, index };
71
+ }
72
+ return { index, status: 404, headers: {}, body: "No procedure matched" };
73
+ }).catch((err) => {
74
+ Promise.reject(err);
75
+ return { index, status: 500, headers: {}, body: "Internal server error" };
76
+ });
73
77
  }
74
- }()
78
+ );
79
+ await Promise.race(responses);
80
+ const status = await value(this.successStatus, responses, options2);
81
+ const headers = await value(this.headers, responses, options2);
82
+ const response = await toBatchResponse({
83
+ status,
84
+ headers,
85
+ mode,
86
+ body: (async function* () {
87
+ const promises = [...responses];
88
+ while (true) {
89
+ const handling = promises.filter((p) => p !== void 0);
90
+ if (handling.length === 0) {
91
+ return;
92
+ }
93
+ const result = await Promise.race(handling);
94
+ promises[result.index] = void 0;
95
+ yield result;
96
+ }
97
+ })()
98
+ });
99
+ return {
100
+ matched: true,
101
+ response
102
+ };
75
103
  });
76
- return {
77
- matched: true,
78
- response
79
- };
80
104
  } catch (cause) {
81
105
  if (isParsing) {
82
106
  return {
@@ -112,13 +136,11 @@ class CORSPlugin {
112
136
  resHeaders["access-control-max-age"] = this.options.maxAge.toString();
113
137
  }
114
138
  if (this.options.allowMethods?.length) {
115
- resHeaders["access-control-allow-methods"] = this.options.allowMethods.join(",");
139
+ resHeaders["access-control-allow-methods"] = flattenHeader(this.options.allowMethods);
116
140
  }
117
141
  const allowHeaders = this.options.allowHeaders ?? interceptorOptions.request.headers["access-control-request-headers"];
118
- if (Array.isArray(allowHeaders) && allowHeaders.length) {
119
- resHeaders["access-control-allow-headers"] = allowHeaders.join(",");
120
- } else if (typeof allowHeaders === "string") {
121
- resHeaders["access-control-allow-headers"] = allowHeaders;
142
+ if (typeof allowHeaders === "string" || allowHeaders?.length) {
143
+ resHeaders["access-control-allow-headers"] = flattenHeader(allowHeaders);
122
144
  }
123
145
  return {
124
146
  matched: true,
@@ -136,7 +158,7 @@ class CORSPlugin {
136
158
  if (!result.matched) {
137
159
  return result;
138
160
  }
139
- const origin = Array.isArray(interceptorOptions.request.headers.origin) ? interceptorOptions.request.headers.origin.join(",") : interceptorOptions.request.headers.origin || "";
161
+ const origin = flattenHeader(interceptorOptions.request.headers.origin) ?? "";
140
162
  const allowedOrigin = await value(this.options.origin, origin, interceptorOptions);
141
163
  const allowedOriginArr = Array.isArray(allowedOrigin) ? allowedOrigin : [allowedOrigin];
142
164
  if (allowedOriginArr.includes("*")) {
@@ -158,13 +180,29 @@ class CORSPlugin {
158
180
  result.response.headers["access-control-allow-credentials"] = "true";
159
181
  }
160
182
  if (this.options.exposeHeaders?.length) {
161
- result.response.headers["access-control-expose-headers"] = this.options.exposeHeaders.join(",");
183
+ result.response.headers["access-control-expose-headers"] = flattenHeader(this.options.exposeHeaders);
162
184
  }
163
185
  return result;
164
186
  });
165
187
  }
166
188
  }
167
189
 
190
+ class RequestHeadersPlugin {
191
+ init(options) {
192
+ options.rootInterceptors ??= [];
193
+ options.rootInterceptors.push((interceptorOptions) => {
194
+ const reqHeaders = interceptorOptions.context.reqHeaders ?? toFetchHeaders(interceptorOptions.request.headers);
195
+ return interceptorOptions.next({
196
+ ...interceptorOptions,
197
+ context: {
198
+ ...interceptorOptions.context,
199
+ reqHeaders
200
+ }
201
+ });
202
+ });
203
+ }
204
+ }
205
+
168
206
  class ResponseHeadersPlugin {
169
207
  init(options) {
170
208
  options.rootInterceptors ??= [];
@@ -180,7 +218,7 @@ class ResponseHeadersPlugin {
180
218
  if (!result.matched) {
181
219
  return result;
182
220
  }
183
- const responseHeaders = result.response.headers;
221
+ const responseHeaders = clone(result.response.headers);
184
222
  for (const [key, value] of resHeaders) {
185
223
  if (Array.isArray(responseHeaders[key])) {
186
224
  responseHeaders[key].push(value);
@@ -190,9 +228,58 @@ class ResponseHeadersPlugin {
190
228
  responseHeaders[key] = value;
191
229
  }
192
230
  }
193
- return result;
231
+ return {
232
+ ...result,
233
+ response: {
234
+ ...result.response,
235
+ headers: responseHeaders
236
+ }
237
+ };
238
+ });
239
+ }
240
+ }
241
+
242
+ const SIMPLE_CSRF_PROTECTION_CONTEXT_SYMBOL = Symbol("SIMPLE_CSRF_PROTECTION_CONTEXT");
243
+ class SimpleCsrfProtectionHandlerPlugin {
244
+ headerName;
245
+ headerValue;
246
+ exclude;
247
+ error;
248
+ constructor(options = {}) {
249
+ this.headerName = options.headerName ?? "x-csrf-token";
250
+ this.headerValue = options.headerValue ?? "orpc";
251
+ this.exclude = options.exclude ?? false;
252
+ this.error = options.error ?? new ORPCError("CSRF_TOKEN_MISMATCH", {
253
+ status: 403,
254
+ message: "Invalid CSRF token"
255
+ });
256
+ }
257
+ order = 8e6;
258
+ init(options) {
259
+ options.rootInterceptors ??= [];
260
+ options.clientInterceptors ??= [];
261
+ options.rootInterceptors.unshift(async (options2) => {
262
+ const headerName = await value(this.headerName, options2);
263
+ const headerValue = await value(this.headerValue, options2);
264
+ return options2.next({
265
+ ...options2,
266
+ context: {
267
+ ...options2.context,
268
+ [SIMPLE_CSRF_PROTECTION_CONTEXT_SYMBOL]: options2.request.headers[headerName] === headerValue
269
+ }
270
+ });
271
+ });
272
+ options.clientInterceptors.unshift(async (options2) => {
273
+ if (typeof options2.context[SIMPLE_CSRF_PROTECTION_CONTEXT_SYMBOL] !== "boolean") {
274
+ throw new TypeError("[SimpleCsrfProtectionHandlerPlugin] CSRF protection context has been corrupted or modified by another plugin or interceptor");
275
+ }
276
+ const excluded = await value(this.exclude, options2);
277
+ if (!excluded && !options2.context[SIMPLE_CSRF_PROTECTION_CONTEXT_SYMBOL]) {
278
+ throw this.error;
279
+ }
280
+ return options2.next();
194
281
  });
195
282
  }
196
283
  }
197
284
 
198
- export { BatchHandlerPlugin, CORSPlugin, ResponseHeadersPlugin };
285
+ export { BatchHandlerPlugin, CORSPlugin, RequestHeadersPlugin, ResponseHeadersPlugin, SimpleCsrfProtectionHandlerPlugin };
@@ -1,6 +1,7 @@
1
1
  import { isContractProcedure, ValidationError, mergePrefix, mergeErrorMap, enhanceRoute } from '@orpc/contract';
2
- import { fallbackORPCErrorStatus, ORPCError } from '@orpc/client';
3
- import { value, intercept } from '@orpc/shared';
2
+ import { resolveMaybeOptionalOptions, toArray, value, runWithSpan, intercept, isAsyncIteratorObject, asyncIteratorWithSpan } from '@orpc/shared';
3
+ import { ORPCError, fallbackORPCErrorStatus, mapEventIterator } from '@orpc/client';
4
+ import { HibernationEventIterator } from '@orpc/standard-server';
4
5
 
5
6
  const LAZY_SYMBOL = Symbol("ORPC_LAZY_SYMBOL");
6
7
  function lazy(loader, meta = {}) {
@@ -46,6 +47,9 @@ function addMiddleware(middlewares, addition) {
46
47
  }
47
48
 
48
49
  class Procedure {
50
+ /**
51
+ * This property holds the defined options.
52
+ */
49
53
  "~orpc";
50
54
  constructor(def) {
51
55
  this["~orpc"] = def;
@@ -68,14 +72,15 @@ function createORPCErrorConstructorMap(errors) {
68
72
  if (typeof code !== "string") {
69
73
  return Reflect.get(target, code);
70
74
  }
71
- const item = (...[options]) => {
75
+ const item = (...rest) => {
76
+ const options = resolveMaybeOptionalOptions(rest);
72
77
  const config = errors[code];
73
78
  return new ORPCError(code, {
74
79
  defined: Boolean(config),
75
80
  status: config?.status,
76
- message: options?.message ?? config?.message,
77
- data: options?.data,
78
- cause: options?.cause
81
+ message: options.message ?? config?.message,
82
+ data: options.data,
83
+ cause: options.cause
79
84
  });
80
85
  };
81
86
  return item;
@@ -103,34 +108,59 @@ function middlewareOutputFn(output) {
103
108
  return { output, context: {} };
104
109
  }
105
110
 
106
- function createProcedureClient(lazyableProcedure, ...[options]) {
111
+ function createProcedureClient(lazyableProcedure, ...rest) {
112
+ const options = resolveMaybeOptionalOptions(rest);
107
113
  return async (...[input, callerOptions]) => {
108
- const path = options?.path ?? [];
114
+ const path = toArray(options.path);
109
115
  const { default: procedure } = await unlazy(lazyableProcedure);
110
116
  const clientContext = callerOptions?.context ?? {};
111
- const context = await value(options?.context ?? {}, clientContext);
117
+ const context = await value(options.context ?? {}, clientContext);
112
118
  const errors = createORPCErrorConstructorMap(procedure["~orpc"].errorMap);
119
+ const validateError = async (e) => {
120
+ if (e instanceof ORPCError) {
121
+ return await validateORPCError(procedure["~orpc"].errorMap, e);
122
+ }
123
+ return e;
124
+ };
113
125
  try {
114
- return await intercept(
115
- options?.interceptors ?? [],
116
- {
117
- context,
118
- input,
119
- // input only optional when it undefinable so we can safely cast it
120
- errors,
121
- path,
122
- procedure,
123
- signal: callerOptions?.signal,
124
- lastEventId: callerOptions?.lastEventId
125
- },
126
- (interceptorOptions) => executeProcedureInternal(interceptorOptions.procedure, interceptorOptions)
126
+ const output = await runWithSpan(
127
+ { name: "call_procedure", signal: callerOptions?.signal },
128
+ (span) => {
129
+ span?.setAttribute("procedure.path", [...path]);
130
+ return intercept(
131
+ toArray(options.interceptors),
132
+ {
133
+ context,
134
+ input,
135
+ // input only optional when it undefinable so we can safely cast it
136
+ errors,
137
+ path,
138
+ procedure,
139
+ signal: callerOptions?.signal,
140
+ lastEventId: callerOptions?.lastEventId
141
+ },
142
+ (interceptorOptions) => executeProcedureInternal(interceptorOptions.procedure, interceptorOptions)
143
+ );
144
+ }
127
145
  );
128
- } catch (e) {
129
- if (!(e instanceof ORPCError)) {
130
- throw e;
146
+ if (isAsyncIteratorObject(output)) {
147
+ if (output instanceof HibernationEventIterator) {
148
+ return output;
149
+ }
150
+ return mapEventIterator(
151
+ asyncIteratorWithSpan(
152
+ { name: "consume_event_iterator_output", signal: callerOptions?.signal },
153
+ output
154
+ ),
155
+ {
156
+ value: (v) => v,
157
+ error: (e) => validateError(e)
158
+ }
159
+ );
131
160
  }
132
- const validated = await validateORPCError(procedure["~orpc"].errorMap, e);
133
- throw validated;
161
+ return output;
162
+ } catch (e) {
163
+ throw await validateError(e);
134
164
  }
135
165
  };
136
166
  }
@@ -139,31 +169,41 @@ async function validateInput(procedure, input) {
139
169
  if (!schema) {
140
170
  return input;
141
171
  }
142
- const result = await schema["~standard"].validate(input);
143
- if (result.issues) {
144
- throw new ORPCError("BAD_REQUEST", {
145
- message: "Input validation failed",
146
- data: {
147
- issues: result.issues
148
- },
149
- cause: new ValidationError({ message: "Input validation failed", issues: result.issues })
150
- });
151
- }
152
- return result.value;
172
+ return runWithSpan(
173
+ { name: "validate_input" },
174
+ async () => {
175
+ const result = await schema["~standard"].validate(input);
176
+ if (result.issues) {
177
+ throw new ORPCError("BAD_REQUEST", {
178
+ message: "Input validation failed",
179
+ data: {
180
+ issues: result.issues
181
+ },
182
+ cause: new ValidationError({ message: "Input validation failed", issues: result.issues })
183
+ });
184
+ }
185
+ return result.value;
186
+ }
187
+ );
153
188
  }
154
189
  async function validateOutput(procedure, output) {
155
190
  const schema = procedure["~orpc"].outputSchema;
156
191
  if (!schema) {
157
192
  return output;
158
193
  }
159
- const result = await schema["~standard"].validate(output);
160
- if (result.issues) {
161
- throw new ORPCError("INTERNAL_SERVER_ERROR", {
162
- message: "Output validation failed",
163
- cause: new ValidationError({ message: "Output validation failed", issues: result.issues })
164
- });
165
- }
166
- return result.value;
194
+ return runWithSpan(
195
+ { name: "validate_output" },
196
+ async () => {
197
+ const result = await schema["~standard"].validate(output);
198
+ if (result.issues) {
199
+ throw new ORPCError("INTERNAL_SERVER_ERROR", {
200
+ message: "Output validation failed",
201
+ cause: new ValidationError({ message: "Output validation failed", issues: result.issues })
202
+ });
203
+ }
204
+ return result.value;
205
+ }
206
+ );
167
207
  }
168
208
  async function executeProcedureInternal(procedure, options) {
169
209
  const middlewares = procedure["~orpc"].middlewares;
@@ -175,17 +215,28 @@ async function executeProcedureInternal(procedure, options) {
175
215
  currentInput = await validateInput(procedure, currentInput);
176
216
  }
177
217
  const mid = middlewares[index];
178
- const output = mid ? (await mid({
179
- ...options,
180
- context,
181
- next: async (...[nextOptions]) => {
182
- const nextContext = nextOptions?.context ?? {};
183
- return {
184
- output: await next(index + 1, mergeCurrentContext(context, nextContext), currentInput),
185
- context: nextContext
186
- };
218
+ const output = mid ? await runWithSpan(
219
+ { name: `middleware.${mid.name}`, signal: options.signal },
220
+ async (span) => {
221
+ span?.setAttribute("middleware.index", index);
222
+ span?.setAttribute("middleware.name", mid.name);
223
+ const result = await mid({
224
+ ...options,
225
+ context,
226
+ next: async (...[nextOptions]) => {
227
+ const nextContext = nextOptions?.context ?? {};
228
+ return {
229
+ output: await next(index + 1, mergeCurrentContext(context, nextContext), currentInput),
230
+ context: nextContext
231
+ };
232
+ }
233
+ }, currentInput, middlewareOutputFn);
234
+ return result.output;
187
235
  }
188
- }, currentInput, middlewareOutputFn)).output : await procedure["~orpc"].handler({ ...options, context, input: currentInput });
236
+ ) : await runWithSpan(
237
+ { name: "handler", signal: options.signal },
238
+ () => procedure["~orpc"].handler({ ...options, context, input: currentInput })
239
+ );
189
240
  if (index === outputValidationIndex) {
190
241
  return await validateOutput(procedure, output);
191
242
  }
@@ -358,7 +409,8 @@ function createContractedProcedure(procedure, contract) {
358
409
  });
359
410
  }
360
411
  function call(procedure, input, ...rest) {
361
- return createProcedureClient(procedure, ...rest)(input);
412
+ const options = resolveMaybeOptionalOptions(rest);
413
+ return createProcedureClient(procedure, options)(input, options);
362
414
  }
363
415
 
364
416
  export { LAZY_SYMBOL as L, Procedure as P, createContractedProcedure as a, addMiddleware as b, createProcedureClient as c, isLazy as d, enhanceRouter as e, createAssertedLazyProcedure as f, getRouter as g, createORPCErrorConstructorMap as h, isProcedure as i, getLazyMeta as j, middlewareOutputFn as k, lazy as l, mergeCurrentContext as m, isStartWithMiddlewares as n, mergeMiddlewares as o, call as p, getHiddenRouterContract as q, createAccessibleLazyRouter as r, setHiddenRouterContract as s, traverseContractProcedures as t, unlazy as u, validateORPCError as v, resolveContractProcedures as w, unlazyRouter as x };
@@ -0,0 +1,12 @@
1
+ import { C as Context } from './server.CYNGeoCm.js';
2
+ import { b as StandardHandleOptions } from './server.Bmh5xd4n.js';
3
+
4
+ type FriendlyStandardHandleOptions<T extends Context> = Omit<StandardHandleOptions<T>, 'context'> & (Record<never, never> extends T ? {
5
+ context?: T;
6
+ } : {
7
+ context: T;
8
+ });
9
+ declare function resolveFriendlyStandardHandleOptions<T extends Context>(options: FriendlyStandardHandleOptions<T>): StandardHandleOptions<T>;
10
+
11
+ export { resolveFriendlyStandardHandleOptions as r };
12
+ export type { FriendlyStandardHandleOptions as F };
@@ -0,0 +1,12 @@
1
+ import { C as Context } from './server.CYNGeoCm.mjs';
2
+ import { b as StandardHandleOptions } from './server.gqRxT-yN.mjs';
3
+
4
+ type FriendlyStandardHandleOptions<T extends Context> = Omit<StandardHandleOptions<T>, 'context'> & (Record<never, never> extends T ? {
5
+ context?: T;
6
+ } : {
7
+ context: T;
8
+ });
9
+ declare function resolveFriendlyStandardHandleOptions<T extends Context>(options: FriendlyStandardHandleOptions<T>): StandardHandleOptions<T>;
10
+
11
+ export { resolveFriendlyStandardHandleOptions as r };
12
+ export type { FriendlyStandardHandleOptions as F };