effect-orpc 1.0.0-effect-v4.2 → 1.0.0-effect-v4.4
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 +495 -0
- package/dist/{chunk-E5YLLTJI.js → chunk-I5EWBI42.js} +1 -1
- package/dist/chunk-I5EWBI42.js.map +1 -0
- package/dist/index.js +356 -64
- package/dist/index.js.map +1 -1
- package/dist/node.js +2 -2
- package/dist/node.js.map +1 -1
- package/package.json +6 -6
- package/src/contract.ts +491 -0
- package/src/effect-builder.ts +42 -90
- package/src/effect-runtime.ts +144 -0
- package/src/eoc.ts +499 -0
- package/src/index.ts +18 -3
- package/src/node.ts +3 -3
- package/src/service-context-bridge.ts +3 -3
- package/src/tagged-error.ts +24 -4
- package/src/tests/contract.test.ts +348 -0
- package/src/tests/effect-builder.test.ts +5 -5
- 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 +26 -17
- package/dist/chunk-E5YLLTJI.js.map +0 -1
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,26 +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,
|
|
23
|
-
|
|
17
|
+
DecoratedMiddleware,
|
|
24
18
|
Lazy,
|
|
25
19
|
MapInputMiddleware,
|
|
26
20
|
MergedCurrentContext,
|
|
27
21
|
MergedInitialContext,
|
|
28
22
|
Middleware,
|
|
29
23
|
ProcedureHandler,
|
|
30
|
-
ProcedureHandlerOptions,
|
|
31
24
|
Router,
|
|
32
25
|
} from "@orpc/server";
|
|
33
26
|
import {
|
|
@@ -37,21 +30,18 @@ import {
|
|
|
37
30
|
fallbackConfig,
|
|
38
31
|
lazy,
|
|
39
32
|
} from "@orpc/server";
|
|
40
|
-
import {
|
|
33
|
+
import type { IntersectPick } from "@orpc/shared";
|
|
34
|
+
import type { ManagedRuntime } from "effect";
|
|
41
35
|
|
|
42
36
|
import { enhanceEffectRouter } from "./effect-enhance-router";
|
|
43
37
|
import { EffectDecoratedProcedure } from "./effect-procedure";
|
|
44
|
-
import {
|
|
38
|
+
import { createEffectProcedureHandler } from "./effect-runtime";
|
|
45
39
|
import type {
|
|
46
40
|
EffectErrorConstructorMap,
|
|
47
41
|
EffectErrorMap,
|
|
48
42
|
MergedEffectErrorMap,
|
|
49
43
|
} from "./tagged-error";
|
|
50
|
-
import {
|
|
51
|
-
createEffectErrorConstructorMap,
|
|
52
|
-
effectErrorMapToErrorMap,
|
|
53
|
-
isORPCTaggedError,
|
|
54
|
-
} from "./tagged-error";
|
|
44
|
+
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
55
45
|
import type {
|
|
56
46
|
AnyBuilderLike,
|
|
57
47
|
EffectBuilderDef,
|
|
@@ -98,41 +88,6 @@ export function addSpanStackTrace(): () => string | undefined {
|
|
|
98
88
|
};
|
|
99
89
|
}
|
|
100
90
|
|
|
101
|
-
function toORPCErrorFromCause(
|
|
102
|
-
cause: Cause.Cause<unknown>,
|
|
103
|
-
): ORPCError<string, unknown> {
|
|
104
|
-
const reason = cause.reasons[0];
|
|
105
|
-
|
|
106
|
-
if (reason === undefined) {
|
|
107
|
-
return new ORPCError("INTERNAL_SERVER_ERROR");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (Cause.isDieReason(reason)) {
|
|
111
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
112
|
-
cause: reason.defect,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (Cause.isFailReason(reason)) {
|
|
117
|
-
const error = reason.error;
|
|
118
|
-
|
|
119
|
-
if (isORPCTaggedError(error)) {
|
|
120
|
-
return error.toORPCError();
|
|
121
|
-
}
|
|
122
|
-
if (error instanceof ORPCError) {
|
|
123
|
-
return error;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
127
|
-
cause: error,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return new ORPCError("INTERNAL_SERVER_ERROR", {
|
|
132
|
-
cause: new Error(`${reason.fiberId} Interrupted`),
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
91
|
/**
|
|
137
92
|
* Effect-native procedure builder that wraps an oRPC Builder instance
|
|
138
93
|
* and adds Effect-specific capabilities while preserving Effect error
|
|
@@ -340,6 +295,35 @@ export class EffectBuilder<
|
|
|
340
295
|
});
|
|
341
296
|
}
|
|
342
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
|
+
|
|
343
327
|
/**
|
|
344
328
|
* Adds type-safe custom errors.
|
|
345
329
|
* Supports both traditional oRPC error definitions and ORPCTaggedError classes.
|
|
@@ -637,45 +621,13 @@ export class EffectBuilder<
|
|
|
637
621
|
return new EffectDecoratedProcedure({
|
|
638
622
|
...this["~effect"],
|
|
639
623
|
handler: async (opts) => {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
input: opts.input,
|
|
648
|
-
path: opts.path,
|
|
649
|
-
procedure: opts.procedure,
|
|
650
|
-
signal: opts.signal,
|
|
651
|
-
lastEventId: opts.lastEventId,
|
|
652
|
-
errors: createEffectErrorConstructorMap(
|
|
653
|
-
this["~effect"].effectErrorMap,
|
|
654
|
-
),
|
|
655
|
-
};
|
|
656
|
-
const spanName = spanConfig?.name ?? opts.path.join(".");
|
|
657
|
-
const captureStackTrace =
|
|
658
|
-
spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
|
|
659
|
-
const resolver = Effect.fnUntraced(effectFn);
|
|
660
|
-
const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
|
|
661
|
-
captureStackTrace,
|
|
662
|
-
});
|
|
663
|
-
const parentServices = getCurrentServices();
|
|
664
|
-
const exit = parentServices
|
|
665
|
-
? await Effect.runPromiseExitWith(
|
|
666
|
-
ServiceMap.merge(await runtime.services(), parentServices),
|
|
667
|
-
)(tracedEffect, {
|
|
668
|
-
signal: opts.signal,
|
|
669
|
-
})
|
|
670
|
-
: await runtime.runPromiseExit(tracedEffect, {
|
|
671
|
-
signal: opts.signal,
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
if (Exit.isFailure(exit)) {
|
|
675
|
-
throw toORPCErrorFromCause(exit.cause);
|
|
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
|
}
|