@orpc/server 2.0.0-beta.5 → 2.0.0-beta.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -102
- package/dist/adapters/aws-lambda/handler.d.ts +27 -0
- package/dist/adapters/aws-lambda/handler.js +24 -0
- package/dist/adapters/aws-lambda/index.d.ts +4 -0
- package/dist/adapters/aws-lambda/index.js +2 -0
- package/dist/adapters/aws-lambda/rpc-handler.d.ts +19 -0
- package/dist/adapters/aws-lambda/rpc-handler.js +21 -0
- package/dist/adapters/crossws/handler.d.ts +47 -0
- package/dist/adapters/crossws/handler.js +53 -0
- package/dist/adapters/crossws/index.d.ts +3 -54
- package/dist/adapters/crossws/index.js +2 -0
- package/dist/adapters/crossws/rpc-handler.d.ts +16 -0
- package/dist/adapters/crossws/rpc-handler.js +18 -0
- package/dist/adapters/fastify/handler.d.ts +23 -0
- package/dist/adapters/fastify/handler.js +20 -0
- package/dist/adapters/fastify/index.d.ts +3 -0
- package/dist/adapters/fastify/index.js +2 -0
- package/dist/adapters/fastify/rpc-handler.d.ts +15 -0
- package/dist/adapters/fastify/rpc-handler.js +17 -0
- package/dist/adapters/fetch/handler.d.ts +25 -0
- package/dist/adapters/fetch/handler.js +22 -0
- package/dist/adapters/fetch/index.d.ts +4 -140
- package/dist/adapters/fetch/index.js +3 -0
- package/dist/adapters/fetch/rpc-handler.d.ts +17 -0
- package/dist/adapters/fetch/rpc-handler.js +19 -0
- package/dist/adapters/message-port/handler.d.ts +62 -0
- package/dist/adapters/message-port/handler.js +72 -0
- package/dist/adapters/message-port/index.d.ts +3 -74
- package/dist/adapters/message-port/index.js +2 -0
- package/dist/adapters/message-port/rpc-handler.d.ts +16 -0
- package/dist/adapters/message-port/rpc-handler.js +18 -0
- package/dist/adapters/node/handler.d.ts +23 -0
- package/dist/adapters/node/handler.js +20 -0
- package/dist/adapters/node/index.d.ts +4 -121
- package/dist/adapters/node/index.js +3 -0
- package/dist/adapters/node/rpc-handler.d.ts +16 -0
- package/dist/adapters/node/rpc-handler.js +18 -0
- package/dist/adapters/standard/codec.d.ts +16 -0
- package/dist/adapters/standard/handler.d.ts +68 -0
- package/dist/adapters/standard/handler.js +205 -0
- package/dist/adapters/standard/index.d.ts +7 -19
- package/dist/adapters/standard/index.js +4 -0
- package/dist/adapters/standard/plugin.d.ts +26 -0
- package/dist/adapters/standard/plugin.js +14 -0
- package/dist/adapters/standard/rpc-handler-codec.d.ts +42 -0
- package/dist/adapters/standard/rpc-handler-codec.js +50 -0
- package/dist/adapters/standard/rpc-matcher.d.ts +53 -0
- package/dist/adapters/standard/rpc-matcher.js +106 -0
- package/dist/adapters/standard/utils.d.ts +10 -0
- package/dist/adapters/standard/utils.js +8 -0
- package/dist/adapters/standard-peer/index.d.ts +2 -16
- package/dist/adapters/standard-peer/index.js +1 -0
- package/dist/adapters/standard-peer/utils.d.ts +6 -0
- package/dist/adapters/standard-peer/utils.js +13 -0
- package/dist/adapters/websocket/handler.d.ts +61 -0
- package/dist/adapters/websocket/handler.js +75 -0
- package/dist/adapters/websocket/index.d.ts +3 -61
- package/dist/adapters/websocket/index.js +2 -0
- package/dist/adapters/websocket/rpc-handler.d.ts +16 -0
- package/dist/adapters/websocket/rpc-handler.js +18 -0
- package/dist/builder-variants.d.ts +226 -0
- package/dist/builder.d.ts +126 -0
- package/dist/builder.js +200 -0
- package/dist/constants.d.ts +2 -0
- package/dist/constants.js +4 -0
- package/dist/context.d.ts +6 -0
- package/dist/extensions/callable.d.ts +11 -10
- package/dist/extensions/callable.js +8 -0
- package/dist/helpers/base64url.d.ts +31 -0
- package/dist/helpers/base64url.js +48 -0
- package/dist/helpers/cookie.d.ts +50 -0
- package/dist/helpers/cookie.js +62 -0
- package/dist/helpers/encryption.d.ts +28 -0
- package/dist/helpers/encryption.js +90 -0
- package/dist/helpers/index.d.ts +5 -149
- package/dist/helpers/index.js +4 -0
- package/dist/helpers/signing.d.ts +50 -0
- package/dist/helpers/signing.js +78 -0
- package/dist/implementer-procedure.d.ts +15 -0
- package/dist/implementer-procedure.js +37 -0
- package/dist/implementer-router.d.ts +34 -0
- package/dist/implementer-router.js +98 -0
- package/dist/implementer.d.ts +16 -0
- package/dist/implementer.js +30 -0
- package/dist/index.d.ts +22 -196
- package/dist/index.js +16 -0
- package/dist/lazy.d.ts +20 -0
- package/dist/lazy.js +20 -0
- package/dist/middleware-decorated.d.ts +9 -0
- package/dist/middleware-decorated.js +67 -0
- package/dist/middleware.d.ts +54 -0
- package/dist/plugins/batch.d.ts +102 -0
- package/dist/plugins/batch.js +371 -0
- package/dist/plugins/cors.d.ts +69 -0
- package/dist/plugins/cors.js +119 -0
- package/dist/plugins/get-method-csrf-protection.d.ts +25 -0
- package/dist/plugins/get-method-csrf-protection.js +48 -0
- package/dist/plugins/head-method.d.ts +25 -0
- package/dist/plugins/head-method.js +107 -0
- package/dist/plugins/index.d.ts +15 -197
- package/dist/plugins/index.js +14 -0
- package/dist/plugins/method-override.d.ts +40 -0
- package/dist/plugins/method-override.js +54 -0
- package/dist/plugins/request-compression.d.ts +18 -0
- package/dist/plugins/request-compression.js +55 -0
- package/dist/plugins/request-headers.d.ts +24 -0
- package/dist/plugins/request-headers.js +28 -0
- package/dist/plugins/request-limit.d.ts +32 -0
- package/dist/plugins/request-limit.js +61 -0
- package/dist/plugins/response-compression.d.ts +62 -0
- package/dist/plugins/response-compression.js +157 -0
- package/dist/plugins/response-headers.d.ts +32 -0
- package/dist/plugins/response-headers.js +44 -0
- package/dist/plugins/rethrow.d.ts +35 -0
- package/dist/plugins/rethrow.js +47 -0
- package/dist/plugins/signal-sync.d.ts +15 -0
- package/dist/plugins/signal-sync.js +76 -0
- package/dist/plugins/timeout.d.ts +39 -0
- package/dist/plugins/timeout.js +62 -0
- package/dist/procedure-client.d.ts +18 -0
- package/dist/procedure-client.js +158 -0
- package/dist/procedure-decorated.d.ts +10 -0
- package/dist/procedure-decorated.js +36 -0
- package/dist/procedure-utils.d.ts +21 -0
- package/dist/procedure-utils.js +48 -0
- package/dist/procedure.d.ts +72 -0
- package/dist/procedure.js +18 -0
- package/dist/router-client.d.ts +21 -0
- package/dist/router-client.js +35 -0
- package/dist/router-hidden.js +12 -0
- package/dist/router-utils.d.ts +31 -0
- package/dist/router-utils.js +157 -0
- package/dist/router.d.ts +58 -0
- package/package.json +95 -63
- package/dist/adapters/crossws/index.d.mts +0 -54
- package/dist/adapters/crossws/index.mjs +0 -64
- package/dist/adapters/fetch/index.d.mts +0 -140
- package/dist/adapters/fetch/index.mjs +0 -204
- package/dist/adapters/message-port/index.d.mts +0 -74
- package/dist/adapters/message-port/index.mjs +0 -90
- package/dist/adapters/node/index.d.mts +0 -121
- package/dist/adapters/node/index.mjs +0 -179
- package/dist/adapters/standard/index.d.mts +0 -19
- package/dist/adapters/standard/index.mjs +0 -8
- package/dist/adapters/standard-peer/index.d.mts +0 -16
- package/dist/adapters/standard-peer/index.mjs +0 -2
- package/dist/adapters/websocket/index.d.mts +0 -61
- package/dist/adapters/websocket/index.mjs +0 -76
- package/dist/extensions/callable.d.mts +0 -10
- package/dist/extensions/callable.mjs +0 -11
- package/dist/helpers/index.d.mts +0 -149
- package/dist/helpers/index.mjs +0 -198
- package/dist/index.d.mts +0 -196
- package/dist/index.mjs +0 -385
- package/dist/plugins/index.d.mts +0 -197
- package/dist/plugins/index.mjs +0 -357
- package/dist/shared/server.BL22TloH.d.mts +0 -184
- package/dist/shared/server.BL22TloH.d.ts +0 -184
- package/dist/shared/server.BsNNjG5J.d.mts +0 -61
- package/dist/shared/server.BwHnWUuN.mjs +0 -222
- package/dist/shared/server.CX4vUnDk.mjs +0 -11
- package/dist/shared/server.Cj5lgPuG.d.mts +0 -66
- package/dist/shared/server.CjOb6ItT.mjs +0 -41
- package/dist/shared/server.CrlKQucM.mjs +0 -233
- package/dist/shared/server.DBANIheG.d.ts +0 -104
- package/dist/shared/server.DJIkub_t.d.mts +0 -104
- package/dist/shared/server.D_QauotT.mjs +0 -30
- package/dist/shared/server.GDpX6Df8.mjs +0 -271
- package/dist/shared/server.Pa0F03f_.d.ts +0 -61
- package/dist/shared/server.W91HSRkE.mjs +0 -9
- package/dist/shared/server.d_2NS3g5.d.ts +0 -66
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { unlazy } from "./lazy.js";
|
|
2
|
+
import { ValidationError, createORPCErrorConstructorMap, reconcileORPCError } from "@orpc/contract";
|
|
3
|
+
import { getTracer, intercept, isAsyncIteratorObject, mergeTwoLevels, override, resolveMaybeOptionalOptions, runWithSpan, toArray, traceAsyncIterator, traceReadableStream, value } from "@orpc/shared";
|
|
4
|
+
import { ORPCError, wrapAsyncIteratorPreservingEventMeta } from "@orpc/client";
|
|
5
|
+
// src/procedure-client.ts
|
|
6
|
+
function createProcedureClient(lazyableProcedure, ...rest) {
|
|
7
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
8
|
+
return async (...[input, callerOptions]) => {
|
|
9
|
+
const path = toArray(options.path);
|
|
10
|
+
const { default: procedure } = await unlazy(lazyableProcedure);
|
|
11
|
+
const clientContext = callerOptions?.context ?? {};
|
|
12
|
+
const context = await value(options.context, clientContext) ?? {};
|
|
13
|
+
const errors = createORPCErrorConstructorMap(procedure["~orpc"].errorMap);
|
|
14
|
+
const reconcileError = async (e) => {
|
|
15
|
+
if (e instanceof ORPCError) return await reconcileORPCError(procedure["~orpc"].errorMap, e);
|
|
16
|
+
return e;
|
|
17
|
+
};
|
|
18
|
+
try {
|
|
19
|
+
const output = await runWithSpan("call_procedure", (span) => {
|
|
20
|
+
span?.setAttribute("procedure.path", path);
|
|
21
|
+
return intercept(options.interceptors, {
|
|
22
|
+
context,
|
|
23
|
+
input,
|
|
24
|
+
errors,
|
|
25
|
+
path,
|
|
26
|
+
procedure,
|
|
27
|
+
signal: callerOptions?.signal,
|
|
28
|
+
lastEventId: callerOptions?.lastEventId
|
|
29
|
+
}, (interceptorOptions) => executeProcedureInternal(interceptorOptions.procedure, interceptorOptions));
|
|
30
|
+
});
|
|
31
|
+
if (isAsyncIteratorObject(output))
|
|
32
|
+
/**
|
|
33
|
+
* traceAsyncIterator/wrapAsyncIteratorPreservingEventMeta return AsyncIteratorClass
|
|
34
|
+
* which is backwards compatible with AsyncIteratorObject.
|
|
35
|
+
*
|
|
36
|
+
* @warning
|
|
37
|
+
* If remove this return, can be breaking change
|
|
38
|
+
* because AsyncIteratorClass convert `.throw` to `.return` (rarely used)
|
|
39
|
+
*
|
|
40
|
+
* @warning
|
|
41
|
+
* Remember use `override` for AsyncIteratorObject to remain other special properties
|
|
42
|
+
*/
|
|
43
|
+
return override(output, wrapAsyncIteratorPreservingEventMeta(getTracer() ? traceAsyncIterator("consume_async_iterator_object_output", output) : output, { mapError: reconcileError }));
|
|
44
|
+
else if (getTracer() && output instanceof ReadableStream)
|
|
45
|
+
/**
|
|
46
|
+
* @warning
|
|
47
|
+
* Remember use `override` for ReadableStream to remain other special properties
|
|
48
|
+
*/
|
|
49
|
+
return override(output, traceReadableStream("consume_octet_stream_output", output));
|
|
50
|
+
return output;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
throw await reconcileError(e);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function validateInput(i, schema, input) {
|
|
57
|
+
return runWithSpan(`validate_input.${i}`, async (span) => {
|
|
58
|
+
span?.setAttribute("input_schema.index", i);
|
|
59
|
+
const result = await schema["~standard"].validate(input);
|
|
60
|
+
if (result.issues) throw new ORPCError("BAD_REQUEST", {
|
|
61
|
+
message: "Input validation failed",
|
|
62
|
+
data: { issues: result.issues },
|
|
63
|
+
cause: new ValidationError({
|
|
64
|
+
message: "Input validation failed",
|
|
65
|
+
issues: result.issues,
|
|
66
|
+
invalidData: input
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
return result.value;
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function validateOutput(i, schema, output) {
|
|
73
|
+
return runWithSpan(`validate_output.${i}`, async (span) => {
|
|
74
|
+
span?.setAttribute("output_schema.index", i);
|
|
75
|
+
const result = await schema["~standard"].validate(output);
|
|
76
|
+
if (result.issues) throw new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
77
|
+
message: "Output validation failed",
|
|
78
|
+
cause: new ValidationError({
|
|
79
|
+
message: "Output validation failed",
|
|
80
|
+
issues: result.issues,
|
|
81
|
+
invalidData: output
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
return result.value;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const middlewareDone = (...rest) => {
|
|
88
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
89
|
+
return {
|
|
90
|
+
output: options.output,
|
|
91
|
+
context: options.context ?? {}
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
async function executeProcedureInternal(procedure, options) {
|
|
95
|
+
const inputSchemas = toArray(procedure["~orpc"].inputSchemas);
|
|
96
|
+
const outputSchemas = toArray(procedure["~orpc"].outputSchemas);
|
|
97
|
+
const orderedMiddlewares = procedure["~orpc"].orderedMiddlewares;
|
|
98
|
+
const next = async (midIndex, context, input, signal) => {
|
|
99
|
+
let currentInput = input;
|
|
100
|
+
let middlewareInput = input;
|
|
101
|
+
const startInputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].inputSchemasLengthAtUse ?? 0;
|
|
102
|
+
const endInputIndex = midIndex === orderedMiddlewares.length ? inputSchemas.length : orderedMiddlewares[midIndex].inputSchemasLengthAtUse ?? 0;
|
|
103
|
+
/**
|
|
104
|
+
* Each schema after the first validates the original input with the results so far applied, then
|
|
105
|
+
* its result is merged in, so no schema loses a field an earlier one stripped. Values that are not
|
|
106
|
+
* plain objects stay piped, which keeps schemas like `asyncIteratorObject` wrapping each other.
|
|
107
|
+
*/
|
|
108
|
+
if (!procedure["~orpc"].disableInputValidation) {
|
|
109
|
+
for (let i = startInputIndex; i < endInputIndex; i++) {
|
|
110
|
+
const validated = await validateInput(i, inputSchemas[i], i !== 0 ? mergeTwoLevels(options.input, currentInput) : currentInput);
|
|
111
|
+
currentInput = i !== 0 ? mergeTwoLevels(currentInput, validated) : validated;
|
|
112
|
+
}
|
|
113
|
+
middlewareInput = endInputIndex > 0 && endInputIndex < inputSchemas.length ? mergeTwoLevels(options.input, currentInput) : currentInput;
|
|
114
|
+
}
|
|
115
|
+
let currentOutput;
|
|
116
|
+
let currentContext = context;
|
|
117
|
+
if (midIndex < orderedMiddlewares.length) {
|
|
118
|
+
const { middleware } = orderedMiddlewares[midIndex];
|
|
119
|
+
const result = await runWithSpan(`middleware.${middleware.name}`, async (span) => {
|
|
120
|
+
span?.setAttribute("middleware.index", midIndex);
|
|
121
|
+
return await middleware({
|
|
122
|
+
...options,
|
|
123
|
+
context,
|
|
124
|
+
signal,
|
|
125
|
+
next: (...rest) => {
|
|
126
|
+
const nextOptions = resolveMaybeOptionalOptions(rest);
|
|
127
|
+
const nextContext = nextOptions.context ?? {};
|
|
128
|
+
return next(midIndex + 1, {
|
|
129
|
+
...context,
|
|
130
|
+
...nextContext
|
|
131
|
+
}, currentInput, nextOptions.signal ?? signal);
|
|
132
|
+
},
|
|
133
|
+
lastEventId: options.lastEventId
|
|
134
|
+
}, middlewareInput, middlewareDone);
|
|
135
|
+
});
|
|
136
|
+
currentOutput = result.output;
|
|
137
|
+
currentContext = {
|
|
138
|
+
...context,
|
|
139
|
+
...result.context
|
|
140
|
+
};
|
|
141
|
+
} else currentOutput = await runWithSpan("handler", () => procedure["~orpc"].handler({
|
|
142
|
+
...options,
|
|
143
|
+
context,
|
|
144
|
+
input: currentInput,
|
|
145
|
+
signal
|
|
146
|
+
}, currentInput));
|
|
147
|
+
const startOutputIndex = midIndex === 0 ? 0 : orderedMiddlewares[midIndex - 1].outputSchemasLengthAtUse ?? 0;
|
|
148
|
+
const endOutputIndex = midIndex === orderedMiddlewares.length ? outputSchemas.length : orderedMiddlewares[midIndex].outputSchemasLengthAtUse ?? 0;
|
|
149
|
+
if (!procedure["~orpc"].disableOutputValidation) for (let i = endOutputIndex - 1; i >= startOutputIndex; i--) currentOutput = await validateOutput(i, outputSchemas[i], currentOutput);
|
|
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
|
+
}
|
|
158
|
+
export { createProcedureClient };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Context, MergedContext, MergedInitialContext } from "./context.js";
|
|
2
|
+
import { Middleware } from "./middleware.js";
|
|
3
|
+
import { Procedure } from "./procedure.js";
|
|
4
|
+
import { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MergedErrorMap, MetaPlugin } from "@orpc/contract";
|
|
5
|
+
import { IntersectPick } from "@orpc/shared";
|
|
6
|
+
export declare class DecoratedProcedure<TInitialContext extends Context, TInjectedContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends Procedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap> {
|
|
7
|
+
meta(...plugins: MetaPlugin<TInputSchema, TOutputSchema, TErrorMap>[]): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
|
|
8
|
+
errors<T extends ErrorMap>(errors: T): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, MergedErrorMap<TErrorMap, T>>;
|
|
9
|
+
use<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $ErrorMap extends ErrorMap = TErrorMap>(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>>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Procedure } from "./procedure.js";
|
|
2
|
+
import { getHiddenMetaPlugins, mergeErrorMap, resolveMetaPlugins } from "@orpc/contract";
|
|
3
|
+
// src/procedure-decorated.ts
|
|
4
|
+
var DecoratedProcedure = class DecoratedProcedure extends Procedure {
|
|
5
|
+
meta(...plugins) {
|
|
6
|
+
const [meta, metaPlugins] = resolveMetaPlugins(this["~orpc"].meta, this["~orpc"].metaPlugins, plugins);
|
|
7
|
+
return new DecoratedProcedure({
|
|
8
|
+
...this["~orpc"],
|
|
9
|
+
meta,
|
|
10
|
+
metaPlugins
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
errors(errors) {
|
|
14
|
+
let procedure = new DecoratedProcedure({
|
|
15
|
+
...this["~orpc"],
|
|
16
|
+
errorMap: mergeErrorMap(this["~orpc"].errorMap, errors)
|
|
17
|
+
});
|
|
18
|
+
const plugins = getHiddenMetaPlugins(errors);
|
|
19
|
+
if (plugins) procedure = procedure.meta(...plugins);
|
|
20
|
+
return procedure;
|
|
21
|
+
}
|
|
22
|
+
use(middleware) {
|
|
23
|
+
let procedure = new DecoratedProcedure({
|
|
24
|
+
...this["~orpc"],
|
|
25
|
+
errorMap: mergeErrorMap(middleware["~orpc"]?.errorMap, this["~orpc"].errorMap),
|
|
26
|
+
orderedMiddlewares: [...this["~orpc"].orderedMiddlewares, {
|
|
27
|
+
middleware,
|
|
28
|
+
inputSchemasLengthAtUse: this["~orpc"].inputSchemas?.length,
|
|
29
|
+
outputSchemasLengthAtUse: this["~orpc"].outputSchemas?.length
|
|
30
|
+
}]
|
|
31
|
+
});
|
|
32
|
+
if (middleware["~orpc"]?.metaPlugins) procedure = procedure.meta(...middleware["~orpc"]?.metaPlugins);
|
|
33
|
+
return procedure;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export { DecoratedProcedure };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Context } from "./context.js";
|
|
2
|
+
import { Lazyable } from "./lazy.js";
|
|
3
|
+
import { Procedure } from "./procedure.js";
|
|
4
|
+
import { ProcedureClientOptions } from "./procedure-client.js";
|
|
5
|
+
import { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, ORPCErrorFromErrorMap } from "@orpc/contract";
|
|
6
|
+
import { PromiseWithError, ThrowableError as ThrowableError$1 } from "@orpc/shared";
|
|
7
|
+
import { ClientOptions } from "@orpc/client";
|
|
8
|
+
export type CallOptions<TInitialContext extends Context, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> = ProcedureClientOptions<TInitialContext, TOutputSchema, TErrorMap, object> & Omit<ClientOptions<object>, "context">;
|
|
9
|
+
export type CallRest<TInitialContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> = 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>];
|
|
10
|
+
/**
|
|
11
|
+
* Quickly call a procedure without creating a client.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const output = await call(getting, 'input')
|
|
16
|
+
* const output = await call(getting, 'input', { context: { db: 'postgres' } })
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://orpc.dev/docs/client/server-side#one-off-calls | Server-Side Clients - One-Off Calls}
|
|
20
|
+
*/
|
|
21
|
+
export declare function call<TInitialContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap>(lazyableProcedure: Lazyable<Procedure<TInitialContext, any, TInputSchema, TOutputSchema, TErrorMap>>, ...[input, options]: CallRest<TInitialContext, TInputSchema, TOutputSchema, TErrorMap>): PromiseWithError<InferSchemaOutput<TOutputSchema>, ORPCErrorFromErrorMap<TErrorMap> | ThrowableError$1>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Lazy, unlazy } from "./lazy.js";
|
|
2
|
+
import { Procedure } from "./procedure.js";
|
|
3
|
+
import { createProcedureClient } from "./procedure-client.js";
|
|
4
|
+
// src/procedure-utils.ts
|
|
5
|
+
function createGuardedProcedureLazy(lazy) {
|
|
6
|
+
return new Lazy({
|
|
7
|
+
...lazy["~orpc"],
|
|
8
|
+
async loader() {
|
|
9
|
+
const { default: maybeProcedure } = await unlazy(lazy);
|
|
10
|
+
if (!(maybeProcedure instanceof Procedure)) 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
|
+
return { default: maybeProcedure };
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a new procedure that ensure the contract is applied to the procedure.
|
|
21
|
+
*
|
|
22
|
+
* .input/.output/.handler mismatches are already caught by the `implementer.router`,
|
|
23
|
+
* but .errors (in case implemented procedure error map is more than enough) and .meta cannot be
|
|
24
|
+
* validated that way - so they must be overridden here to ensure the client always sees what the contract defines.
|
|
25
|
+
*/
|
|
26
|
+
function createContractProcedure(procedure, contract) {
|
|
27
|
+
return new Procedure({
|
|
28
|
+
...procedure["~orpc"],
|
|
29
|
+
errorMap: contract["~orpc"].errorMap,
|
|
30
|
+
meta: contract["~orpc"].meta,
|
|
31
|
+
metaPlugins: contract["~orpc"].metaPlugins
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Quickly call a procedure without creating a client.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const output = await call(getting, 'input')
|
|
40
|
+
* const output = await call(getting, 'input', { context: { db: 'postgres' } })
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @see {@link https://orpc.dev/docs/client/server-side#one-off-calls | Server-Side Clients - One-Off Calls}
|
|
44
|
+
*/
|
|
45
|
+
function call(lazyableProcedure, ...[input = void 0, options = {}]) {
|
|
46
|
+
return createProcedureClient(lazyableProcedure, options)(input, options);
|
|
47
|
+
}
|
|
48
|
+
export { call, createContractProcedure, createGuardedProcedureLazy };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Context } from "./context.js";
|
|
2
|
+
import { AnyMiddleware } from "./middleware.js";
|
|
3
|
+
import { AnySchema, ErrorMap, ORPCErrorConstructorMap, ProcedureContractDefinition } from "@orpc/contract";
|
|
4
|
+
import { Promisable } from "@orpc/shared";
|
|
5
|
+
export interface ProcedureHandlerOptions<TCurrentContext extends Context, TInput, TErrorConstructorMap extends ORPCErrorConstructorMap<any>> {
|
|
6
|
+
context: TCurrentContext;
|
|
7
|
+
input: TInput;
|
|
8
|
+
path: string[];
|
|
9
|
+
procedure: Procedure<Context, Context, AnySchema, AnySchema, ErrorMap>;
|
|
10
|
+
signal?: AbortSignal | undefined;
|
|
11
|
+
lastEventId?: string | undefined;
|
|
12
|
+
errors: TErrorConstructorMap;
|
|
13
|
+
}
|
|
14
|
+
export interface ProcedureHandler<TCurrentContext extends Context, TInput, THandlerOutput, TErrorConstructorMap extends ORPCErrorConstructorMap<any>> {
|
|
15
|
+
(opts: ProcedureHandlerOptions<TCurrentContext, TInput, TErrorConstructorMap>, input: TInput): Promisable<THandlerOutput>;
|
|
16
|
+
}
|
|
17
|
+
export interface OrderedMiddleware {
|
|
18
|
+
/**
|
|
19
|
+
* Snapshot of `inputSchemas.length`
|
|
20
|
+
* at the time this middleware was used.
|
|
21
|
+
*
|
|
22
|
+
* @default 0
|
|
23
|
+
*/
|
|
24
|
+
inputSchemasLengthAtUse?: number | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Snapshot of `outputSchemas.length`
|
|
27
|
+
* at the time this middleware was used.
|
|
28
|
+
*
|
|
29
|
+
* @default 0
|
|
30
|
+
*/
|
|
31
|
+
outputSchemasLengthAtUse?: number | undefined;
|
|
32
|
+
middleware: AnyMiddleware;
|
|
33
|
+
}
|
|
34
|
+
export interface ProcedureConfig {
|
|
35
|
+
/**
|
|
36
|
+
* When enabled, input schemas are not validated at runtime.
|
|
37
|
+
* Schemas are still used for type inference and OpenAPI generation.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* **Warning**: Do not disable validation for schemas that transform values.
|
|
41
|
+
*
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
disableInputValidation?: boolean | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* When enabled, output schemas are not validated at runtime.
|
|
47
|
+
* Schemas are still used for type inference and OpenAPI generation.
|
|
48
|
+
*
|
|
49
|
+
* Useful when output schemas exist only for specification generation.
|
|
50
|
+
*
|
|
51
|
+
* @remarks
|
|
52
|
+
* **Warning**: Do not disable validation for schemas that transform values.
|
|
53
|
+
*
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
disableOutputValidation?: boolean | undefined;
|
|
57
|
+
}
|
|
58
|
+
export interface ProcedureDefinition<TInitialContext extends Context, TInjectedContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends ProcedureContractDefinition<TInputSchema, TOutputSchema, TErrorMap>, ProcedureConfig {
|
|
59
|
+
__TInitialContext?: (type: TInitialContext) => unknown;
|
|
60
|
+
__TInjectedContext?: (type: TInjectedContext) => unknown;
|
|
61
|
+
orderedMiddlewares: OrderedMiddleware[];
|
|
62
|
+
handler: ProcedureHandler<any, any, any, any>;
|
|
63
|
+
}
|
|
64
|
+
export declare class Procedure<TInitialContext extends Context, TInjectedContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> {
|
|
65
|
+
"~orpc": ProcedureDefinition<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
|
|
66
|
+
"constructor"(def: ProcedureDefinition<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>);
|
|
67
|
+
/**
|
|
68
|
+
* Checks if the given instance satisfies the {@link Procedure} class/interface.
|
|
69
|
+
*/
|
|
70
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
71
|
+
}
|
|
72
|
+
export type AnyProcedure = Procedure<any, any, any, any, any>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ProcedureContract } from "@orpc/contract";
|
|
2
|
+
import { getConstructor } from "@orpc/shared";
|
|
3
|
+
// src/procedure.ts
|
|
4
|
+
var Procedure = class Procedure {
|
|
5
|
+
"~orpc";
|
|
6
|
+
"constructor"(def) {
|
|
7
|
+
this["~orpc"] = def;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the given instance satisfies the {@link Procedure} class/interface.
|
|
11
|
+
*/
|
|
12
|
+
static [Symbol.hasInstance](instance) {
|
|
13
|
+
if (this !== Procedure) return Function.prototype[Symbol.hasInstance].call(this, instance);
|
|
14
|
+
if (getConstructor(instance) === Procedure) return true;
|
|
15
|
+
return instance instanceof ProcedureContract && Array.isArray(instance["~orpc"].orderedMiddlewares) && typeof instance["~orpc"].handler === "function";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export { Procedure };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Lazyable } from "./lazy.js";
|
|
2
|
+
import { Procedure } from "./procedure.js";
|
|
3
|
+
import { ProcedureClient, ProcedureClientOptions } from "./procedure-client.js";
|
|
4
|
+
import { AnyRouter, InferRouterInitialContext } from "./router.js";
|
|
5
|
+
import { ErrorMap, Schema } from "@orpc/contract";
|
|
6
|
+
import { MaybeOptionalOptions } from "@orpc/shared";
|
|
7
|
+
import { ClientContext } from "@orpc/client";
|
|
8
|
+
/**
|
|
9
|
+
* The client type derived from a router, exposing every procedure as a callable
|
|
10
|
+
* function while preserving the router's shape.
|
|
11
|
+
*
|
|
12
|
+
* @see {@link https://orpc.dev/docs/client/client-side#creating-a-client | Client-Side Clients - Creating a Client}
|
|
13
|
+
*/
|
|
14
|
+
export type RouterClient<TRouter extends AnyRouter, TClientContext extends ClientContext = object> = TRouter extends Procedure<any, any, infer $InputSchema, infer $OutputSchema, infer $ErrorMap> ? ProcedureClient<TClientContext, $InputSchema, $OutputSchema, $ErrorMap> : { [K in keyof TRouter]: TRouter[K] extends Lazyable<infer U extends AnyRouter> ? RouterClient<U, TClientContext> : never; };
|
|
15
|
+
/**
|
|
16
|
+
* Creates a server-side client that calls the router's procedures directly,
|
|
17
|
+
* within the same process, without any network layer.
|
|
18
|
+
*
|
|
19
|
+
* @see {@link https://orpc.dev/docs/client/server-side#router-clients | Server-Side Clients - Router Clients}
|
|
20
|
+
*/
|
|
21
|
+
export declare function createRouterClient<T extends AnyRouter, TClientContext extends ClientContext = object>(router: Lazyable<T | undefined>, ...rest: MaybeOptionalOptions<ProcedureClientOptions<InferRouterInitialContext<T>, Schema<unknown>, ErrorMap, TClientContext>>): RouterClient<T, TClientContext>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Lazy } from "./lazy.js";
|
|
2
|
+
import { Procedure } from "./procedure.js";
|
|
3
|
+
import { createProcedureClient } from "./procedure-client.js";
|
|
4
|
+
import { createGuardedProcedureLazy } from "./procedure-utils.js";
|
|
5
|
+
import { getRouter } from "./router-utils.js";
|
|
6
|
+
import { resolveMaybeOptionalOptions, toArray } from "@orpc/shared";
|
|
7
|
+
import { RECURSIVE_CLIENT_UNWRAP_KEYS } from "@orpc/client";
|
|
8
|
+
// src/router-client.ts
|
|
9
|
+
/**
|
|
10
|
+
* Creates a server-side client that calls the router's procedures directly,
|
|
11
|
+
* within the same process, without any network layer.
|
|
12
|
+
*
|
|
13
|
+
* @see {@link https://orpc.dev/docs/client/server-side#router-clients | Server-Side Clients - Router Clients}
|
|
14
|
+
*/
|
|
15
|
+
function createRouterClient(router, ...rest) {
|
|
16
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
17
|
+
if (router instanceof Procedure) return createProcedureClient(router, options);
|
|
18
|
+
const procedureCaller = router instanceof Lazy ? createProcedureClient(createGuardedProcedureLazy(router), options) : {};
|
|
19
|
+
const cache = /* @__PURE__ */ new Map();
|
|
20
|
+
return new Proxy(procedureCaller, { get(target, key) {
|
|
21
|
+
if (typeof key !== "string" || router instanceof Lazy && RECURSIVE_CLIENT_UNWRAP_KEYS.has(key)) return Reflect.get(target, key);
|
|
22
|
+
let nextClient = cache.get(key);
|
|
23
|
+
if (nextClient === void 0) {
|
|
24
|
+
const next = getRouter(router, [key]);
|
|
25
|
+
if (!next) return Reflect.get(target, key);
|
|
26
|
+
nextClient = createRouterClient(next, {
|
|
27
|
+
...options,
|
|
28
|
+
path: [...toArray(options.path), key]
|
|
29
|
+
});
|
|
30
|
+
cache.set(key, nextClient);
|
|
31
|
+
}
|
|
32
|
+
return nextClient;
|
|
33
|
+
} });
|
|
34
|
+
}
|
|
35
|
+
export { createRouterClient };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/router-hidden.ts
|
|
2
|
+
const HIDDEN_ROUTER_CONTRACT_SYMBOL = /* @__PURE__ */ Symbol.for("ORPC_HIDDEN_ROUTER_CONTRACT");
|
|
3
|
+
function withHiddenRouterContract(router, contract) {
|
|
4
|
+
return new Proxy(router, { get(target, key) {
|
|
5
|
+
if (key === HIDDEN_ROUTER_CONTRACT_SYMBOL) return contract;
|
|
6
|
+
return Reflect.get(target, key);
|
|
7
|
+
} });
|
|
8
|
+
}
|
|
9
|
+
function getHiddenRouterContract(router) {
|
|
10
|
+
return router[HIDDEN_ROUTER_CONTRACT_SYMBOL];
|
|
11
|
+
}
|
|
12
|
+
export { getHiddenRouterContract, withHiddenRouterContract };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Context, MergedInitialContext } from "./context.js";
|
|
2
|
+
import { Lazy, Lazyable } from "./lazy.js";
|
|
3
|
+
import "./middleware.js";
|
|
4
|
+
import { AnyProcedure, Procedure } from "./procedure.js";
|
|
5
|
+
import { AnyRouter } from "./router.js";
|
|
6
|
+
import { AnyProcedureContract, ErrorMap, MergedErrorMap, RouterContract } from "@orpc/contract";
|
|
7
|
+
import { Promisable } from "@orpc/shared";
|
|
8
|
+
export type AugmentedRouter<T extends AnyRouter, TErrorMap extends ErrorMap> = T extends Procedure<infer $InitialContext, infer $CurrentContext, infer $InputSchema, infer $OutputSchema, infer $ErrorMap> ? Procedure<$InitialContext, $CurrentContext, $InputSchema, $OutputSchema, MergedErrorMap<TErrorMap, $ErrorMap>> : { [K in keyof T]: T[K] extends Lazy<infer $ extends AnyRouter> ? Lazy<AugmentedRouter<$, TErrorMap>> : T[K] extends AnyRouter ? AugmentedRouter<T[K], TErrorMap> : never; };
|
|
9
|
+
export type AugmentedRouterWithMiddlewares<T extends AnyRouter, TInitialContext extends Context, TInjectedContext extends Context, TErrorMap extends ErrorMap> = T extends Procedure<infer $InitialContext, infer $CurrentContext, infer $InputSchema, infer $OutputSchema, infer $ErrorMap> ? Procedure<MergedInitialContext<TInitialContext, TInjectedContext, $InitialContext>, $CurrentContext, $InputSchema, $OutputSchema, MergedErrorMap<TErrorMap, $ErrorMap>> : { [K in keyof T]: T[K] extends Lazy<infer $ extends AnyRouter> ? Lazy<AugmentedRouterWithMiddlewares<$, TInitialContext, TInjectedContext, TErrorMap>> : T[K] extends AnyRouter ? AugmentedRouterWithMiddlewares<T[K], TInitialContext, TInjectedContext, TErrorMap> : never; };
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the procedure of a contract walked from a router: the procedure itself,
|
|
12
|
+
* or the implementation of a contract-first procedure, looked up by its path.
|
|
13
|
+
*
|
|
14
|
+
* @throws {TypeError} If a contract-first procedure has no valid implementation.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveContractProcedure(router: AnyRouter, contract: AnyProcedureContract, path: readonly string[]): Promise<AnyProcedure>;
|
|
17
|
+
export declare function getRouter<T extends Lazyable<AnyRouter | undefined>>(router: T, path: readonly string[]): T extends Lazy<any> ? Lazy<AnyRouter | undefined> : Lazyable<AnyRouter | undefined>;
|
|
18
|
+
export interface WalkProcedureContractsLazyResult {
|
|
19
|
+
router: Lazy<AnyRouter>;
|
|
20
|
+
path: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare function walkProcedureContractsSync(router: RouterContract | AnyRouter, callback: (contract: AnyProcedureContract | AnyProcedure, path: string[]) => void, path?: string[]): WalkProcedureContractsLazyResult[];
|
|
23
|
+
export declare function walkProcedureContractsAsync(router: RouterContract | AnyRouter, callback: (contract: AnyProcedureContract | AnyProcedure, path: string[]) => Promisable<void>, path?: string[]): Promise<void>;
|
|
24
|
+
export type UnlaziedRouter<T extends AnyRouter> = T extends AnyProcedure ? T : { [K in keyof T]: T[K] extends Lazyable<infer U extends AnyRouter> ? UnlaziedRouter<U> : never; };
|
|
25
|
+
/**
|
|
26
|
+
* Fully resolves all lazy routers inside a router, returning a plain router.
|
|
27
|
+
* Useful for making a router with lazy parts contract-compatible.
|
|
28
|
+
*
|
|
29
|
+
* @see {@link https://orpc.dev/docs/contract/router#router-to-contract | Router Contract - Router to Contract}
|
|
30
|
+
*/
|
|
31
|
+
export declare function unlazyRouter<T extends AnyRouter>(router: T): Promise<UnlaziedRouter<T>>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Lazy, unlazy } from "./lazy.js";
|
|
2
|
+
import { Procedure } from "./procedure.js";
|
|
3
|
+
import { createContractProcedure } from "./procedure-utils.js";
|
|
4
|
+
import { getHiddenRouterContract } from "./router-hidden.js";
|
|
5
|
+
import { ProcedureContract, mergeErrorMap, resolveMetaPlugins } from "@orpc/contract";
|
|
6
|
+
import { getOwn, isNonPrimitive, omit, setOwn } from "@orpc/shared";
|
|
7
|
+
// src/router-utils.ts
|
|
8
|
+
function augmentRouter(router, options) {
|
|
9
|
+
if (router instanceof Lazy) {
|
|
10
|
+
const [meta, metaPlugins] = resolveMetaPlugins(options.meta, options.metaPlugins, router["~orpc"].metaPlugins);
|
|
11
|
+
return new Lazy({
|
|
12
|
+
meta,
|
|
13
|
+
metaPlugins,
|
|
14
|
+
async loader() {
|
|
15
|
+
const { default: unlaziedRouter } = await unlazy(router);
|
|
16
|
+
const enhanced = augmentRouter(unlaziedRouter, options);
|
|
17
|
+
return unlazy(enhanced);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
if (router instanceof Procedure) {
|
|
22
|
+
const [meta, metaPlugins] = resolveMetaPlugins(options.meta, options.metaPlugins, router["~orpc"].metaPlugins);
|
|
23
|
+
return new Procedure({
|
|
24
|
+
...omit(options, [
|
|
25
|
+
"middlewares",
|
|
26
|
+
"errorMap",
|
|
27
|
+
"meta",
|
|
28
|
+
"metaPlugins"
|
|
29
|
+
]),
|
|
30
|
+
...router["~orpc"],
|
|
31
|
+
meta,
|
|
32
|
+
metaPlugins,
|
|
33
|
+
errorMap: mergeErrorMap(options.errorMap, router["~orpc"].errorMap),
|
|
34
|
+
orderedMiddlewares: [...options.middlewares.map((middleware) => ({
|
|
35
|
+
middleware,
|
|
36
|
+
inputSchemasLengthAtUse: 0,
|
|
37
|
+
outputSchemasLengthAtUse: 0
|
|
38
|
+
})), ...router["~orpc"].orderedMiddlewares]
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (!isNonPrimitive(router)) return router;
|
|
42
|
+
const enhanced = {};
|
|
43
|
+
for (const [key, child] of Object.entries(router)) setOwn(enhanced, key, augmentRouter(child, options));
|
|
44
|
+
return enhanced;
|
|
45
|
+
}
|
|
46
|
+
function augmentImplementedRouter(router, options) {
|
|
47
|
+
if (router instanceof Lazy) return new Lazy({
|
|
48
|
+
...router["~orpc"],
|
|
49
|
+
async loader() {
|
|
50
|
+
const { default: unlaziedRouter } = await unlazy(router);
|
|
51
|
+
const enhanced = augmentImplementedRouter(unlaziedRouter, options);
|
|
52
|
+
return unlazy(enhanced);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
if (router instanceof Procedure) return new Procedure({
|
|
56
|
+
...omit(options, ["middlewares"]),
|
|
57
|
+
...router["~orpc"],
|
|
58
|
+
orderedMiddlewares: [...options.middlewares.map((middleware) => ({
|
|
59
|
+
middleware,
|
|
60
|
+
inputSchemasLengthAtUse: 0,
|
|
61
|
+
outputSchemasLengthAtUse: 0
|
|
62
|
+
})), ...router["~orpc"].orderedMiddlewares]
|
|
63
|
+
});
|
|
64
|
+
if (!isNonPrimitive(router)) return router;
|
|
65
|
+
const enhanced = {};
|
|
66
|
+
for (const [key, child] of Object.entries(router)) setOwn(enhanced, key, augmentImplementedRouter(child, options));
|
|
67
|
+
return enhanced;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Resolves the procedure of a contract walked from a router: the procedure itself,
|
|
71
|
+
* or the implementation of a contract-first procedure, looked up by its path.
|
|
72
|
+
*
|
|
73
|
+
* @throws {TypeError} If a contract-first procedure has no valid implementation.
|
|
74
|
+
*/
|
|
75
|
+
async function resolveContractProcedure(router, contract, path) {
|
|
76
|
+
if (contract instanceof Procedure) return contract;
|
|
77
|
+
const { default: maybeProcedure } = await unlazy(getRouter(router, path));
|
|
78
|
+
if (!(maybeProcedure instanceof Procedure)) throw new TypeError(`[Contract-First] Missing or invalid implementation for procedure at path: "${path.join(".")}". Ensure the procedure is correctly implemented and matches its contract.`);
|
|
79
|
+
return createContractProcedure(maybeProcedure, contract);
|
|
80
|
+
}
|
|
81
|
+
function getRouter(router, path) {
|
|
82
|
+
let current = router;
|
|
83
|
+
for (let i = 0; i < path.length; i++) {
|
|
84
|
+
const segment = path[i];
|
|
85
|
+
if (!isNonPrimitive(current)) return;
|
|
86
|
+
if (current instanceof Procedure) return;
|
|
87
|
+
if (!(current instanceof Lazy)) {
|
|
88
|
+
current = getOwn(current, segment);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const lazied = current;
|
|
92
|
+
const rest = path.slice(i);
|
|
93
|
+
return new Lazy({
|
|
94
|
+
...lazied["~orpc"],
|
|
95
|
+
async loader() {
|
|
96
|
+
const next = getRouter((await unlazy(lazied)).default, rest);
|
|
97
|
+
return await unlazy(next);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (!isNonPrimitive(current)) return;
|
|
102
|
+
return current;
|
|
103
|
+
}
|
|
104
|
+
function walkProcedureContractsSync(router, callback, path = []) {
|
|
105
|
+
const lazyResults = [];
|
|
106
|
+
walkProcedureContractsSyncInternal(router, callback, path.slice(), lazyResults);
|
|
107
|
+
return lazyResults;
|
|
108
|
+
}
|
|
109
|
+
function walkProcedureContractsSyncInternal(router, callback, path, lazyResults) {
|
|
110
|
+
const hiddenContract = getHiddenRouterContract(router);
|
|
111
|
+
if (hiddenContract !== void 0) router = hiddenContract;
|
|
112
|
+
if (router instanceof ProcedureContract) {
|
|
113
|
+
callback(router, path.slice());
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!isNonPrimitive(router)) return;
|
|
117
|
+
for (const [key, value] of Object.entries(router)) {
|
|
118
|
+
path.push(key);
|
|
119
|
+
if (value instanceof Lazy) lazyResults.push({
|
|
120
|
+
router: value,
|
|
121
|
+
path: path.slice()
|
|
122
|
+
});
|
|
123
|
+
else walkProcedureContractsSyncInternal(value, callback, path, lazyResults);
|
|
124
|
+
path.pop();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function walkProcedureContractsAsync(router, callback, path = []) {
|
|
128
|
+
const hiddenContract = getHiddenRouterContract(router);
|
|
129
|
+
if (hiddenContract !== void 0) router = hiddenContract;
|
|
130
|
+
if (router instanceof ProcedureContract) {
|
|
131
|
+
await callback(router, path);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (!isNonPrimitive(router)) return;
|
|
135
|
+
for (const [key, value] of Object.entries(router)) if (value instanceof Lazy) {
|
|
136
|
+
const { default: router } = await unlazy(value);
|
|
137
|
+
await walkProcedureContractsAsync(router, callback, [...path, key]);
|
|
138
|
+
} else await walkProcedureContractsAsync(value, callback, [...path, key]);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Fully resolves all lazy routers inside a router, returning a plain router.
|
|
142
|
+
* Useful for making a router with lazy parts contract-compatible.
|
|
143
|
+
*
|
|
144
|
+
* @see {@link https://orpc.dev/docs/contract/router#router-to-contract | Router Contract - Router to Contract}
|
|
145
|
+
*/
|
|
146
|
+
async function unlazyRouter(router) {
|
|
147
|
+
if (router instanceof Procedure) return router;
|
|
148
|
+
if (!isNonPrimitive(router)) return router;
|
|
149
|
+
const unlazied = {};
|
|
150
|
+
for (const key of Object.keys(router)) {
|
|
151
|
+
const item = router[key];
|
|
152
|
+
const { default: unlaziedRouter } = await unlazy(item);
|
|
153
|
+
setOwn(unlazied, key, await unlazyRouter(unlaziedRouter));
|
|
154
|
+
}
|
|
155
|
+
return unlazied;
|
|
156
|
+
}
|
|
157
|
+
export { augmentImplementedRouter, augmentRouter, getRouter, resolveContractProcedure, unlazyRouter, walkProcedureContractsAsync, walkProcedureContractsSync };
|