@orpc/server 2.0.0-beta.47 → 2.0.0-beta.48

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 (169) hide show
  1. package/README.md +2 -3
  2. package/dist/adapters/aws-lambda/handler.d.mts +25 -0
  3. package/dist/adapters/aws-lambda/handler.mjs +21 -0
  4. package/dist/adapters/aws-lambda/index.d.mts +14 -49
  5. package/dist/adapters/aws-lambda/index.mjs +2 -39
  6. package/dist/adapters/aws-lambda/rpc-handler.d.mts +18 -0
  7. package/dist/adapters/aws-lambda/rpc-handler.mjs +10 -0
  8. package/dist/adapters/crossws/handler.d.mts +41 -0
  9. package/dist/adapters/crossws/handler.mjs +38 -0
  10. package/dist/adapters/crossws/index.d.mts +2 -63
  11. package/dist/adapters/crossws/index.mjs +2 -68
  12. package/dist/adapters/crossws/rpc-handler.d.mts +15 -0
  13. package/dist/adapters/crossws/rpc-handler.mjs +10 -0
  14. package/dist/adapters/fastify/handler.d.mts +21 -0
  15. package/dist/adapters/fastify/handler.mjs +20 -0
  16. package/dist/adapters/fastify/index.d.mts +2 -42
  17. package/dist/adapters/fastify/index.mjs +2 -39
  18. package/dist/adapters/fastify/rpc-handler.d.mts +14 -0
  19. package/dist/adapters/fastify/rpc-handler.mjs +10 -0
  20. package/dist/adapters/fetch/handler.d.mts +23 -0
  21. package/dist/adapters/fetch/handler.mjs +22 -0
  22. package/dist/adapters/fetch/index.d.mts +6 -46
  23. package/dist/adapters/fetch/index.mjs +4 -41
  24. package/dist/adapters/fetch/rpc-handler.d.mts +16 -0
  25. package/dist/adapters/fetch/rpc-handler.mjs +10 -0
  26. package/dist/adapters/message-port/handler.d.mts +57 -0
  27. package/dist/adapters/message-port/handler.mjs +62 -0
  28. package/dist/adapters/message-port/index.d.mts +2 -77
  29. package/dist/adapters/message-port/index.mjs +2 -87
  30. package/dist/adapters/message-port/rpc-handler.d.mts +15 -0
  31. package/dist/adapters/message-port/rpc-handler.mjs +10 -0
  32. package/dist/adapters/node/handler.d.mts +21 -0
  33. package/dist/adapters/node/handler.mjs +20 -0
  34. package/dist/adapters/node/index.d.mts +6 -43
  35. package/dist/adapters/node/index.mjs +4 -40
  36. package/dist/adapters/node/rpc-handler.d.mts +15 -0
  37. package/dist/adapters/node/rpc-handler.mjs +10 -0
  38. package/dist/adapters/standard/codec.d.mts +16 -0
  39. package/dist/adapters/standard/codec.mjs +1 -0
  40. package/dist/adapters/standard/handler.d.mts +68 -0
  41. package/dist/adapters/standard/handler.mjs +185 -0
  42. package/dist/adapters/standard/index.d.mts +6 -95
  43. package/dist/adapters/standard/index.mjs +5 -8
  44. package/dist/adapters/standard/plugin.d.mts +32 -0
  45. package/dist/adapters/standard/plugin.mjs +16 -0
  46. package/dist/adapters/standard/rpc-handler-codec.d.mts +42 -0
  47. package/dist/adapters/standard/rpc-handler-codec.mjs +51 -0
  48. package/dist/adapters/standard/rpc-matcher.d.mts +53 -0
  49. package/dist/adapters/standard/rpc-matcher.mjs +140 -0
  50. package/dist/adapters/standard/utils.d.mts +10 -0
  51. package/dist/adapters/standard/utils.mjs +6 -0
  52. package/dist/adapters/standard-peer/index.d.mts +1 -11
  53. package/dist/adapters/standard-peer/index.mjs +1 -10
  54. package/dist/adapters/standard-peer/utils.d.mts +4 -0
  55. package/dist/adapters/standard-peer/utils.mjs +11 -0
  56. package/dist/adapters/websocket/handler.d.mts +55 -0
  57. package/dist/adapters/websocket/handler.mjs +55 -0
  58. package/dist/adapters/websocket/index.d.mts +2 -77
  59. package/dist/adapters/websocket/index.mjs +2 -87
  60. package/dist/adapters/websocket/rpc-handler.d.mts +15 -0
  61. package/dist/adapters/websocket/rpc-handler.mjs +10 -0
  62. package/dist/builder-variants.d.mts +267 -0
  63. package/dist/builder-variants.mjs +1 -0
  64. package/dist/builder.d.mts +141 -0
  65. package/dist/builder.mjs +145 -0
  66. package/dist/constants.d.mts +2 -0
  67. package/dist/constants.mjs +2 -0
  68. package/dist/context.d.mts +13 -0
  69. package/dist/context.mjs +1 -0
  70. package/dist/extensions/callable.d.mts +16 -9
  71. package/dist/extensions/callable.mjs +5 -9
  72. package/dist/helpers/base64url.d.mts +31 -0
  73. package/dist/helpers/base64url.mjs +25 -0
  74. package/dist/helpers/cookie.d.mts +50 -0
  75. package/dist/helpers/cookie.mjs +35 -0
  76. package/dist/helpers/encryption.d.mts +28 -0
  77. package/dist/helpers/encryption.mjs +62 -0
  78. package/dist/helpers/index.d.mts +4 -167
  79. package/dist/helpers/index.mjs +4 -200
  80. package/dist/helpers/signing.d.mts +50 -0
  81. package/dist/helpers/signing.mjs +43 -0
  82. package/dist/implementer-procedure.d.mts +36 -0
  83. package/dist/implementer-procedure.mjs +38 -0
  84. package/dist/implementer-router.d.mts +78 -0
  85. package/dist/implementer-router.mjs +77 -0
  86. package/dist/implementer.d.mts +22 -0
  87. package/dist/implementer.mjs +30 -0
  88. package/dist/index.d.mts +57 -476
  89. package/dist/index.mjs +25 -458
  90. package/dist/lazy.d.mts +20 -0
  91. package/dist/lazy.mjs +22 -0
  92. package/dist/middleware-decorated.d.mts +27 -0
  93. package/dist/middleware-decorated.mjs +65 -0
  94. package/dist/middleware.d.mts +70 -0
  95. package/dist/middleware.mjs +1 -0
  96. package/dist/plugins/batch.d.mts +104 -0
  97. package/dist/plugins/batch.mjs +373 -0
  98. package/dist/plugins/cors.d.mts +67 -0
  99. package/dist/plugins/cors.mjs +134 -0
  100. package/dist/plugins/get-method-csrf-protection.d.mts +23 -0
  101. package/dist/plugins/get-method-csrf-protection.mjs +45 -0
  102. package/dist/plugins/head-method.d.mts +23 -0
  103. package/dist/plugins/head-method.mjs +95 -0
  104. package/dist/plugins/index.d.mts +39 -432
  105. package/dist/plugins/index.mjs +23 -965
  106. package/dist/plugins/method-override.d.mts +38 -0
  107. package/dist/plugins/method-override.mjs +50 -0
  108. package/dist/plugins/request-compression.d.mts +16 -0
  109. package/dist/plugins/request-compression.mjs +67 -0
  110. package/dist/plugins/request-headers.d.mts +22 -0
  111. package/dist/plugins/request-headers.mjs +21 -0
  112. package/dist/plugins/request-limit.d.mts +30 -0
  113. package/dist/plugins/request-limit.mjs +53 -0
  114. package/dist/plugins/response-compression.d.mts +59 -0
  115. package/dist/plugins/response-compression.mjs +172 -0
  116. package/dist/plugins/response-headers.d.mts +30 -0
  117. package/dist/plugins/response-headers.mjs +34 -0
  118. package/dist/plugins/rethrow.d.mts +33 -0
  119. package/dist/plugins/rethrow.mjs +46 -0
  120. package/dist/plugins/signal-sync.d.mts +13 -0
  121. package/dist/plugins/signal-sync.mjs +84 -0
  122. package/dist/plugins/timeout.d.mts +37 -0
  123. package/dist/plugins/timeout.mjs +56 -0
  124. package/dist/procedure-client.d.mts +41 -0
  125. package/dist/procedure-client.mjs +157 -0
  126. package/dist/procedure-decorated.d.mts +20 -0
  127. package/dist/procedure-decorated.mjs +41 -0
  128. package/dist/procedure-utils.d.mts +52 -0
  129. package/dist/procedure-utils.mjs +33 -0
  130. package/dist/procedure.d.mts +93 -0
  131. package/dist/procedure.mjs +20 -0
  132. package/dist/router-client.d.mts +27 -0
  133. package/dist/router-client.mjs +35 -0
  134. package/dist/router-hidden.d.mts +5 -0
  135. package/dist/router-hidden.mjs +12 -0
  136. package/dist/router-utils.d.mts +59 -0
  137. package/dist/router-utils.mjs +191 -0
  138. package/dist/router.d.mts +61 -0
  139. package/dist/router.mjs +1 -0
  140. package/package.json +11 -11
  141. package/dist/adapters/aws-lambda/index.d.ts +0 -51
  142. package/dist/adapters/crossws/index.d.ts +0 -63
  143. package/dist/adapters/fastify/index.d.ts +0 -42
  144. package/dist/adapters/fetch/index.d.ts +0 -47
  145. package/dist/adapters/message-port/index.d.ts +0 -77
  146. package/dist/adapters/node/index.d.ts +0 -44
  147. package/dist/adapters/standard/index.d.ts +0 -95
  148. package/dist/adapters/standard-peer/index.d.ts +0 -11
  149. package/dist/adapters/websocket/index.d.ts +0 -77
  150. package/dist/extensions/callable.d.ts +0 -10
  151. package/dist/helpers/index.d.ts +0 -167
  152. package/dist/index.d.ts +0 -476
  153. package/dist/plugins/index.d.ts +0 -432
  154. package/dist/shared/server.1ExWFMze.mjs +0 -69
  155. package/dist/shared/server.9B1jEm5a.d.mts +0 -105
  156. package/dist/shared/server.BB464y-6.mjs +0 -207
  157. package/dist/shared/server.BC5BIu02.d.mts +0 -73
  158. package/dist/shared/server.BSYGskId.d.ts +0 -14
  159. package/dist/shared/server.BvG3boBj.d.mts +0 -14
  160. package/dist/shared/server.CTV_mC2P.d.mts +0 -34
  161. package/dist/shared/server.CYbIpHbH.mjs +0 -239
  162. package/dist/shared/server.CgBF3Vj1.d.ts +0 -34
  163. package/dist/shared/server.Chq5FpXf.mjs +0 -353
  164. package/dist/shared/server.DFPxP2v3.d.mts +0 -166
  165. package/dist/shared/server.DFPxP2v3.d.ts +0 -166
  166. package/dist/shared/server.DOg7ke6y.d.ts +0 -105
  167. package/dist/shared/server.Dz7j9BEh.d.ts +0 -73
  168. package/dist/shared/server.W91HSRkE.mjs +0 -9
  169. package/dist/shared/server.sBQSgqK3.mjs +0 -41
