@orpc/server 0.1.0 → 0.1.2
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/dist/chunk-26DTFWOI.js +200 -0
- package/dist/chunk-26DTFWOI.js.map +1 -0
- package/dist/fetch.js +87 -91
- package/dist/fetch.js.map +1 -1
- package/dist/index.js +6 -9
- package/dist/index.js.map +1 -1
- package/dist/src/adapters/fetch.d.ts +9 -3
- package/dist/src/adapters/fetch.d.ts.map +1 -1
- package/dist/src/builder.d.ts +4 -4
- package/dist/src/builder.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/middleware.d.ts +17 -7
- package/dist/src/middleware.d.ts.map +1 -1
- package/dist/src/procedure-builder.d.ts +4 -4
- package/dist/src/procedure-builder.d.ts.map +1 -1
- package/dist/src/procedure-caller.d.ts +0 -5
- package/dist/src/procedure-caller.d.ts.map +1 -1
- package/dist/src/procedure-implementer.d.ts +4 -5
- package/dist/src/procedure-implementer.d.ts.map +1 -1
- package/dist/src/procedure.d.ts +8 -9
- package/dist/src/procedure.d.ts.map +1 -1
- package/dist/src/router-builder.d.ts +2 -2
- package/dist/src/router-builder.d.ts.map +1 -1
- package/dist/src/router-caller.d.ts +1 -6
- package/dist/src/router-caller.d.ts.map +1 -1
- package/dist/src/router-implementer.d.ts +2 -2
- package/dist/src/router-implementer.d.ts.map +1 -1
- package/dist/src/router.d.ts +1 -1
- package/dist/src/router.d.ts.map +1 -1
- package/dist/src/types.d.ts +1 -10
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils.d.ts +1 -2
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/src/adapters/fetch.test.ts +32 -17
- package/src/adapters/fetch.ts +134 -123
- package/src/builder.test.ts +48 -39
- package/src/builder.ts +32 -30
- package/src/index.ts +2 -2
- package/src/middleware.test.ts +54 -73
- package/src/middleware.ts +39 -22
- package/src/procedure-builder.test.ts +26 -22
- package/src/procedure-builder.ts +15 -15
- package/src/procedure-caller.test.ts +25 -70
- package/src/procedure-caller.ts +69 -88
- package/src/procedure-implementer.test.ts +27 -22
- package/src/procedure-implementer.ts +16 -17
- package/src/procedure.test.ts +17 -12
- package/src/procedure.ts +46 -45
- package/src/router-builder.test.ts +4 -4
- package/src/router-builder.ts +12 -10
- package/src/router-caller.test.ts +6 -6
- package/src/router-caller.ts +5 -16
- package/src/router-implementer.test.ts +12 -12
- package/src/router-implementer.ts +9 -6
- package/src/router.test.ts +4 -4
- package/src/router.ts +12 -10
- package/src/types.test.ts +1 -1
- package/src/types.ts +1 -15
- package/src/utils.test.ts +2 -229
- package/src/utils.ts +5 -84
- package/dist/chunk-ACLC6USM.js +0 -262
- package/dist/chunk-ACLC6USM.js.map +0 -1
@@ -0,0 +1,200 @@
|
|
1
|
+
// src/utils.ts
|
2
|
+
function mergeContext(a, b) {
|
3
|
+
if (!a)
|
4
|
+
return b;
|
5
|
+
if (!b)
|
6
|
+
return a;
|
7
|
+
return {
|
8
|
+
...a,
|
9
|
+
...b
|
10
|
+
};
|
11
|
+
}
|
12
|
+
|
13
|
+
// src/middleware.ts
|
14
|
+
var decoratedMiddlewareSymbol = Symbol("\u{1F512}decoratedMiddleware");
|
15
|
+
function decorateMiddleware(middleware) {
|
16
|
+
if (Reflect.get(middleware, decoratedMiddlewareSymbol)) {
|
17
|
+
return middleware;
|
18
|
+
}
|
19
|
+
const concat = (concatMiddleware, mapInput2) => {
|
20
|
+
const concatMiddleware_ = mapInput2 ? decorateMiddleware(concatMiddleware).mapInput(mapInput2) : concatMiddleware;
|
21
|
+
return decorateMiddleware(async (input, context, meta, ...rest) => {
|
22
|
+
const input_ = input;
|
23
|
+
const context_ = context;
|
24
|
+
const meta_ = meta;
|
25
|
+
const next = async (options) => {
|
26
|
+
return concatMiddleware_(input_, mergeContext(context_, options.context), meta_, ...rest);
|
27
|
+
};
|
28
|
+
const m1 = await middleware(input_, context_, {
|
29
|
+
...meta_,
|
30
|
+
next
|
31
|
+
}, ...rest);
|
32
|
+
return m1;
|
33
|
+
});
|
34
|
+
};
|
35
|
+
const mapInput = (map) => {
|
36
|
+
return decorateMiddleware(
|
37
|
+
(input, ...rest) => middleware(map(input), ...rest)
|
38
|
+
);
|
39
|
+
};
|
40
|
+
return Object.assign(middleware, {
|
41
|
+
[decoratedMiddlewareSymbol]: true,
|
42
|
+
concat,
|
43
|
+
mapInput
|
44
|
+
});
|
45
|
+
}
|
46
|
+
|
47
|
+
// src/procedure-caller.ts
|
48
|
+
import { ORPCError } from "@orpc/shared/error";
|
49
|
+
function createProcedureCaller(options) {
|
50
|
+
const internal = options.internal ?? true;
|
51
|
+
const path = options.path ?? [];
|
52
|
+
const procedure = options.procedure;
|
53
|
+
const validate = options.validate ?? true;
|
54
|
+
const caller = async (input) => {
|
55
|
+
const validInput = (() => {
|
56
|
+
if (!validate)
|
57
|
+
return input;
|
58
|
+
const schema = procedure.zz$p.contract.zz$cp.InputSchema;
|
59
|
+
if (!schema)
|
60
|
+
return input;
|
61
|
+
try {
|
62
|
+
return schema.parse(input);
|
63
|
+
} catch (e) {
|
64
|
+
throw new ORPCError({
|
65
|
+
message: "Validation input failed",
|
66
|
+
code: "BAD_REQUEST",
|
67
|
+
cause: e
|
68
|
+
});
|
69
|
+
}
|
70
|
+
})();
|
71
|
+
const middlewares = procedure.zz$p.middlewares ?? [];
|
72
|
+
let currentMidIndex = 0;
|
73
|
+
let currentContext = options.context;
|
74
|
+
const next = async (nextOptions) => {
|
75
|
+
const mid = middlewares[currentMidIndex];
|
76
|
+
currentMidIndex += 1;
|
77
|
+
currentContext = mergeContext(currentContext, nextOptions.context);
|
78
|
+
if (mid) {
|
79
|
+
return await mid(validInput, currentContext, {
|
80
|
+
path,
|
81
|
+
procedure,
|
82
|
+
internal,
|
83
|
+
next,
|
84
|
+
output: (output2) => ({ output: output2, context: void 0 })
|
85
|
+
});
|
86
|
+
} else {
|
87
|
+
return {
|
88
|
+
output: await await procedure.zz$p.handler(validInput, currentContext, {
|
89
|
+
path,
|
90
|
+
procedure,
|
91
|
+
internal
|
92
|
+
}),
|
93
|
+
context: currentContext
|
94
|
+
};
|
95
|
+
}
|
96
|
+
};
|
97
|
+
const output = (await next({})).output;
|
98
|
+
const validOutput = await (async () => {
|
99
|
+
if (!validate)
|
100
|
+
return output;
|
101
|
+
const schema = procedure.zz$p.contract.zz$cp.OutputSchema;
|
102
|
+
if (!schema)
|
103
|
+
return output;
|
104
|
+
const result = await schema.safeParseAsync(output);
|
105
|
+
if (result.error) {
|
106
|
+
throw new ORPCError({
|
107
|
+
message: "Validation output failed",
|
108
|
+
code: "INTERNAL_SERVER_ERROR",
|
109
|
+
cause: result.error
|
110
|
+
});
|
111
|
+
}
|
112
|
+
return result.data;
|
113
|
+
})();
|
114
|
+
return validOutput;
|
115
|
+
};
|
116
|
+
return caller;
|
117
|
+
}
|
118
|
+
|
119
|
+
// src/procedure.ts
|
120
|
+
import {
|
121
|
+
DecoratedContractProcedure,
|
122
|
+
isContractProcedure
|
123
|
+
} from "@orpc/contract";
|
124
|
+
import { OpenAPIDeserializer } from "@orpc/transformer";
|
125
|
+
var Procedure = class {
|
126
|
+
constructor(zz$p) {
|
127
|
+
this.zz$p = zz$p;
|
128
|
+
}
|
129
|
+
};
|
130
|
+
var DECORATED_PROCEDURE_SYMBOL = Symbol("DECORATED_PROCEDURE");
|
131
|
+
function decorateProcedure(procedure) {
|
132
|
+
if (DECORATED_PROCEDURE_SYMBOL in procedure) {
|
133
|
+
return procedure;
|
134
|
+
}
|
135
|
+
const serverAction = async (input) => {
|
136
|
+
const input_ = (() => {
|
137
|
+
if (!(input instanceof FormData))
|
138
|
+
return input;
|
139
|
+
const transformer = new OpenAPIDeserializer({
|
140
|
+
schema: procedure.zz$p.contract.zz$cp.InputSchema
|
141
|
+
});
|
142
|
+
return transformer.deserializeAsFormData(input);
|
143
|
+
})();
|
144
|
+
const procedureCaller = createProcedureCaller({
|
145
|
+
procedure,
|
146
|
+
context: void 0,
|
147
|
+
internal: false,
|
148
|
+
validate: true
|
149
|
+
});
|
150
|
+
return await procedureCaller(input_);
|
151
|
+
};
|
152
|
+
return Object.assign(serverAction, {
|
153
|
+
[DECORATED_PROCEDURE_SYMBOL]: true,
|
154
|
+
zz$p: procedure.zz$p,
|
155
|
+
prefix(prefix) {
|
156
|
+
return decorateProcedure({
|
157
|
+
zz$p: {
|
158
|
+
...procedure.zz$p,
|
159
|
+
contract: DecoratedContractProcedure.decorate(
|
160
|
+
procedure.zz$p.contract
|
161
|
+
).prefix(prefix)
|
162
|
+
}
|
163
|
+
});
|
164
|
+
},
|
165
|
+
route(opts) {
|
166
|
+
return decorateProcedure({
|
167
|
+
zz$p: {
|
168
|
+
...procedure.zz$p,
|
169
|
+
contract: DecoratedContractProcedure.decorate(
|
170
|
+
procedure.zz$p.contract
|
171
|
+
).route(opts)
|
172
|
+
}
|
173
|
+
});
|
174
|
+
},
|
175
|
+
use(middleware, mapInput) {
|
176
|
+
const middleware_ = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
|
177
|
+
return decorateProcedure({
|
178
|
+
zz$p: {
|
179
|
+
...procedure.zz$p,
|
180
|
+
middlewares: [middleware_, ...procedure.zz$p.middlewares ?? []]
|
181
|
+
}
|
182
|
+
});
|
183
|
+
}
|
184
|
+
});
|
185
|
+
}
|
186
|
+
function isProcedure(item) {
|
187
|
+
if (item instanceof Procedure)
|
188
|
+
return true;
|
189
|
+
return (typeof item === "object" || typeof item === "function") && item !== null && "zz$p" in item && typeof item.zz$p === "object" && item.zz$p !== null && "contract" in item.zz$p && isContractProcedure(item.zz$p.contract) && "handler" in item.zz$p && typeof item.zz$p.handler === "function";
|
190
|
+
}
|
191
|
+
|
192
|
+
export {
|
193
|
+
mergeContext,
|
194
|
+
decorateMiddleware,
|
195
|
+
createProcedureCaller,
|
196
|
+
Procedure,
|
197
|
+
decorateProcedure,
|
198
|
+
isProcedure
|
199
|
+
};
|
200
|
+
//# sourceMappingURL=chunk-26DTFWOI.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts","../src/middleware.ts","../src/procedure-caller.ts","../src/procedure.ts"],"sourcesContent":["import type { Context, MergeContext } from './types'\n\nexport function mergeContext<A extends Context, B extends Context>(\n a: A,\n b: B,\n): MergeContext<A, B> {\n if (!a)\n return b as any\n if (!b)\n return a as any\n\n return {\n ...a,\n ...b,\n } as any\n}\n","import type { Promisable } from '@orpc/shared'\nimport type { Context, MergeContext, Meta } from './types'\nimport { mergeContext } from './utils'\n\nexport type MiddlewareResult<TExtraContext extends Context, TOutput> = Promisable<{\n output: TOutput\n context: TExtraContext\n}>\n\nexport interface MiddlewareMeta<\n TOutput,\n> extends Meta {\n next: <UExtraContext extends Context = undefined>(\n options: UExtraContext extends undefined ? { context?: UExtraContext } : { context: UExtraContext }\n ) => MiddlewareResult<UExtraContext, TOutput>\n output: <UOutput>(output: UOutput) => MiddlewareResult<undefined, UOutput>\n}\n\nexport interface Middleware<\n TContext extends Context,\n TExtraContext extends Context,\n TInput,\n TOutput,\n> {\n (\n input: TInput,\n context: TContext,\n meta: MiddlewareMeta<TOutput>,\n ): Promisable<\n MiddlewareResult<TExtraContext, TOutput>\n >\n}\n\nexport interface MapInputMiddleware<TInput, TMappedInput> {\n (input: TInput): TMappedInput\n}\n\nexport interface DecoratedMiddleware<\n TContext extends Context,\n TExtraContext extends Context,\n TInput,\n TOutput,\n> extends Middleware<TContext, TExtraContext, TInput, TOutput> {\n concat: (<\n UExtraContext extends Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>> | undefined = undefined,\n UInput = TInput,\n >(\n middleware: Middleware<\n MergeContext<TContext, TExtraContext>,\n UExtraContext,\n UInput & TInput,\n TOutput\n >,\n ) => DecoratedMiddleware<\n TContext,\n MergeContext<TExtraContext, UExtraContext>,\n TInput & UInput,\n TOutput\n >) & (<\n UExtraContext extends Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>> | undefined = undefined,\n UInput = TInput,\n UMappedInput = unknown,\n >(\n middleware: Middleware<\n MergeContext<TContext, TExtraContext>,\n UExtraContext,\n UMappedInput,\n TOutput\n >,\n mapInput: MapInputMiddleware<UInput, UMappedInput>,\n ) => DecoratedMiddleware<\n TContext,\n MergeContext<TExtraContext, UExtraContext>,\n TInput & UInput,\n TOutput\n >)\n\n mapInput: <UInput = unknown>(\n map: MapInputMiddleware<UInput, TInput>,\n ) => DecoratedMiddleware<TContext, TExtraContext, UInput, TOutput>\n}\n\nconst decoratedMiddlewareSymbol = Symbol('🔒decoratedMiddleware')\n\nexport function decorateMiddleware<\n TContext extends Context,\n TExtraContext extends Context,\n TInput,\n TOutput,\n>(\n middleware: Middleware<TContext, TExtraContext, TInput, TOutput>,\n): DecoratedMiddleware<TContext, TExtraContext, TInput, TOutput> {\n if (Reflect.get(middleware, decoratedMiddlewareSymbol)) {\n return middleware as any\n }\n\n const concat = (\n concatMiddleware: Middleware<any, any, any, any>,\n mapInput?: MapInputMiddleware<any, any>,\n ): Middleware<any, any, any, any> => {\n const concatMiddleware_ = mapInput\n ? decorateMiddleware(concatMiddleware).mapInput(mapInput)\n : concatMiddleware\n\n return decorateMiddleware(async (input, context, meta, ...rest) => {\n const input_ = input as any\n const context_ = context as any\n const meta_ = meta as any\n\n const next: MiddlewareMeta<any>['next'] = async (options) => {\n return concatMiddleware_(input_, mergeContext(context_, options.context), meta_, ...rest)\n }\n\n const m1 = await middleware(input_, context_, {\n ...meta_,\n next,\n }, ...rest)\n\n return m1\n })\n }\n\n const mapInput = <UInput = unknown>(\n map: MapInputMiddleware<UInput, TInput>,\n ): DecoratedMiddleware<TContext, TExtraContext, UInput, TOutput> => {\n return decorateMiddleware((input, ...rest) =>\n middleware(map(input), ...rest),\n )\n }\n\n return Object.assign(middleware, {\n [decoratedMiddlewareSymbol]: true,\n concat: concat as any,\n mapInput,\n })\n}\n","import type { SchemaInput, SchemaOutput } from '@orpc/contract'\nimport type { MiddlewareMeta } from './middleware'\nimport type { Procedure } from './procedure'\nimport type { Context } from './types'\nimport { ORPCError } from '@orpc/shared/error'\nimport { mergeContext } from './utils'\n\nexport interface CreateProcedureCallerOptions<\n TProcedure extends Procedure<any, any, any, any, any>,\n TValidate extends boolean,\n> {\n procedure: TProcedure\n\n /**\n * The context used when calling the procedure.\n */\n context: TProcedure extends Procedure<infer UContext, any, any, any, any>\n ? UContext\n : never\n\n /**\n * This is helpful for logging and analytics.\n */\n path?: string[]\n\n /**\n * This flag helpful when you want bypass some logics not necessary to internal server calls.\n *\n * @default true\n */\n internal?: boolean\n\n /**\n * Indicate whether validate input and output.\n *\n * @default true\n */\n validate?: TValidate\n}\n\nexport type ProcedureCaller<\n TProcedure extends Procedure<any, any, any, any, any>,\n TValidate extends boolean,\n> = TProcedure extends Procedure<\n any,\n any,\n infer UInputSchema,\n infer UOutputSchema,\n infer UHandlerOutput\n>\n ? (\n input: TValidate extends true\n ? SchemaInput<UInputSchema>\n : SchemaOutput<UInputSchema>,\n ) => Promise<\n TValidate extends true\n ? SchemaOutput<UOutputSchema, UHandlerOutput>\n : SchemaInput<UOutputSchema, UHandlerOutput>\n >\n : never\n\nexport function createProcedureCaller<\n TProcedure extends Procedure<any, any, any, any, any>,\n TValidate extends boolean = true,\n>(\n options: CreateProcedureCallerOptions<TProcedure, TValidate>,\n): ProcedureCaller<TProcedure, TValidate> {\n const internal = options.internal ?? true\n const path = options.path ?? []\n const procedure = options.procedure\n const validate = options.validate ?? true\n\n const caller = async (input: unknown): Promise<unknown> => {\n const validInput = (() => {\n if (!validate)\n return input\n const schema = procedure.zz$p.contract.zz$cp.InputSchema\n if (!schema)\n return input\n\n try {\n return schema.parse(input)\n }\n catch (e) {\n throw new ORPCError({\n message: 'Validation input failed',\n code: 'BAD_REQUEST',\n cause: e,\n })\n }\n })()\n\n const middlewares = procedure.zz$p.middlewares ?? []\n let currentMidIndex = 0\n let currentContext: Context = options.context\n\n const next: MiddlewareMeta<unknown>['next'] = async (nextOptions) => {\n const mid = middlewares[currentMidIndex]\n currentMidIndex += 1\n currentContext = mergeContext(currentContext, nextOptions.context)\n\n if (mid) {\n return await mid(validInput, currentContext, {\n path,\n procedure,\n internal,\n next,\n output: output => ({ output, context: undefined }),\n })\n }\n else {\n return {\n output: await await procedure.zz$p.handler(validInput, currentContext, {\n path,\n procedure,\n internal,\n }),\n context: currentContext,\n }\n }\n }\n\n const output = (await next({})).output\n\n const validOutput = await (async () => {\n if (!validate)\n return output\n const schema = procedure.zz$p.contract.zz$cp.OutputSchema\n if (!schema)\n return output\n const result = await schema.safeParseAsync(output)\n if (result.error) {\n throw new ORPCError({\n message: 'Validation output failed',\n code: 'INTERNAL_SERVER_ERROR',\n cause: result.error,\n })\n }\n return result.data\n })()\n\n return validOutput\n }\n\n return caller as ProcedureCaller<TProcedure, TValidate>\n}\n","import type { Promisable } from '@orpc/shared'\nimport type { Context, MergeContext, Meta } from './types'\nimport {\n type ContractProcedure,\n DecoratedContractProcedure,\n type HTTPPath,\n isContractProcedure,\n type RouteOptions,\n type Schema,\n type SchemaInput,\n type SchemaOutput,\n} from '@orpc/contract'\nimport { OpenAPIDeserializer } from '@orpc/transformer'\nimport {\n decorateMiddleware,\n type MapInputMiddleware,\n type Middleware,\n} from './middleware'\nimport { createProcedureCaller } from './procedure-caller'\n\nexport class Procedure<\n TContext extends Context,\n TExtraContext extends Context,\n TInputSchema extends Schema,\n TOutputSchema extends Schema,\n THandlerOutput extends SchemaOutput<TOutputSchema>,\n> {\n constructor(\n public zz$p: {\n middlewares?: Middleware<any, any, any, any>[]\n contract: ContractProcedure<TInputSchema, TOutputSchema>\n handler: ProcedureHandler<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >\n },\n ) {}\n}\n\nexport type DecoratedProcedure<\n TContext extends Context,\n TExtraContext extends Context,\n TInputSchema extends Schema,\n TOutputSchema extends Schema,\n THandlerOutput extends SchemaOutput<TOutputSchema>,\n> = Procedure<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n> & {\n prefix: (\n prefix: HTTPPath,\n ) => DecoratedProcedure<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >\n\n route: (\n opts: RouteOptions,\n ) => DecoratedProcedure<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >\n\n use: (<\n UExtraContext extends\n | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>\n | undefined = undefined,\n >(\n middleware: Middleware<\n MergeContext<TContext, TExtraContext>,\n UExtraContext,\n SchemaOutput<TInputSchema>,\n SchemaInput<TOutputSchema, THandlerOutput>\n >,\n ) => DecoratedProcedure<\n TContext,\n MergeContext<TExtraContext, UExtraContext>,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >) & (<\n UExtraContext extends\n | Partial<MergeContext<Context, MergeContext<TContext, TExtraContext>>>\n | undefined = undefined,\n UMappedInput = unknown,\n >(\n middleware: Middleware<\n MergeContext<TContext, TExtraContext>,\n UExtraContext,\n UMappedInput,\n SchemaInput<TOutputSchema, THandlerOutput>\n >,\n mapInput: MapInputMiddleware<\n SchemaOutput<TInputSchema, THandlerOutput>,\n UMappedInput\n >,\n ) => DecoratedProcedure<\n TContext,\n MergeContext<TExtraContext, UExtraContext>,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >)\n} & (undefined extends TContext\n ? (\n input: SchemaInput<TInputSchema> | FormData,\n ) => Promise<SchemaOutput<TOutputSchema, THandlerOutput>>\n : unknown)\n\nexport interface ProcedureHandler<\n TContext extends Context,\n TExtraContext extends Context,\n TInputSchema extends Schema,\n TOutputSchema extends Schema,\n TOutput extends SchemaOutput<TOutputSchema>,\n> {\n (\n input: SchemaOutput<TInputSchema>,\n context: MergeContext<TContext, TExtraContext>,\n meta: Meta,\n ): Promisable<SchemaInput<TOutputSchema, TOutput>>\n}\n\nconst DECORATED_PROCEDURE_SYMBOL = Symbol('DECORATED_PROCEDURE')\n\nexport function decorateProcedure<\n TContext extends Context,\n TExtraContext extends Context,\n TInputSchema extends Schema,\n TOutputSchema extends Schema,\n THandlerOutput extends SchemaOutput<TOutputSchema>,\n>(\n procedure: Procedure<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n >,\n): DecoratedProcedure<\n TContext,\n TExtraContext,\n TInputSchema,\n TOutputSchema,\n THandlerOutput\n > {\n if (DECORATED_PROCEDURE_SYMBOL in procedure) {\n return procedure as any\n }\n\n const serverAction = async (input: unknown): Promise<SchemaOutput<TOutputSchema, THandlerOutput>> => {\n const input_ = (() => {\n if (!(input instanceof FormData))\n return input\n\n const transformer = new OpenAPIDeserializer({\n schema: procedure.zz$p.contract.zz$cp.InputSchema,\n })\n\n return transformer.deserializeAsFormData(input)\n })()\n\n const procedureCaller = createProcedureCaller({\n procedure,\n context: undefined as any,\n internal: false,\n validate: true,\n })\n\n return await procedureCaller(input_ as any)\n }\n\n return Object.assign(serverAction, {\n [DECORATED_PROCEDURE_SYMBOL]: true,\n zz$p: procedure.zz$p,\n\n prefix(prefix: HTTPPath) {\n return decorateProcedure({\n zz$p: {\n ...procedure.zz$p,\n contract: DecoratedContractProcedure.decorate(\n procedure.zz$p.contract,\n ).prefix(prefix),\n },\n })\n },\n\n route(opts: RouteOptions) {\n return decorateProcedure({\n zz$p: {\n ...procedure.zz$p,\n contract: DecoratedContractProcedure.decorate(\n procedure.zz$p.contract,\n ).route(opts),\n },\n })\n },\n\n use(\n middleware: Middleware<any, any, any, any>,\n mapInput?: MapInputMiddleware<any, any>,\n ) {\n const middleware_ = mapInput\n ? decorateMiddleware(middleware).mapInput(mapInput)\n : middleware\n\n return decorateProcedure({\n zz$p: {\n ...procedure.zz$p,\n middlewares: [middleware_, ...(procedure.zz$p.middlewares ?? [])],\n },\n })\n },\n }) as any\n}\n\nexport type WELL_DEFINED_PROCEDURE = Procedure<\n Context,\n Context,\n Schema,\n Schema,\n unknown\n>\n\nexport function isProcedure(item: unknown): item is WELL_DEFINED_PROCEDURE {\n if (item instanceof Procedure)\n return true\n\n return (\n (typeof item === 'object' || typeof item === 'function')\n && item !== null\n && 'zz$p' in item\n && typeof item.zz$p === 'object'\n && item.zz$p !== null\n && 'contract' in item.zz$p\n && isContractProcedure(item.zz$p.contract)\n && 'handler' in item.zz$p\n && typeof item.zz$p.handler === 'function'\n )\n}\n"],"mappings":"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","names":["mapInput","output"]}
|
package/dist/fetch.js
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
import {
|
2
2
|
createProcedureCaller,
|
3
|
-
hook,
|
4
3
|
isProcedure
|
5
|
-
} from "./chunk-
|
4
|
+
} from "./chunk-26DTFWOI.js";
|
6
5
|
|
7
6
|
// src/adapters/fetch.ts
|
8
7
|
import {
|
@@ -18,10 +17,10 @@ import {
|
|
18
17
|
} from "@orpc/shared";
|
19
18
|
import { ORPCError } from "@orpc/shared/error";
|
20
19
|
import {
|
21
|
-
ORPCDeserializer,
|
22
|
-
ORPCSerializer,
|
23
20
|
OpenAPIDeserializer,
|
24
21
|
OpenAPISerializer,
|
22
|
+
ORPCDeserializer,
|
23
|
+
ORPCSerializer,
|
25
24
|
zodCoerce
|
26
25
|
} from "@orpc/transformer";
|
27
26
|
|
@@ -551,103 +550,100 @@ function createFetchHandler(options) {
|
|
551
550
|
const isORPCTransformer = requestOptions.request.headers.get(ORPC_HEADER) === ORPC_HEADER_VALUE;
|
552
551
|
const accept = requestOptions.request.headers.get("Accept") || void 0;
|
553
552
|
const serializer = isORPCTransformer ? new ORPCSerializer() : new OpenAPISerializer({ accept });
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
553
|
+
const handler = async () => {
|
554
|
+
const url = new URL(requestOptions.request.url);
|
555
|
+
const pathname = `/${trim(url.pathname.replace(requestOptions.prefix ?? "", ""), "/")}`;
|
556
|
+
let path;
|
557
|
+
let procedure;
|
558
|
+
let params;
|
559
|
+
if (isORPCTransformer) {
|
560
|
+
path = trim(pathname, "/").split("/").map(decodeURIComponent);
|
561
|
+
const val = get(options.router, path);
|
562
|
+
if (isProcedure(val)) {
|
563
|
+
procedure = val;
|
564
|
+
}
|
565
|
+
} else {
|
566
|
+
const customMethod = requestOptions.request.method === "POST" ? url.searchParams.get("method")?.toUpperCase() : void 0;
|
567
|
+
const method = customMethod || requestOptions.request.method;
|
568
|
+
const [matches, params_] = routing.match(method, pathname);
|
569
|
+
const [match] = matches.sort((a, b) => {
|
570
|
+
return Object.keys(a[1]).length - Object.keys(b[1]).length;
|
571
|
+
});
|
572
|
+
if (match) {
|
573
|
+
path = match[0][0];
|
574
|
+
procedure = match[0][1];
|
575
|
+
if (params_) {
|
576
|
+
params = mapValues(
|
577
|
+
match[1],
|
578
|
+
(v) => params_[v]
|
579
|
+
);
|
580
|
+
} else {
|
581
|
+
params = match[1];
|
582
|
+
}
|
583
|
+
}
|
584
|
+
if (!path || !procedure) {
|
562
585
|
path = trim(pathname, "/").split("/").map(decodeURIComponent);
|
563
586
|
const val = get(options.router, path);
|
564
587
|
if (isProcedure(val)) {
|
565
588
|
procedure = val;
|
566
589
|
}
|
567
|
-
}
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
590
|
+
}
|
591
|
+
}
|
592
|
+
if (!path || !procedure) {
|
593
|
+
throw new ORPCError({ code: "NOT_FOUND", message: "Not found" });
|
594
|
+
}
|
595
|
+
const deserializer = isORPCTransformer ? new ORPCDeserializer() : new OpenAPIDeserializer({
|
596
|
+
schema: procedure.zz$p.contract.zz$cp.InputSchema
|
597
|
+
});
|
598
|
+
const input_ = await (async () => {
|
599
|
+
try {
|
600
|
+
return await deserializer.deserialize(requestOptions.request);
|
601
|
+
} catch (e) {
|
602
|
+
throw new ORPCError({
|
603
|
+
code: "BAD_REQUEST",
|
604
|
+
message: "Cannot parse request. Please check the request body and Content-Type header.",
|
605
|
+
cause: e
|
573
606
|
});
|
574
|
-
if (match) {
|
575
|
-
path = match[0][0];
|
576
|
-
procedure = match[0][1];
|
577
|
-
if (params_) {
|
578
|
-
params = mapValues(
|
579
|
-
match[1],
|
580
|
-
(v) => params_[v]
|
581
|
-
);
|
582
|
-
} else {
|
583
|
-
params = match[1];
|
584
|
-
}
|
585
|
-
}
|
586
|
-
if (!path || !procedure) {
|
587
|
-
path = trim(pathname, "/").split("/").map(decodeURIComponent);
|
588
|
-
const val = get(options.router, path);
|
589
|
-
if (isProcedure(val)) {
|
590
|
-
procedure = val;
|
591
|
-
}
|
592
|
-
}
|
593
607
|
}
|
594
|
-
|
595
|
-
|
608
|
+
})();
|
609
|
+
const input = (() => {
|
610
|
+
if (!params || Object.keys(params).length === 0) {
|
611
|
+
return input_;
|
596
612
|
}
|
597
|
-
const
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
};
|
603
|
-
await options.hooks?.(requestOptions.context, meta);
|
604
|
-
const deserializer = isORPCTransformer ? new ORPCDeserializer() : new OpenAPIDeserializer({
|
605
|
-
schema: procedure.zz$p.contract.zz$cp.InputSchema
|
606
|
-
});
|
607
|
-
const input_ = await (async () => {
|
608
|
-
try {
|
609
|
-
return await deserializer.deserialize(requestOptions.request);
|
610
|
-
} catch (e) {
|
611
|
-
throw new ORPCError({
|
612
|
-
code: "BAD_REQUEST",
|
613
|
-
message: "Cannot parse request. Please check the request body and Content-Type header.",
|
614
|
-
cause: e
|
615
|
-
});
|
616
|
-
}
|
617
|
-
})();
|
618
|
-
const input = (() => {
|
619
|
-
if (!params || Object.keys(params).length === 0) {
|
620
|
-
return input_;
|
621
|
-
}
|
622
|
-
const coercedParams = procedure.zz$p.contract.zz$cp.InputSchema ? zodCoerce(
|
623
|
-
procedure.zz$p.contract.zz$cp.InputSchema,
|
624
|
-
{ ...params },
|
625
|
-
{
|
626
|
-
bracketNotation: true
|
627
|
-
}
|
628
|
-
) : params;
|
629
|
-
if (!isPlainObject(input_)) {
|
630
|
-
return coercedParams;
|
613
|
+
const coercedParams = procedure.zz$p.contract.zz$cp.InputSchema ? zodCoerce(
|
614
|
+
procedure.zz$p.contract.zz$cp.InputSchema,
|
615
|
+
{ ...params },
|
616
|
+
{
|
617
|
+
bracketNotation: true
|
631
618
|
}
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
619
|
+
) : params;
|
620
|
+
if (!isPlainObject(input_)) {
|
621
|
+
return coercedParams;
|
622
|
+
}
|
623
|
+
return {
|
624
|
+
...coercedParams,
|
625
|
+
...input_
|
626
|
+
};
|
627
|
+
})();
|
628
|
+
const caller = createProcedureCaller({
|
629
|
+
context: requestOptions.context,
|
630
|
+
internal: false,
|
631
|
+
validate: true,
|
632
|
+
procedure,
|
633
|
+
path
|
634
|
+
});
|
635
|
+
const output = await caller(input);
|
636
|
+
const { body, headers } = serializer.serialize(output);
|
637
|
+
return new Response(body, {
|
638
|
+
status: 200,
|
639
|
+
headers
|
650
640
|
});
|
641
|
+
};
|
642
|
+
try {
|
643
|
+
return await options.hooks?.(requestOptions.context, {
|
644
|
+
next: handler,
|
645
|
+
response: (response) => response
|
646
|
+
}) ?? await handler();
|
651
647
|
} catch (e) {
|
652
648
|
const error = toORPCError(e);
|
653
649
|
try {
|