effect-orpc 0.1.3 → 0.2.0
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 +486 -0
- package/dist/index.js +352 -72
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/contract.ts +491 -0
- package/src/effect-builder.ts +40 -88
- package/src/effect-runtime.ts +134 -0
- package/src/eoc.ts +499 -0
- package/src/index.ts +18 -3
- package/src/tagged-error.ts +24 -4
- package/src/tests/contract.test.ts +346 -0
- package/src/tests/effect-error-map.test.ts +22 -3
- package/src/tests/parity-shared.ts +32 -0
- package/src/tests/parity.contract-builder-variants.test.ts +192 -0
- package/src/tests/parity.contract-builder.test.ts +222 -0
- package/src/tests/parity.effect-builder.test.ts +193 -0
- package/src/tests/parity.effect-procedure.test.ts +124 -0
- package/src/tests/parity.implementer-variants.test.ts +249 -0
- package/src/tests/parity.implementer.test.ts +280 -0
- package/src/tests/shared.ts +2 -0
- package/src/types/index.ts +0 -16
- package/src/types/variants.ts +25 -16
package/src/contract.ts
ADDED
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyContractRouter,
|
|
3
|
+
AnySchema,
|
|
4
|
+
ContractProcedure,
|
|
5
|
+
ErrorMap,
|
|
6
|
+
InferContractRouterErrorMap,
|
|
7
|
+
InferContractRouterMeta,
|
|
8
|
+
InferSchemaInput,
|
|
9
|
+
InferSchemaOutput,
|
|
10
|
+
Meta,
|
|
11
|
+
} from "@orpc/contract";
|
|
12
|
+
import { isContractProcedure } from "@orpc/contract";
|
|
13
|
+
import type {
|
|
14
|
+
BuilderConfig,
|
|
15
|
+
BuilderDef,
|
|
16
|
+
Context,
|
|
17
|
+
DecoratedMiddleware,
|
|
18
|
+
ImplementedProcedure,
|
|
19
|
+
Lazy,
|
|
20
|
+
MapInputMiddleware,
|
|
21
|
+
MergedCurrentContext,
|
|
22
|
+
MergedInitialContext,
|
|
23
|
+
Middleware,
|
|
24
|
+
ORPCErrorConstructorMap,
|
|
25
|
+
ProcedureHandler,
|
|
26
|
+
Router,
|
|
27
|
+
} from "@orpc/server";
|
|
28
|
+
import { implement } from "@orpc/server";
|
|
29
|
+
import type { IntersectPick } from "@orpc/shared";
|
|
30
|
+
import type { ManagedRuntime } from "effect";
|
|
31
|
+
|
|
32
|
+
import { addSpanStackTrace } from "./effect-builder";
|
|
33
|
+
import { enhanceEffectRouter } from "./effect-enhance-router";
|
|
34
|
+
import { EffectDecoratedProcedure } from "./effect-procedure";
|
|
35
|
+
import { createEffectProcedureHandler } from "./effect-runtime";
|
|
36
|
+
import { effectContractSymbol, getEffectContractErrorMap } from "./eoc";
|
|
37
|
+
import type { EffectErrorMap } from "./tagged-error";
|
|
38
|
+
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
39
|
+
import type { EffectErrorMapToErrorMap, EffectProcedureHandler } from "./types";
|
|
40
|
+
|
|
41
|
+
type ContractLeafEffectHandler<
|
|
42
|
+
TCurrentContext extends Context,
|
|
43
|
+
TInputSchema extends AnySchema,
|
|
44
|
+
TOutputSchema extends AnySchema,
|
|
45
|
+
TErrorMap extends EffectErrorMap,
|
|
46
|
+
TRequirementsProvided,
|
|
47
|
+
TMeta extends Meta,
|
|
48
|
+
> = EffectProcedureHandler<
|
|
49
|
+
TCurrentContext,
|
|
50
|
+
InferSchemaOutput<TInputSchema>,
|
|
51
|
+
InferSchemaInput<TOutputSchema>,
|
|
52
|
+
TErrorMap,
|
|
53
|
+
TRequirementsProvided,
|
|
54
|
+
TMeta
|
|
55
|
+
>;
|
|
56
|
+
|
|
57
|
+
type InferContractLeafEffectErrorMap<
|
|
58
|
+
TContract,
|
|
59
|
+
TErrorMap extends ErrorMap,
|
|
60
|
+
> = TContract extends {
|
|
61
|
+
[effectContractSymbol]: {
|
|
62
|
+
errorMap: infer TEffectErrorMap extends EffectErrorMap;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
? TEffectErrorMap
|
|
66
|
+
: TErrorMap;
|
|
67
|
+
|
|
68
|
+
export interface EffectProcedureImplementer<
|
|
69
|
+
TInitialContext extends Context,
|
|
70
|
+
TCurrentContext extends Context,
|
|
71
|
+
TInputSchema extends AnySchema,
|
|
72
|
+
TOutputSchema extends AnySchema,
|
|
73
|
+
TErrorMap extends EffectErrorMap,
|
|
74
|
+
TMeta extends Meta,
|
|
75
|
+
TRequirementsProvided,
|
|
76
|
+
TRuntimeError,
|
|
77
|
+
> {
|
|
78
|
+
"~orpc": BuilderDef<
|
|
79
|
+
TInputSchema,
|
|
80
|
+
TOutputSchema,
|
|
81
|
+
EffectErrorMapToErrorMap<TErrorMap>,
|
|
82
|
+
TMeta
|
|
83
|
+
>;
|
|
84
|
+
use<
|
|
85
|
+
UOutContext extends IntersectPick<TCurrentContext, UOutContext>,
|
|
86
|
+
UInContext extends Context = TCurrentContext,
|
|
87
|
+
>(
|
|
88
|
+
middleware: Middleware<
|
|
89
|
+
UInContext | TCurrentContext,
|
|
90
|
+
UOutContext,
|
|
91
|
+
InferSchemaOutput<TInputSchema>,
|
|
92
|
+
InferSchemaInput<TOutputSchema>,
|
|
93
|
+
ORPCErrorConstructorMap<EffectErrorMapToErrorMap<TErrorMap>>,
|
|
94
|
+
TMeta
|
|
95
|
+
>,
|
|
96
|
+
): EffectProcedureImplementer<
|
|
97
|
+
MergedInitialContext<TInitialContext, UInContext, TCurrentContext>,
|
|
98
|
+
MergedCurrentContext<TCurrentContext, UOutContext>,
|
|
99
|
+
TInputSchema,
|
|
100
|
+
TOutputSchema,
|
|
101
|
+
TErrorMap,
|
|
102
|
+
TMeta,
|
|
103
|
+
TRequirementsProvided,
|
|
104
|
+
TRuntimeError
|
|
105
|
+
>;
|
|
106
|
+
use<
|
|
107
|
+
UOutContext extends IntersectPick<TCurrentContext, UOutContext>,
|
|
108
|
+
UInput,
|
|
109
|
+
UInContext extends Context = TCurrentContext,
|
|
110
|
+
>(
|
|
111
|
+
middleware: Middleware<
|
|
112
|
+
UInContext | TCurrentContext,
|
|
113
|
+
UOutContext,
|
|
114
|
+
UInput,
|
|
115
|
+
InferSchemaInput<TOutputSchema>,
|
|
116
|
+
ORPCErrorConstructorMap<EffectErrorMapToErrorMap<TErrorMap>>,
|
|
117
|
+
TMeta
|
|
118
|
+
>,
|
|
119
|
+
mapInput: MapInputMiddleware<InferSchemaOutput<TInputSchema>, UInput>,
|
|
120
|
+
): EffectProcedureImplementer<
|
|
121
|
+
MergedInitialContext<TInitialContext, UInContext, TCurrentContext>,
|
|
122
|
+
MergedCurrentContext<TCurrentContext, UOutContext>,
|
|
123
|
+
TInputSchema,
|
|
124
|
+
TOutputSchema,
|
|
125
|
+
TErrorMap,
|
|
126
|
+
TMeta,
|
|
127
|
+
TRequirementsProvided,
|
|
128
|
+
TRuntimeError
|
|
129
|
+
>;
|
|
130
|
+
handler(
|
|
131
|
+
handler: ProcedureHandler<
|
|
132
|
+
TCurrentContext,
|
|
133
|
+
InferSchemaOutput<TInputSchema>,
|
|
134
|
+
InferSchemaInput<TOutputSchema>,
|
|
135
|
+
EffectErrorMapToErrorMap<TErrorMap>,
|
|
136
|
+
TMeta
|
|
137
|
+
>,
|
|
138
|
+
): ImplementedProcedure<
|
|
139
|
+
TInitialContext,
|
|
140
|
+
TCurrentContext,
|
|
141
|
+
TInputSchema,
|
|
142
|
+
TOutputSchema,
|
|
143
|
+
EffectErrorMapToErrorMap<TErrorMap>,
|
|
144
|
+
TMeta
|
|
145
|
+
>;
|
|
146
|
+
effect(
|
|
147
|
+
effectFn: ContractLeafEffectHandler<
|
|
148
|
+
TCurrentContext,
|
|
149
|
+
TInputSchema,
|
|
150
|
+
TOutputSchema,
|
|
151
|
+
TErrorMap,
|
|
152
|
+
TRequirementsProvided,
|
|
153
|
+
TMeta
|
|
154
|
+
>,
|
|
155
|
+
): EffectDecoratedProcedure<
|
|
156
|
+
TInitialContext,
|
|
157
|
+
TCurrentContext,
|
|
158
|
+
TInputSchema,
|
|
159
|
+
TOutputSchema,
|
|
160
|
+
TErrorMap,
|
|
161
|
+
TMeta,
|
|
162
|
+
TRequirementsProvided,
|
|
163
|
+
TRuntimeError
|
|
164
|
+
>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export type EffectImplementerInternal<
|
|
168
|
+
TContract extends AnyContractRouter,
|
|
169
|
+
TInitialContext extends Context,
|
|
170
|
+
TCurrentContext extends Context,
|
|
171
|
+
TRequirementsProvided,
|
|
172
|
+
TRuntimeError,
|
|
173
|
+
> =
|
|
174
|
+
TContract extends ContractProcedure<
|
|
175
|
+
infer TInputSchema,
|
|
176
|
+
infer TOutputSchema,
|
|
177
|
+
infer TErrorMap extends ErrorMap,
|
|
178
|
+
infer TMeta extends Meta
|
|
179
|
+
>
|
|
180
|
+
? EffectProcedureImplementer<
|
|
181
|
+
TInitialContext,
|
|
182
|
+
TCurrentContext,
|
|
183
|
+
TInputSchema,
|
|
184
|
+
TOutputSchema,
|
|
185
|
+
InferContractLeafEffectErrorMap<TContract, TErrorMap>,
|
|
186
|
+
TMeta,
|
|
187
|
+
TRequirementsProvided,
|
|
188
|
+
TRuntimeError
|
|
189
|
+
>
|
|
190
|
+
: {
|
|
191
|
+
middleware<
|
|
192
|
+
UOutContext extends IntersectPick<TCurrentContext, UOutContext>,
|
|
193
|
+
TInput,
|
|
194
|
+
TOutput = any,
|
|
195
|
+
>(
|
|
196
|
+
middleware: Middleware<
|
|
197
|
+
TInitialContext,
|
|
198
|
+
UOutContext,
|
|
199
|
+
TInput,
|
|
200
|
+
TOutput,
|
|
201
|
+
ORPCErrorConstructorMap<InferContractRouterErrorMap<TContract>>,
|
|
202
|
+
InferContractRouterMeta<TContract>
|
|
203
|
+
>,
|
|
204
|
+
): DecoratedMiddleware<
|
|
205
|
+
TInitialContext,
|
|
206
|
+
UOutContext,
|
|
207
|
+
TInput,
|
|
208
|
+
TOutput,
|
|
209
|
+
any,
|
|
210
|
+
InferContractRouterMeta<TContract>
|
|
211
|
+
>;
|
|
212
|
+
use<
|
|
213
|
+
UOutContext extends IntersectPick<TCurrentContext, UOutContext>,
|
|
214
|
+
UInContext extends Context = TCurrentContext,
|
|
215
|
+
>(
|
|
216
|
+
middleware: Middleware<
|
|
217
|
+
UInContext | TCurrentContext,
|
|
218
|
+
UOutContext,
|
|
219
|
+
unknown,
|
|
220
|
+
unknown,
|
|
221
|
+
ORPCErrorConstructorMap<InferContractRouterErrorMap<TContract>>,
|
|
222
|
+
InferContractRouterMeta<TContract>
|
|
223
|
+
>,
|
|
224
|
+
): EffectImplementerInternal<
|
|
225
|
+
TContract,
|
|
226
|
+
MergedInitialContext<TInitialContext, UInContext, TCurrentContext>,
|
|
227
|
+
MergedCurrentContext<TCurrentContext, UOutContext>,
|
|
228
|
+
TRequirementsProvided,
|
|
229
|
+
TRuntimeError
|
|
230
|
+
>;
|
|
231
|
+
router<U extends Router<TContract, TCurrentContext>>(
|
|
232
|
+
router: U,
|
|
233
|
+
): ReturnType<
|
|
234
|
+
typeof enhanceEffectRouter<
|
|
235
|
+
U,
|
|
236
|
+
TInitialContext,
|
|
237
|
+
TCurrentContext,
|
|
238
|
+
Record<never, never>,
|
|
239
|
+
TRequirementsProvided,
|
|
240
|
+
TRuntimeError
|
|
241
|
+
>
|
|
242
|
+
>;
|
|
243
|
+
lazy<U extends Router<TContract, TCurrentContext>>(
|
|
244
|
+
loader: () => Promise<{ default: U }>,
|
|
245
|
+
): ReturnType<
|
|
246
|
+
typeof enhanceEffectRouter<
|
|
247
|
+
Lazy<U>,
|
|
248
|
+
TInitialContext,
|
|
249
|
+
TCurrentContext,
|
|
250
|
+
Record<never, never>,
|
|
251
|
+
TRequirementsProvided,
|
|
252
|
+
TRuntimeError
|
|
253
|
+
>
|
|
254
|
+
>;
|
|
255
|
+
} & {
|
|
256
|
+
[K in keyof TContract]: TContract[K] extends AnyContractRouter
|
|
257
|
+
? EffectImplementerInternal<
|
|
258
|
+
TContract[K],
|
|
259
|
+
TInitialContext,
|
|
260
|
+
TCurrentContext,
|
|
261
|
+
TRequirementsProvided,
|
|
262
|
+
TRuntimeError
|
|
263
|
+
>
|
|
264
|
+
: never;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export type EffectImplementer<
|
|
268
|
+
TContract extends AnyContractRouter,
|
|
269
|
+
TInitialContext extends Context,
|
|
270
|
+
TCurrentContext extends Context,
|
|
271
|
+
TRequirementsProvided,
|
|
272
|
+
TRuntimeError,
|
|
273
|
+
> = {
|
|
274
|
+
$context<U extends Context>(): EffectImplementer<
|
|
275
|
+
TContract,
|
|
276
|
+
U & Record<never, never>,
|
|
277
|
+
U,
|
|
278
|
+
TRequirementsProvided,
|
|
279
|
+
TRuntimeError
|
|
280
|
+
>;
|
|
281
|
+
$config(
|
|
282
|
+
config: BuilderConfig,
|
|
283
|
+
): EffectImplementer<
|
|
284
|
+
TContract,
|
|
285
|
+
TInitialContext,
|
|
286
|
+
TCurrentContext,
|
|
287
|
+
TRequirementsProvided,
|
|
288
|
+
TRuntimeError
|
|
289
|
+
>;
|
|
290
|
+
} & EffectImplementerInternal<
|
|
291
|
+
TContract,
|
|
292
|
+
TInitialContext,
|
|
293
|
+
TCurrentContext,
|
|
294
|
+
TRequirementsProvided,
|
|
295
|
+
TRuntimeError
|
|
296
|
+
>;
|
|
297
|
+
|
|
298
|
+
const CONTRACT_HIDDEN_METHODS = new Set([
|
|
299
|
+
"$config",
|
|
300
|
+
"$context",
|
|
301
|
+
"$input",
|
|
302
|
+
"$meta",
|
|
303
|
+
"$route",
|
|
304
|
+
"errors",
|
|
305
|
+
"input",
|
|
306
|
+
"lazy",
|
|
307
|
+
"meta",
|
|
308
|
+
"middleware",
|
|
309
|
+
"output",
|
|
310
|
+
"prefix",
|
|
311
|
+
"route",
|
|
312
|
+
"router",
|
|
313
|
+
"tag",
|
|
314
|
+
]);
|
|
315
|
+
|
|
316
|
+
function makeEnhanceOptions<TRequirementsProvided, TRuntimeError>(
|
|
317
|
+
runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>,
|
|
318
|
+
) {
|
|
319
|
+
return {
|
|
320
|
+
middlewares: [],
|
|
321
|
+
errorMap: {},
|
|
322
|
+
dedupeLeadingMiddlewares: true,
|
|
323
|
+
runtime,
|
|
324
|
+
} as const;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function wrapContractNode<
|
|
328
|
+
TContract extends AnyContractRouter,
|
|
329
|
+
TRequirementsProvided,
|
|
330
|
+
TRuntimeError,
|
|
331
|
+
>(
|
|
332
|
+
contract: TContract,
|
|
333
|
+
target: any,
|
|
334
|
+
runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>,
|
|
335
|
+
): EffectImplementerInternal<
|
|
336
|
+
TContract,
|
|
337
|
+
Context,
|
|
338
|
+
Context,
|
|
339
|
+
TRequirementsProvided,
|
|
340
|
+
TRuntimeError
|
|
341
|
+
> {
|
|
342
|
+
const cache = new Map<PropertyKey, unknown>();
|
|
343
|
+
|
|
344
|
+
return new Proxy(target, {
|
|
345
|
+
get(currentTarget, prop, receiver) {
|
|
346
|
+
if (cache.has(prop)) {
|
|
347
|
+
return cache.get(prop);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (isContractProcedure(contract)) {
|
|
351
|
+
if (prop === "effect") {
|
|
352
|
+
const effect = (
|
|
353
|
+
effectFn: ContractLeafEffectHandler<any, any, any, any, any, any>,
|
|
354
|
+
) => {
|
|
355
|
+
const effectErrorMap =
|
|
356
|
+
getEffectContractErrorMap(contract) ??
|
|
357
|
+
currentTarget["~orpc"].errorMap;
|
|
358
|
+
|
|
359
|
+
return new EffectDecoratedProcedure({
|
|
360
|
+
...currentTarget["~orpc"],
|
|
361
|
+
errorMap: effectErrorMapToErrorMap(effectErrorMap),
|
|
362
|
+
effectErrorMap,
|
|
363
|
+
runtime,
|
|
364
|
+
handler: createEffectProcedureHandler({
|
|
365
|
+
runtime,
|
|
366
|
+
effectErrorMap,
|
|
367
|
+
effectFn,
|
|
368
|
+
defaultCaptureStackTrace: addSpanStackTrace(),
|
|
369
|
+
}),
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
cache.set(prop, effect);
|
|
374
|
+
return effect;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (prop === "use") {
|
|
378
|
+
const use = (...args: unknown[]) =>
|
|
379
|
+
wrapContractNode(
|
|
380
|
+
contract,
|
|
381
|
+
Reflect.apply(
|
|
382
|
+
Reflect.get(currentTarget, prop, currentTarget),
|
|
383
|
+
currentTarget,
|
|
384
|
+
args,
|
|
385
|
+
),
|
|
386
|
+
runtime,
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
cache.set(prop, use);
|
|
390
|
+
return use;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (CONTRACT_HIDDEN_METHODS.has(String(prop))) {
|
|
394
|
+
return undefined;
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
if (prop === "$context" || prop === "$config" || prop === "use") {
|
|
398
|
+
const wrappedMethod = (...args: unknown[]) =>
|
|
399
|
+
wrapContractNode(
|
|
400
|
+
contract,
|
|
401
|
+
Reflect.apply(
|
|
402
|
+
Reflect.get(currentTarget, prop, currentTarget),
|
|
403
|
+
currentTarget,
|
|
404
|
+
args,
|
|
405
|
+
),
|
|
406
|
+
runtime,
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
cache.set(prop, wrappedMethod);
|
|
410
|
+
return wrappedMethod;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (prop === "router" || prop === "lazy") {
|
|
414
|
+
const wrappedMethod = (...args: unknown[]) =>
|
|
415
|
+
enhanceEffectRouter(
|
|
416
|
+
Reflect.apply(
|
|
417
|
+
Reflect.get(currentTarget, prop, currentTarget),
|
|
418
|
+
currentTarget,
|
|
419
|
+
args,
|
|
420
|
+
) as any,
|
|
421
|
+
makeEnhanceOptions(runtime),
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
cache.set(prop, wrappedMethod);
|
|
425
|
+
return wrappedMethod;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (typeof prop === "string" && prop in contract) {
|
|
429
|
+
const child = wrapContractNode(
|
|
430
|
+
(contract as Record<string, AnyContractRouter>)[prop]!,
|
|
431
|
+
Reflect.get(currentTarget, prop, receiver),
|
|
432
|
+
runtime,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
cache.set(prop, child);
|
|
436
|
+
return child;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const value = Reflect.get(currentTarget, prop, receiver);
|
|
441
|
+
return typeof value === "function" ? value.bind(currentTarget) : value;
|
|
442
|
+
},
|
|
443
|
+
has(currentTarget, prop) {
|
|
444
|
+
if (isContractProcedure(contract)) {
|
|
445
|
+
if (prop === "effect") {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
if (CONTRACT_HIDDEN_METHODS.has(String(prop))) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
} else if (typeof prop === "string" && prop in contract) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return Reflect.has(currentTarget, prop);
|
|
456
|
+
},
|
|
457
|
+
}) as EffectImplementerInternal<
|
|
458
|
+
TContract,
|
|
459
|
+
Context,
|
|
460
|
+
Context,
|
|
461
|
+
TRequirementsProvided,
|
|
462
|
+
TRuntimeError
|
|
463
|
+
>;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
export function implementEffect<
|
|
467
|
+
TContract extends AnyContractRouter,
|
|
468
|
+
TRequirementsProvided,
|
|
469
|
+
TRuntimeError,
|
|
470
|
+
>(
|
|
471
|
+
contract: TContract,
|
|
472
|
+
runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>,
|
|
473
|
+
): EffectImplementer<
|
|
474
|
+
TContract,
|
|
475
|
+
Record<never, never>,
|
|
476
|
+
Record<never, never>,
|
|
477
|
+
TRequirementsProvided,
|
|
478
|
+
TRuntimeError
|
|
479
|
+
> {
|
|
480
|
+
return wrapContractNode(
|
|
481
|
+
contract,
|
|
482
|
+
implement(contract),
|
|
483
|
+
runtime,
|
|
484
|
+
) as EffectImplementer<
|
|
485
|
+
TContract,
|
|
486
|
+
Record<never, never>,
|
|
487
|
+
Record<never, never>,
|
|
488
|
+
TRequirementsProvided,
|
|
489
|
+
TRuntimeError
|
|
490
|
+
>;
|
|
491
|
+
}
|
package/src/effect-builder.ts
CHANGED
|
@@ -8,25 +8,19 @@ import type {
|
|
|
8
8
|
Route,
|
|
9
9
|
Schema,
|
|
10
10
|
} from "@orpc/contract";
|
|
11
|
-
import {
|
|
12
|
-
mergeMeta,
|
|
13
|
-
mergePrefix,
|
|
14
|
-
mergeRoute,
|
|
15
|
-
mergeTags,
|
|
16
|
-
ORPCError,
|
|
17
|
-
} from "@orpc/contract";
|
|
11
|
+
import { mergeMeta, mergePrefix, mergeRoute, mergeTags } from "@orpc/contract";
|
|
18
12
|
import type {
|
|
19
13
|
AnyMiddleware,
|
|
20
14
|
BuilderConfig,
|
|
21
15
|
BuilderDef,
|
|
22
16
|
Context,
|
|
17
|
+
DecoratedMiddleware,
|
|
23
18
|
Lazy,
|
|
24
19
|
MapInputMiddleware,
|
|
25
20
|
MergedCurrentContext,
|
|
26
21
|
MergedInitialContext,
|
|
27
22
|
Middleware,
|
|
28
23
|
ProcedureHandler,
|
|
29
|
-
ProcedureHandlerOptions,
|
|
30
24
|
Router,
|
|
31
25
|
} from "@orpc/server";
|
|
32
26
|
import {
|
|
@@ -38,21 +32,16 @@ import {
|
|
|
38
32
|
} from "@orpc/server";
|
|
39
33
|
import type { IntersectPick } from "@orpc/shared";
|
|
40
34
|
import type { ManagedRuntime } from "effect";
|
|
41
|
-
import { Cause, Effect, Exit, FiberRefs } from "effect";
|
|
42
35
|
|
|
43
36
|
import { enhanceEffectRouter } from "./effect-enhance-router";
|
|
44
37
|
import { EffectDecoratedProcedure } from "./effect-procedure";
|
|
45
|
-
import {
|
|
38
|
+
import { createEffectProcedureHandler } from "./effect-runtime";
|
|
46
39
|
import type {
|
|
47
40
|
EffectErrorConstructorMap,
|
|
48
41
|
EffectErrorMap,
|
|
49
42
|
MergedEffectErrorMap,
|
|
50
43
|
} from "./tagged-error";
|
|
51
|
-
import {
|
|
52
|
-
createEffectErrorConstructorMap,
|
|
53
|
-
effectErrorMapToErrorMap,
|
|
54
|
-
isORPCTaggedError,
|
|
55
|
-
} from "./tagged-error";
|
|
44
|
+
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
56
45
|
import type {
|
|
57
46
|
AnyBuilderLike,
|
|
58
47
|
EffectBuilderDef,
|
|
@@ -306,6 +295,35 @@ export class EffectBuilder<
|
|
|
306
295
|
});
|
|
307
296
|
}
|
|
308
297
|
|
|
298
|
+
/**
|
|
299
|
+
* Creates a middleware.
|
|
300
|
+
*
|
|
301
|
+
* @see {@link https://orpc.dev/docs/middleware Middleware Docs}
|
|
302
|
+
*/
|
|
303
|
+
middleware<
|
|
304
|
+
UOutContext extends IntersectPick<TCurrentContext, UOutContext>,
|
|
305
|
+
TInput,
|
|
306
|
+
TOutput = any,
|
|
307
|
+
>(
|
|
308
|
+
middleware: Middleware<
|
|
309
|
+
TInitialContext,
|
|
310
|
+
UOutContext,
|
|
311
|
+
TInput,
|
|
312
|
+
TOutput,
|
|
313
|
+
EffectErrorConstructorMap<TEffectErrorMap>,
|
|
314
|
+
TMeta
|
|
315
|
+
>,
|
|
316
|
+
): DecoratedMiddleware<
|
|
317
|
+
TInitialContext,
|
|
318
|
+
UOutContext,
|
|
319
|
+
TInput,
|
|
320
|
+
TOutput,
|
|
321
|
+
any,
|
|
322
|
+
TMeta
|
|
323
|
+
> {
|
|
324
|
+
return decorateMiddleware(middleware);
|
|
325
|
+
}
|
|
326
|
+
|
|
309
327
|
/**
|
|
310
328
|
* Adds type-safe custom errors.
|
|
311
329
|
* Supports both traditional oRPC error definitions and ORPCTaggedError classes.
|
|
@@ -603,79 +621,13 @@ export class EffectBuilder<
|
|
|
603
621
|
return new EffectDecoratedProcedure({
|
|
604
622
|
...this["~effect"],
|
|
605
623
|
handler: async (opts) => {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
input: opts.input,
|
|
614
|
-
path: opts.path,
|
|
615
|
-
procedure: opts.procedure,
|
|
616
|
-
signal: opts.signal,
|
|
617
|
-
lastEventId: opts.lastEventId,
|
|
618
|
-
errors: createEffectErrorConstructorMap(
|
|
619
|
-
this["~effect"].effectErrorMap,
|
|
620
|
-
),
|
|
621
|
-
};
|
|
622
|
-
const spanName = spanConfig?.name ?? opts.path.join(".");
|
|
623
|
-
const captureStackTrace =
|
|
624
|
-
spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
|
|
625
|
-
const resolver = Effect.fnUntraced(effectFn);
|
|
626
|
-
const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
|
|
627
|
-
captureStackTrace,
|
|
628
|
-
});
|
|
629
|
-
const parentFiberRefs = getCurrentFiberRefs();
|
|
630
|
-
const effectWithRefs = parentFiberRefs
|
|
631
|
-
? Effect.fiberIdWith((fiberId) =>
|
|
632
|
-
Effect.flatMap(Effect.getFiberRefs, (fiberRefs) =>
|
|
633
|
-
Effect.setFiberRefs(
|
|
634
|
-
FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs),
|
|
635
|
-
).pipe(Effect.andThen(tracedEffect)),
|
|
636
|
-
),
|
|
637
|
-
)
|
|
638
|
-
: tracedEffect;
|
|
639
|
-
const exit = await runtime.runPromiseExit(effectWithRefs, {
|
|
640
|
-
signal: opts.signal,
|
|
641
|
-
});
|
|
642
|
-
|
|
643
|
-
if (Exit.isFailure(exit)) {
|
|
644
|
-
throw Cause.match(exit.cause, {
|
|
645
|
-
onDie(defect) {
|
|
646
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
647
|
-
cause: defect,
|
|
648
|
-
});
|
|
649
|
-
},
|
|
650
|
-
onFail(error) {
|
|
651
|
-
if (isORPCTaggedError(error)) {
|
|
652
|
-
return error.toORPCError();
|
|
653
|
-
}
|
|
654
|
-
if (error instanceof ORPCError) {
|
|
655
|
-
return error;
|
|
656
|
-
}
|
|
657
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
658
|
-
cause: error,
|
|
659
|
-
});
|
|
660
|
-
},
|
|
661
|
-
onInterrupt(fiberId) {
|
|
662
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
663
|
-
cause: new Error(`${fiberId} Interrupted`),
|
|
664
|
-
});
|
|
665
|
-
},
|
|
666
|
-
onSequential(left) {
|
|
667
|
-
return left;
|
|
668
|
-
},
|
|
669
|
-
onEmpty: new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
670
|
-
cause: new Error("Unknown error"),
|
|
671
|
-
}),
|
|
672
|
-
onParallel(left) {
|
|
673
|
-
return left;
|
|
674
|
-
},
|
|
675
|
-
});
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
return exit.value;
|
|
624
|
+
return createEffectProcedureHandler({
|
|
625
|
+
runtime,
|
|
626
|
+
effectErrorMap: this["~effect"].effectErrorMap,
|
|
627
|
+
effectFn,
|
|
628
|
+
spanConfig,
|
|
629
|
+
defaultCaptureStackTrace,
|
|
630
|
+
})(opts as any);
|
|
679
631
|
},
|
|
680
632
|
});
|
|
681
633
|
}
|