@@ -0,0 +1,13 @@
1
+ import type { StandardHandlerOptions, StandardHandlerPlugin } from "../adapters/standard/index.mjs";
2
+ import type { Context } from "../context.mjs";
3
+ /**
4
+ * Keeps the request signal and a streaming output (async iterator object or readable stream) in sync:
5
+ * cancelling the output aborts the signal with an `AbortError`,
6
+ * and aborting the signal ends the output with the abort reason and cancels it.
7
+ *
8
+ * @see {@link https://orpc.dev/docs/plugins/signal-sync | Signal Sync Plugin}
9
+ */
10
+ export declare class SignalSyncHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
11
+ name: string;
12
+ init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
13
+ }
@@ -0,0 +1,84 @@
1
+ import { AbortError, anyAbortSignal, AsyncIteratorClass, isAsyncIteratorObject, override, runWithSignal, toArray } from "@orpc/shared";
2
+
3
+ export class SignalSyncHandlerPlugin {
4
+ name = "~signal-sync";
5
+ init(options) {
6
+ const clientInterceptor = async (interceptorOptions) => {
7
+ const controller = new AbortController();
8
+ const signal = anyAbortSignal([interceptorOptions.signal, controller.signal]);
9
+ const cancel = () => controller.abort(new AbortError("The response body was cancelled"));
10
+ const output = await interceptorOptions.next({
11
+ ...interceptorOptions,
12
+ signal
13
+ });
14
+ if (isAsyncIteratorObject(output)) {
15
+ return override(output, syncAsyncIterator(output, signal, cancel));
16
+ }
17
+ if (output instanceof ReadableStream) {
18
+ return override(output, syncReadableStream(output, signal, cancel));
19
+ }
20
+ return output;
21
+ };
22
+ return {
23
+ ...options,
24
+ clientInterceptors: [clientInterceptor, ...toArray(options.clientInterceptors)]
25
+ };
26
+ }
27
+ }
28
+ function listenAbort(signal, onAbort) {
29
+ if (signal.aborted) {
30
+ onAbort();
31
+ } else {
32
+ signal.addEventListener("abort", onAbort, { once: true });
33
+ }
34
+ return () => signal.removeEventListener("abort", onAbort);
35
+ }
36
+ function syncAsyncIterator(iterator, signal, cancel) {
37
+ let cancelling;
38
+ const unlisten = listenAbort(signal, () => {
39
+ cancelling = (async () => iterator.return?.())();
40
+ cancelling.catch(() => {});
41
+ });
42
+ return new AsyncIteratorClass(() => runWithSignal(signal, () => iterator.next()), async ({ kind }) => {
43
+ if (kind === "cancelled") {
44
+ cancel();
45
+ await cancelling;
46
+ }
47
+ unlisten();
48
+ });
49
+ }
50
+ function syncReadableStream(stream, signal, cancel) {
51
+ const reader = stream.getReader();
52
+ let cancelling;
53
+ let unlisten;
54
+ return new ReadableStream({
55
+ start(controller) {
56
+ unlisten = listenAbort(signal, () => {
57
+ controller.error(signal.reason);
58
+ cancelling = reader.cancel(signal.reason);
59
+ cancelling.catch(() => {});
60
+ });
61
+ },
62
+ async pull(controller) {
63
+ try {
64
+ const { done, value } = await reader.read();
65
+ if (signal.aborted) {
66
+ return;
67
+ }
68
+ if (done) {
69
+ unlisten();
70
+ controller.close();
71
+ } else {
72
+ controller.enqueue(value);
73
+ }
74
+ } catch (error) {
75
+ unlisten();
76
+ throw error;
77
+ }
78
+ },
79
+ async cancel() {
80
+ cancel();
81
+ await cancelling;
82
+ }
83
+ }, { highWaterMark: 0 });
84
+ }
@@ -0,0 +1,37 @@
1
+ import type { Value } from "@orpc/shared";
2
+ import type { StandardHandlerInterceptorOptions, StandardHandlerOptions, StandardHandlerPlugin } from "../adapters/standard/index.mjs";
3
+ import type { Context } from "../context.mjs";
4
+ export interface TimeoutHandlerPluginOptions<T extends Context> {
5
+ /**
6
+ * Timeout in milliseconds before the request signal is aborted.
7
+ * This only covers producing the response, use `streamingTimeout`
8
+ * to limit streaming response bodies.
9
+ * Use `null` or `undefined` to disable the timeout.
10
+ */
11
+ timeout: Value<number | null | undefined, [options: StandardHandlerInterceptorOptions<T>]>;
12
+ /**
13
+ * Timeout in milliseconds for the full duration of a streaming response body
14
+ * (async iterator object or readable stream), measured from when the response is produced.
15
+ * When exceeded, the request signal is aborted and the body ends
16
+ * once its producer honors the signal.
17
+ * Usually higher than `timeout`.
18
+ * Use `null` or `undefined` to disable the timeout.
19
+ *
20
+ * @default undefined (streaming responses run without limit)
21
+ */
22
+ streamingTimeout?: Value<number | null | undefined, [options: StandardHandlerInterceptorOptions<T>]> | undefined;
23
+ }
24
+ /**
25
+ * The Timeout Handler Plugin aborts the request signal with an `AbortError`
26
+ * when handling exceeds a configured timeout. It only aborts the signal,
27
+ * the procedure must honor it to stop early and produce the response.
28
+ *
29
+ * @see {@link https://orpc.dev/docs/plugins/timeout | Timeout Plugin}
30
+ */
31
+ export declare class TimeoutHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
32
+ private readonly timeout;
33
+ private readonly streamingTimeout;
34
+ name: string;
35
+ constructor(options: NoInfer<TimeoutHandlerPluginOptions<T>>);
36
+ init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
37
+ }
@@ -0,0 +1,56 @@
1
+ import { AbortError, anyAbortSignal, isAsyncIteratorObject, override, toArray, value, wrapAsyncIterator, wrapReadableStream } from "@orpc/shared";
2
+
3
+ export class TimeoutHandlerPlugin {
4
+ timeout;
5
+ streamingTimeout;
6
+ name = "~timeout";
7
+ constructor(options) {
8
+ this.timeout = options.timeout;
9
+ this.streamingTimeout = options.streamingTimeout;
10
+ }
11
+ init(options) {
12
+ const interceptor = async (interceptorOptions) => {
13
+ const timeoutMs = value(this.timeout, interceptorOptions);
14
+ const streamingTimeoutMs = value(this.streamingTimeout, interceptorOptions);
15
+ const hasTimeout = timeoutMs !== null && timeoutMs !== undefined;
16
+ const hasStreamingTimeout = streamingTimeoutMs !== null && streamingTimeoutMs !== undefined;
17
+ if (!hasTimeout && !hasStreamingTimeout) {
18
+ return interceptorOptions.next();
19
+ }
20
+ const controller = new AbortController();
21
+ const abortWithTimeout = (ms) => {
22
+ controller.abort(new AbortError(`Request timed out after ${ms}ms`));
23
+ };
24
+ const timeoutId = hasTimeout ? setTimeout(abortWithTimeout, timeoutMs, timeoutMs) : undefined;
25
+ const signal = anyAbortSignal([interceptorOptions.request.signal, controller.signal]);
26
+ try {
27
+ const response = await interceptorOptions.next({
28
+ ...interceptorOptions,
29
+ request: {
30
+ ...interceptorOptions.request,
31
+ signal
32
+ }
33
+ });
34
+ if (hasStreamingTimeout) {
35
+ const body = response.body;
36
+ const isIterator = isAsyncIteratorObject(body);
37
+ if (isIterator || body instanceof ReadableStream) {
38
+ const streamingTimeoutId = setTimeout(abortWithTimeout, streamingTimeoutMs, streamingTimeoutMs);
39
+ const onFinish = () => clearTimeout(streamingTimeoutId);
40
+ return {
41
+ ...response,
42
+ body: isIterator ? override(body, wrapAsyncIterator(body, { onFinish })) : override(body, wrapReadableStream(body, { onFinish }))
43
+ };
44
+ }
45
+ }
46
+ return response;
47
+ } finally {
48
+ clearTimeout(timeoutId);
49
+ }
50
+ };
51
+ return {
52
+ ...options,
53
+ interceptors: [interceptor, ...toArray(options.interceptors)]
54
+ };
55
+ }
56
+ }
@@ -0,0 +1,41 @@
1
+ import type { Client, ClientContext } from "@orpc/client";
2
+ import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, ORPCErrorConstructorMap, ORPCErrorFromErrorMap } from "@orpc/contract";
3
+ import type { Interceptor, MaybeOptionalOptions, Promisable, PromiseWithError, ThrowableError, Value } from "@orpc/shared";
4
+ import type { Context } from "./context.mjs";
5
+ import type { Lazyable } from "./lazy.mjs";
6
+ import type { Procedure, ProcedureHandlerOptions } from "./procedure.mjs";
7
+ export type ProcedureClient<
8
+ TClientContext extends ClientContext,
9
+ TInputSchema extends AnySchema,
10
+ TOutputSchema extends AnySchema,
11
+ TErrorMap extends ErrorMap
12
+ > = Client<TClientContext, InferSchemaInput<TInputSchema>, InferSchemaOutput<TOutputSchema>, ORPCErrorFromErrorMap<TErrorMap> | ThrowableError>;
13
+ export interface ProcedureClientInterceptorOptions<
14
+ TInitialContext extends Context,
15
+ TErrorMap extends ErrorMap
16
+ > extends ProcedureHandlerOptions<TInitialContext, unknown, ORPCErrorConstructorMap<TErrorMap>> {}
17
+ export type ProcedureClientInterceptor<
18
+ TInitialContext extends Context,
19
+ TOutputSchema extends AnySchema,
20
+ TErrorMap extends ErrorMap
21
+ > = Interceptor<ProcedureClientInterceptorOptions<TInitialContext, TErrorMap>, PromiseWithError<InferSchemaOutput<TOutputSchema>, ORPCErrorFromErrorMap<TErrorMap> | ThrowableError>>;
22
+ export type ProcedureClientOptions<
23
+ TInitialContext extends Context,
24
+ TOutputSchema extends AnySchema,
25
+ TErrorMap extends ErrorMap,
26
+ TClientContext extends ClientContext
27
+ > = {
28
+ path?: string[] | undefined;
29
+ interceptors?: ProcedureClientInterceptor<TInitialContext, TOutputSchema, TErrorMap>[] | undefined;
30
+ } & (object extends TInitialContext ? {
31
+ context?: Value<Promisable<TInitialContext>, [clientContext: TClientContext]> | undefined;
32
+ } : {
33
+ context: Value<Promisable<TInitialContext>, [clientContext: TClientContext]>;
34
+ });
35
+ export declare function createProcedureClient<
36
+ TInitialContext extends Context,
37
+ TInputSchema extends AnySchema,
38
+ TOutputSchema extends AnySchema,
39
+ TErrorMap extends ErrorMap,
40
+ TClientContext extends ClientContext = object
41
+ >(lazyableProcedure: Lazyable<Procedure<TInitialContext, any, TInputSchema, TOutputSchema, TErrorMap>>, ...rest: MaybeOptionalOptions<ProcedureClientOptions<TInitialContext, TOutputSchema, TErrorMap, TClientContext>>): ProcedureClient<TClientContext, TInputSchema, TOutputSchema, TErrorMap>;
@@ -0,0 +1,157 @@
1
+ import { ORPCError, wrapAsyncIteratorPreservingEventMeta } from "@orpc/client";
2
+ import { createORPCErrorConstructorMap, reconcileORPCError, ValidationError } from "@orpc/contract";
3
+ import { getTracer, intercept, isAsyncIteratorObject, mergeTwoLevels, override, resolveMaybeOptionalOptions, runWithSpan, toArray, traceAsyncIterator, traceReadableStream, value } from "@orpc/shared";
4
+ import { unlazy } from "./lazy.mjs";
5
+ export function createProcedureClient(lazyableProcedure, ...rest) {
6
+ const options = resolveMaybeOptionalOptions(rest);
7
+ return async (...[input, callerOptions]) => {
8
+ const path = toArray(options.path);
9
+ const { default: procedure } = await unlazy(lazyableProcedure);
10
+
11
+ const clientContext = callerOptions?.context ?? {};
12
+
13
+ const context = await value(options.context, clientContext) ?? {};
14
+ const errors = createORPCErrorConstructorMap(procedure["~orpc"].errorMap);
15
+ const reconcileError = async (e) => {
16
+ if (e instanceof ORPCError) {
17
+ return await reconcileORPCError(procedure["~orpc"].errorMap, e);
18
+ }
19
+ return e;
20
+ };
21
+ try {
22
+ const output = await runWithSpan("call_procedure", (span) => {
23
+ span?.setAttribute("procedure.path", path);
24
+ return intercept(options.interceptors, {
25
+ context,
26
+
27
+ input,
28
+ errors,
29
+ path,
30
+ procedure,
31
+ signal: callerOptions?.signal,
32
+ lastEventId: callerOptions?.lastEventId
33
+ }, (interceptorOptions) => executeProcedureInternal(interceptorOptions.procedure, interceptorOptions));
34
+ });
35
+ if (isAsyncIteratorObject(output)) {
36
+
37
+ return override(output, wrapAsyncIteratorPreservingEventMeta(getTracer() ? traceAsyncIterator("consume_async_iterator_object_output", output) : output, { mapError: reconcileError }));
38
+ } else if (getTracer() && output instanceof ReadableStream) {
39
+
40
+ return override(output, traceReadableStream("consume_octet_stream_output", output));
41
+ }
42
+ return output;
43
+ } catch (e) {
44
+ throw await reconcileError(e);
45
+ }
46
+ };
47
+ }
48
+ async function validateInput(i, schema, input) {
49
+ return runWithSpan(`validate_input.${i}`, async (span) => {
50
+ span?.setAttribute("input_schema.index", i);
51
+ const result = await schema["~standard"].validate(input);
52
+ if (result.issues) {
53
+ throw new ORPCError("BAD_REQUEST", {
54
+ message: "Input validation failed",
55
+ data: { issues: result.issues },
56
+ cause: new ValidationError({
57
+ message: "Input validation failed",
58
+ issues: result.issues,
59
+ invalidData: input
60
+ })
61
+ });
62
+ }
63
+ return result.value;
64
+ });
65
+ }
66
+ async function validateOutput(i, schema, output) {
67
+ return runWithSpan(`validate_output.${i}`, async (span) => {
68
+ span?.setAttribute("output_schema.index", i);
69
+ const result = await schema["~standard"].validate(output);
70
+ if (result.issues) {
71
+ throw new ORPCError("INTERNAL_SERVER_ERROR", {
72
+ message: "Output validation failed",
73
+ cause: new ValidationError({
74
+ message: "Output validation failed",
75
+ issues: result.issues,
76
+ invalidData: output
77
+ })
78
+ });
79
+ }
80
+ return result.value;
81
+ });
82
+ }
83
+ const middlewareDone = (...rest) => {
84
+ const options = resolveMaybeOptionalOptions(rest);
85
+ return {
86
+ output: options.output,
87
+
88
+ context: options.context ?? {}
89
+ };
90
+ };
91
+ async function executeProcedureInternal(procedure, options) {
92
+ const inputSchemas = toArray(procedure["~orpc"].inputSchemas);
93
+ const outputSchemas = toArray(procedure["~orpc"].outputSchemas);
94
+ const orderedMiddlewares = procedure["~orpc"].orderedMiddlewares;
95
+ const next = async (midIndex, context, input, signal) => {
96
+ let currentInput = input;
97
+ let middlewareInput = input;
98
+ const startInputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].inputSchemasLengthAtUse ?? 0;
99
+ const endInputIndex = midIndex === orderedMiddlewares.length ? inputSchemas.length : orderedMiddlewares[midIndex].inputSchemasLengthAtUse ?? 0;
100
+
101
+ if (!procedure["~orpc"].disableInputValidation) {
102
+ for (let i = startInputIndex; i < endInputIndex; i++) {
103
+ const validated = await validateInput(i, inputSchemas[i], i !== 0 ? mergeTwoLevels(options.input, currentInput) : currentInput);
104
+ currentInput = i !== 0 ? mergeTwoLevels(currentInput, validated) : validated;
105
+ }
106
+ middlewareInput = endInputIndex > 0 && endInputIndex < inputSchemas.length ? mergeTwoLevels(options.input, currentInput) : currentInput;
107
+ }
108
+ let currentOutput;
109
+ let currentContext = context;
110
+ if (midIndex < orderedMiddlewares.length) {
111
+ const { middleware } = orderedMiddlewares[midIndex];
112
+ const result = await runWithSpan(`middleware.${middleware.name}`, async (span) => {
113
+ span?.setAttribute("middleware.index", midIndex);
114
+ return await middleware({
115
+ ...options,
116
+ context,
117
+ signal,
118
+ next: (...rest) => {
119
+ const nextOptions = resolveMaybeOptionalOptions(rest);
120
+
121
+ const nextContext = nextOptions.context ?? {};
122
+ return next(midIndex + 1, {
123
+ ...context,
124
+ ...nextContext
125
+ }, currentInput, nextOptions.signal ?? signal);
126
+ },
127
+ lastEventId: options.lastEventId
128
+ }, middlewareInput, middlewareDone);
129
+ });
130
+ currentOutput = result.output;
131
+ currentContext = {
132
+ ...context,
133
+ ...result.context
134
+ };
135
+ } else {
136
+ currentOutput = await runWithSpan("handler", () => procedure["~orpc"].handler({
137
+ ...options,
138
+ context,
139
+ input: currentInput,
140
+ signal
141
+ }, currentInput));
142
+ }
143
+ const startOutputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].outputSchemasLengthAtUse ?? 0;
144
+ const endOutputIndex = midIndex === orderedMiddlewares.length ? outputSchemas.length : orderedMiddlewares[midIndex].outputSchemasLengthAtUse ?? 0;
145
+ if (!procedure["~orpc"].disableOutputValidation) {
146
+ for (let i = endOutputIndex - 1; i >= startOutputIndex; i--) {
147
+ currentOutput = await validateOutput(i, outputSchemas[i], currentOutput);
148
+ }
149
+ }
150
+ return {
151
+ output: currentOutput,
152
+ context: currentContext
153
+ };
154
+ };
155
+ const { output } = await next(0, options.context, options.input, options.signal);
156
+ return output;
157
+ }
@@ -0,0 +1,20 @@
1
+ import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MergedErrorMap, MetaPlugin } from "@orpc/contract";
2
+ import type { IntersectPick } from "@orpc/shared";
3
+ import type { Context, MergedContext, MergedInitialContext } from "./context.mjs";
4
+ import type { Middleware } from "./middleware.mjs";
5
+ import { Procedure } from "./procedure.mjs";
6
+ export declare class DecoratedProcedure<
7
+ TInitialContext extends Context,
8
+ TInjectedContext extends Context,
9
+ TInputSchema extends AnySchema,
10
+ TOutputSchema extends AnySchema,
11
+ TErrorMap extends ErrorMap
12
+ > extends Procedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap> {
13
+ meta(...plugins: MetaPlugin<TInputSchema, TOutputSchema, TErrorMap>[]): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
14
+ errors<T extends ErrorMap>(errors: T): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, MergedErrorMap<TErrorMap, T>>;
15
+ use<
16
+ $OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>,
17
+ $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>,
18
+ $ErrorMap extends ErrorMap = TErrorMap
19
+ >(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, InferSchemaOutput<TInputSchema>, InferSchemaInput<TOutputSchema>, $ErrorMap>): DecoratedProcedure<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, TInputSchema, TOutputSchema, MergedErrorMap<$ErrorMap, TErrorMap>>;
20
+ }
@@ -0,0 +1,41 @@
1
+ import { getHiddenMetaPlugins, mergeErrorMap, resolveMetaPlugins } from "@orpc/contract";
2
+ import { Procedure } from "./procedure.mjs";
3
+ export class DecoratedProcedure extends Procedure {
4
+ meta(...plugins) {
5
+ const [meta, metaPlugins] = resolveMetaPlugins(this["~orpc"].meta, this["~orpc"].metaPlugins, plugins);
6
+ return new DecoratedProcedure({
7
+ ...this["~orpc"],
8
+ meta,
9
+ metaPlugins
10
+ });
11
+ }
12
+ errors(errors) {
13
+ let procedure = new DecoratedProcedure({
14
+ ...this["~orpc"],
15
+ errorMap: mergeErrorMap(this["~orpc"].errorMap, errors)
16
+ });
17
+ const plugins = getHiddenMetaPlugins(errors);
18
+ if (plugins) {
19
+ procedure = procedure.meta(...plugins);
20
+ }
21
+ return procedure;
22
+ }
23
+ use(middleware) {
24
+
25
+
26
+
27
+ let procedure = new DecoratedProcedure({
28
+ ...this["~orpc"],
29
+ errorMap: mergeErrorMap(middleware["~orpc"]?.errorMap, this["~orpc"].errorMap),
30
+ orderedMiddlewares: [...this["~orpc"].orderedMiddlewares, {
31
+ middleware,
32
+ inputSchemasLengthAtUse: this["~orpc"].inputSchemas?.length,
33
+ outputSchemasLengthAtUse: this["~orpc"].outputSchemas?.length
34
+ }]
35
+ });
36
+ if (middleware["~orpc"]?.metaPlugins) {
37
+ procedure = procedure.meta(...middleware["~orpc"]?.metaPlugins);
38
+ }
39
+ return procedure;
40
+ }
41
+ }
@@ -0,0 +1,52 @@
1
+ import type { ClientOptions } from "@orpc/client";
2
+ import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, ORPCErrorFromErrorMap, ProcedureContract } from "@orpc/contract";
3
+ import type { PromiseWithError, ThrowableError } from "@orpc/shared";
4
+ import type { Context } from "./context.mjs";
5
+ import type { Lazyable } from "./lazy.mjs";
6
+ import type { AnyProcedure } from "./procedure.mjs";
7
+ import type { ProcedureClientOptions } from "./procedure-client.mjs";
8
+ import { Lazy } from "./lazy.mjs";
9
+ import { Procedure } from "./procedure.mjs";
10
+ export declare function createGuardedProcedureLazy(lazy: Lazy<unknown>): Lazy<AnyProcedure>;
11
+ /**
12
+ * Create a new procedure that ensure the contract is applied to the procedure.
13
+ *
14
+ * .input/.output/.handler mismatches are already caught by the `implementer.router`,
15
+ * but .errors (in case implemented procedure error map is more than enough) and .meta cannot be
16
+ * validated that way - so they must be overridden here to ensure the client always sees what the contract defines.
17
+ */
18
+ export declare function createContractProcedure<
19
+ TInitialContext extends Context,
20
+ TInjectedContext extends Context,
21
+ TInputSchema extends AnySchema,
22
+ TOutputSchema extends AnySchema,
23
+ TErrorMap extends ErrorMap
24
+ >(procedure: Procedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, any>, contract: ProcedureContract<any, any, TErrorMap>): Procedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
25
+ export type CallOptions<
26
+ TInitialContext extends Context,
27
+ TOutputSchema extends AnySchema,
28
+ TErrorMap extends ErrorMap
29
+ > = ProcedureClientOptions<TInitialContext, TOutputSchema, TErrorMap, object> & Omit<ClientOptions<object>, "context">;
30
+ export type CallRest<
31
+ TInitialContext extends Context,
32
+ TInputSchema extends AnySchema,
33
+ TOutputSchema extends AnySchema,
34
+ TErrorMap extends ErrorMap
35
+ > = object extends CallOptions<TInitialContext, TOutputSchema, TErrorMap> ? undefined extends InferSchemaInput<TInputSchema> ? [input?: InferSchemaInput<TInputSchema>, options?: CallOptions<TInitialContext, TOutputSchema, TErrorMap>] : [input: InferSchemaInput<TInputSchema>, options?: CallOptions<TInitialContext, TOutputSchema, TErrorMap>] : [input: InferSchemaInput<TInputSchema>, options: CallOptions<TInitialContext, TOutputSchema, TErrorMap>];
36
+ /**
37
+ * Quickly call a procedure without creating a client.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const output = await call(getting, 'input')
42
+ * const output = await call(getting, 'input', { context: { db: 'postgres' } })
43
+ * ```
44
+ *
45
+ * @see {@link https://orpc.dev/docs/client/server-side#one-off-calls | Server-Side Clients - One-Off Calls}
46
+ */
47
+ export declare function call<
48
+ TInitialContext extends Context,
49
+ TInputSchema extends AnySchema,
50
+ TOutputSchema extends AnySchema,
51
+ TErrorMap extends ErrorMap
52
+ >(lazyableProcedure: Lazyable<Procedure<TInitialContext, any, TInputSchema, TOutputSchema, TErrorMap>>, ...[input, options]: CallRest<TInitialContext, TInputSchema, TOutputSchema, TErrorMap>): PromiseWithError<InferSchemaOutput<TOutputSchema>, ORPCErrorFromErrorMap<TErrorMap> | ThrowableError>;
@@ -0,0 +1,33 @@
1
+ import { Lazy, unlazy } from "./lazy.mjs";
2
+ import { Procedure } from "./procedure.mjs";
3
+ import { createProcedureClient } from "./procedure-client.mjs";
4
+ export function createGuardedProcedureLazy(lazy) {
5
+ const guarded = new Lazy({
6
+ ...lazy["~orpc"],
7
+ async loader() {
8
+ const { default: maybeProcedure } = await unlazy(lazy);
9
+ if (!(maybeProcedure instanceof Procedure)) {
10
+ throw new TypeError(`
11
+ Expected a lazy<procedure> but got lazy<unknown>.
12
+ This should be caught by TypeScript compilation.
13
+ Please report this issue if you think this is a bug.
14
+ `);
15
+ }
16
+ return { default: maybeProcedure };
17
+ }
18
+ });
19
+ return guarded;
20
+ }
21
+
22
+ export function createContractProcedure(procedure, contract) {
23
+ return new Procedure({
24
+ ...procedure["~orpc"],
25
+ errorMap: contract["~orpc"].errorMap,
26
+ meta: contract["~orpc"].meta,
27
+ metaPlugins: contract["~orpc"].metaPlugins
28
+ });
29
+ }
30
+
31
+ export function call(lazyableProcedure, ...[input = undefined, options = {}]) {
32
+ return createProcedureClient(lazyableProcedure, options)(input, options);
33
+ }
@@ -0,0 +1,93 @@
1
+ import type { AnySchema, ErrorMap, ORPCErrorConstructorMap, ProcedureContractDefinition } from "@orpc/contract";
2
+ import type { Promisable } from "@orpc/shared";
3
+ import type { Context } from "./context.mjs";
4
+ import type { AnyMiddleware } from "./middleware.mjs";
5
+ export interface ProcedureHandlerOptions<
6
+ TCurrentContext extends Context,
7
+ TInput,
8
+ TErrorConstructorMap extends ORPCErrorConstructorMap<any>
9
+ > {
10
+ context: TCurrentContext;
11
+ input: TInput;
12
+ path: string[];
13
+ procedure: Procedure<Context, Context, AnySchema, AnySchema, ErrorMap>;
14
+ signal?: AbortSignal | undefined;
15
+ lastEventId?: string | undefined;
16
+ errors: TErrorConstructorMap;
17
+ }
18
+ export interface ProcedureHandler<
19
+ TCurrentContext extends Context,
20
+ TInput,
21
+ THandlerOutput,
22
+ TErrorConstructorMap extends ORPCErrorConstructorMap<any>
23
+ > {
24
+ (opts: ProcedureHandlerOptions<TCurrentContext, TInput, TErrorConstructorMap>, input: TInput): Promisable<THandlerOutput>;
25
+ }
26
+ export interface OrderedMiddleware {
27
+ /**
28
+ * Snapshot of `inputSchemas.length`
29
+ * at the time this middleware was used.
30
+ *
31
+ * @default 0
32
+ */
33
+ inputSchemasLengthAtUse?: number | undefined;
34
+ /**
35
+ * Snapshot of `outputSchemas.length`
36
+ * at the time this middleware was used.
37
+ *
38
+ * @default 0
39
+ */
40
+ outputSchemasLengthAtUse?: number | undefined;
41
+ middleware: AnyMiddleware;
42
+ }
43
+ export interface ProcedureConfig {
44
+ /**
45
+ * When enabled, input schemas are not validated at runtime.
46
+ * Schemas are still used for type inference and OpenAPI generation.
47
+ *
48
+ * @remarks
49
+ * **Warning**: Do not disable validation for schemas that transform values.
50
+ *
51
+ * @default false
52
+ */
53
+ disableInputValidation?: boolean | undefined;
54
+ /**
55
+ * When enabled, output schemas are not validated at runtime.
56
+ * Schemas are still used for type inference and OpenAPI generation.
57
+ *
58
+ * Useful when output schemas exist only for specification generation.
59
+ *
60
+ * @remarks
61
+ * **Warning**: Do not disable validation for schemas that transform values.
62
+ *
63
+ * @default false
64
+ */
65
+ disableOutputValidation?: boolean | undefined;
66
+ }
67
+ export interface ProcedureDefinition<
68
+ TInitialContext extends Context,
69
+ TInjectedContext extends Context,
70
+ TInputSchema extends AnySchema,
71
+ TOutputSchema extends AnySchema,
72
+ TErrorMap extends ErrorMap
73
+ > extends ProcedureContractDefinition<TInputSchema, TOutputSchema, TErrorMap>, ProcedureConfig {
74
+ __TInitialContext?: (type: TInitialContext) => unknown;
75
+ __TInjectedContext?: (type: TInjectedContext) => unknown;
76
+ orderedMiddlewares: OrderedMiddleware[];
77
+ handler: ProcedureHandler<any, any, any, any>;
78
+ }
79
+ export declare class Procedure<
80
+ TInitialContext extends Context,
81
+ TInjectedContext extends Context,
82
+ TInputSchema extends AnySchema,
83
+ TOutputSchema extends AnySchema,
84
+ TErrorMap extends ErrorMap
85
+ > {
86
+ "~orpc": ProcedureDefinition<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
87
+ constructor(def: ProcedureDefinition<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>);
88
+ /**
89
+ * Checks if the given instance satisfies the {@link Procedure} class/interface.
90
+ */
91
+ static [Symbol.hasInstance](instance: unknown): boolean;
92
+ }
93
+ export type AnyProcedure = Procedure<any, any, any, any, any>;
@@ -0,0 +1,20 @@
1
+ import { ProcedureContract } from "@orpc/contract";
2
+ import { getConstructor } from "@orpc/shared";
3
+ export class Procedure {
4
+ "~orpc";
5
+ constructor(def) {
6
+ this["~orpc"] = def;
7
+ }
8
+
9
+ static [Symbol.hasInstance](instance) {
10
+ if (this !== Procedure) {
11
+
12
+ return Function.prototype[Symbol.hasInstance].call(this, instance);
13
+ }
14
+ const constructor = getConstructor(instance);
15
+ if (constructor === Procedure) {
16
+ return true;
17
+ }
18
+ return instance instanceof ProcedureContract && Array.isArray(instance["~orpc"].orderedMiddlewares) && typeof instance["~orpc"].handler === "function";
19
+ }
20
+ }