effect-orpc 0.2.2 → 0.4.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 +225 -105
- package/dist/{chunk-VOWRLWZZ.js → chunk-IJP6L2XR.js} +6 -2
- package/dist/chunk-IJP6L2XR.js.map +1 -0
- package/dist/index.js +770 -282
- package/dist/index.js.map +1 -1
- package/dist/node.js +4 -3
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
- package/src/contract.ts +46 -11
- package/src/effect-builder.ts +295 -33
- package/src/effect-enhance-router.ts +3 -3
- package/src/effect-procedure.ts +205 -11
- package/src/effect-runtime.ts +445 -23
- package/src/extension/create-node-proxy.ts +17 -1
- package/src/extension/state.ts +16 -20
- package/src/fiber-context-bridge.ts +13 -0
- package/src/index.ts +1 -0
- package/src/node.ts +2 -1
- package/src/runtime-source.ts +76 -0
- package/src/tagged-error.ts +1 -10
- package/src/tests/contract.test.ts +21 -0
- package/src/tests/effect-builder.proxy.test.ts +4 -4
- package/src/tests/effect-builder.test.ts +544 -7
- package/src/tests/effect-error-map.test.ts +10 -10
- package/src/tests/effect-procedure.test.ts +9 -6
- package/src/tests/node-side-effect.test.ts +80 -0
- package/src/tests/parity.effect-builder.test.ts +10 -3
- package/src/tests/parity.effect-procedure.test.ts +24 -8
- package/src/tests/shared.ts +1 -25
- package/src/types/effect-builder-surface.ts +117 -1
- package/src/types/effect-procedure-surface.ts +98 -1
- package/src/types/index.ts +291 -5
- package/src/types/variants.ts +351 -18
- package/dist/chunk-VOWRLWZZ.js.map +0 -1
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
type Context,
|
|
17
17
|
type Lazyable,
|
|
18
18
|
} from "@orpc/server";
|
|
19
|
-
import type { ManagedRuntime } from "effect/ManagedRuntime";
|
|
20
19
|
|
|
21
20
|
import { EffectProcedure } from "./effect-procedure";
|
|
22
21
|
import { getEffectErrorMap, unwrapEffectUpstream } from "./extension/state";
|
|
22
|
+
import type { EffectRuntimeRunner } from "./runtime-source";
|
|
23
23
|
import { effectErrorMapToErrorMap, type EffectErrorMap } from "./tagged-error";
|
|
24
24
|
import type { EffectErrorMapToErrorMap, EnhancedEffectRouter } from "./types";
|
|
25
25
|
|
|
@@ -31,7 +31,7 @@ interface EnhanceEffectRouterOptions<
|
|
|
31
31
|
middlewares: readonly AnyMiddleware[];
|
|
32
32
|
errorMap: TEffectErrorMap;
|
|
33
33
|
dedupeLeadingMiddlewares: boolean;
|
|
34
|
-
|
|
34
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export function enhanceEffectRouter<
|
|
@@ -97,7 +97,7 @@ export function enhanceEffectRouter<
|
|
|
97
97
|
source["~orpc"].inputValidationIndex + newMiddlewareAdded,
|
|
98
98
|
outputValidationIndex:
|
|
99
99
|
source["~orpc"].outputValidationIndex + newMiddlewareAdded,
|
|
100
|
-
|
|
100
|
+
runner: options.runner,
|
|
101
101
|
}) as any;
|
|
102
102
|
}
|
|
103
103
|
|
package/src/effect-procedure.ts
CHANGED
|
@@ -9,14 +9,22 @@ import type {
|
|
|
9
9
|
ProcedureDef,
|
|
10
10
|
} from "@orpc/server";
|
|
11
11
|
import {
|
|
12
|
+
Procedure,
|
|
12
13
|
addMiddleware,
|
|
13
14
|
createActionableClient,
|
|
14
15
|
createProcedureClient,
|
|
15
16
|
decorateMiddleware,
|
|
16
|
-
Procedure,
|
|
17
17
|
} from "@orpc/server";
|
|
18
18
|
import type { MaybeOptionalOptions } from "@orpc/shared";
|
|
19
|
+
import { Layer } from "effect";
|
|
19
20
|
|
|
21
|
+
import {
|
|
22
|
+
createEffectOptionalProviderMiddleware,
|
|
23
|
+
createEffectPipelineMiddleware,
|
|
24
|
+
createEffectProcedureHandler,
|
|
25
|
+
createEffectProviderMiddleware,
|
|
26
|
+
isEffectMiddleware,
|
|
27
|
+
} from "./effect-runtime";
|
|
20
28
|
import { composeSurfaceProxy } from "./extension/compose-surfaces";
|
|
21
29
|
import {
|
|
22
30
|
createNodeProxy,
|
|
@@ -30,7 +38,11 @@ import {
|
|
|
30
38
|
} from "./extension/state";
|
|
31
39
|
import type { EffectErrorMap, MergedEffectErrorMap } from "./tagged-error";
|
|
32
40
|
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
33
|
-
import type {
|
|
41
|
+
import type {
|
|
42
|
+
EffectErrorMapToErrorMap,
|
|
43
|
+
EffectPipelineStep,
|
|
44
|
+
EffectProcedureDef,
|
|
45
|
+
} from "./types";
|
|
34
46
|
import type { EffectDecoratedProcedureSurface } from "./types/effect-procedure-surface";
|
|
35
47
|
|
|
36
48
|
type AnyProcedureLike = Procedure<any, any, any, any, any, any>;
|
|
@@ -66,6 +78,8 @@ const procedureVirtualDescriptors = {
|
|
|
66
78
|
callable: { enumerable: false },
|
|
67
79
|
errors: { enumerable: false },
|
|
68
80
|
meta: { enumerable: false },
|
|
81
|
+
provide: { enumerable: false },
|
|
82
|
+
provideOptional: { enumerable: false },
|
|
69
83
|
route: { enumerable: false },
|
|
70
84
|
use: { enumerable: false },
|
|
71
85
|
} as const;
|
|
@@ -75,6 +89,8 @@ const decoratedProcedureVirtualKeys = [
|
|
|
75
89
|
...baseProcedureVirtualKeys,
|
|
76
90
|
"errors",
|
|
77
91
|
"meta",
|
|
92
|
+
"provide",
|
|
93
|
+
"provideOptional",
|
|
78
94
|
"route",
|
|
79
95
|
"use",
|
|
80
96
|
"callable",
|
|
@@ -101,11 +117,69 @@ function getEffectProcedureDef(
|
|
|
101
117
|
): EffectProcedureDef<any, any, any, any, any, any, any, any> {
|
|
102
118
|
return {
|
|
103
119
|
...context.upstream["~orpc"],
|
|
120
|
+
effectSteps: context.state.effectSteps,
|
|
121
|
+
effectHandler: context.state.effectHandler,
|
|
104
122
|
effectErrorMap: context.state.effectErrorMap,
|
|
105
|
-
|
|
123
|
+
runner: context.state.runner,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function makeEffectProcedureHandler(
|
|
128
|
+
def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
|
|
129
|
+
) {
|
|
130
|
+
if (!def.effectHandler) {
|
|
131
|
+
return def.handler;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return createEffectProcedureHandler({
|
|
135
|
+
defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
|
|
136
|
+
effectErrorMap: def.effectErrorMap,
|
|
137
|
+
effectFn: def.effectHandler.effectFn,
|
|
138
|
+
effectSteps: def.effectSteps,
|
|
139
|
+
runner: def.runner,
|
|
140
|
+
spanConfig: def.effectHandler.spanConfig,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function withRebuiltEffectHandler(
|
|
145
|
+
def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
|
|
146
|
+
): EffectProcedureDef<any, any, any, any, any, any, any, any> {
|
|
147
|
+
return {
|
|
148
|
+
...def,
|
|
149
|
+
handler: makeEffectProcedureHandler(def),
|
|
106
150
|
};
|
|
107
151
|
}
|
|
108
152
|
|
|
153
|
+
function appendEffectStep(
|
|
154
|
+
def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
|
|
155
|
+
step: EffectPipelineStep,
|
|
156
|
+
): EffectProcedureDef<any, any, any, any, any, any, any, any> {
|
|
157
|
+
return withRebuiltEffectHandler({
|
|
158
|
+
...def,
|
|
159
|
+
effectSteps: [...(def.effectSteps ?? []), step],
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function flushEffectSteps(
|
|
164
|
+
def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
|
|
165
|
+
): EffectProcedureDef<any, any, any, any, any, any, any, any> {
|
|
166
|
+
if (!def.effectSteps?.length) {
|
|
167
|
+
return def;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const middleware = createEffectPipelineMiddleware({
|
|
171
|
+
effectErrorMap: def.effectErrorMap,
|
|
172
|
+
runner: def.runner,
|
|
173
|
+
steps: def.effectSteps,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return withRebuiltEffectHandler({
|
|
177
|
+
...def,
|
|
178
|
+
effectSteps: undefined,
|
|
179
|
+
middlewares: addMiddleware(def.middlewares, middleware),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
109
183
|
function createEffectProcedureProxy<
|
|
110
184
|
T extends AnyEffectProcedure | AnyEffectDecoratedProcedure,
|
|
111
185
|
>(
|
|
@@ -158,22 +232,113 @@ function createEffectProcedureProxy<
|
|
|
158
232
|
route: mergeRoute(getEffectProcedureDef(context).route, route),
|
|
159
233
|
});
|
|
160
234
|
});
|
|
235
|
+
case "provide":
|
|
236
|
+
return getOrCreateVirtualMethod(context, prop, () => {
|
|
237
|
+
return (tagOrLayer: any, provider?: any) => {
|
|
238
|
+
const def = getEffectProcedureDef(context);
|
|
239
|
+
|
|
240
|
+
if (Layer.isLayer(tagOrLayer)) {
|
|
241
|
+
const step = {
|
|
242
|
+
_tag: "provideLayer" as const,
|
|
243
|
+
layer: tagOrLayer,
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
if (def.effectHandler) {
|
|
247
|
+
return new EffectDecoratedProcedure(
|
|
248
|
+
appendEffectStep(def, step),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return new EffectDecoratedProcedure({
|
|
253
|
+
...def,
|
|
254
|
+
middlewares: addMiddleware(
|
|
255
|
+
def.middlewares,
|
|
256
|
+
createEffectPipelineMiddleware({
|
|
257
|
+
effectErrorMap: state.effectErrorMap,
|
|
258
|
+
runner: state.runner,
|
|
259
|
+
steps: [step],
|
|
260
|
+
}),
|
|
261
|
+
),
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (def.effectHandler) {
|
|
266
|
+
return new EffectDecoratedProcedure(
|
|
267
|
+
appendEffectStep(def, {
|
|
268
|
+
_tag: "provide",
|
|
269
|
+
provider,
|
|
270
|
+
tag: tagOrLayer,
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return new EffectDecoratedProcedure({
|
|
276
|
+
...def,
|
|
277
|
+
middlewares: addMiddleware(
|
|
278
|
+
def.middlewares,
|
|
279
|
+
createEffectProviderMiddleware({
|
|
280
|
+
effectErrorMap: state.effectErrorMap,
|
|
281
|
+
provider,
|
|
282
|
+
runner: state.runner,
|
|
283
|
+
tag: tagOrLayer,
|
|
284
|
+
}),
|
|
285
|
+
),
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
case "provideOptional":
|
|
290
|
+
return getOrCreateVirtualMethod(context, prop, () => {
|
|
291
|
+
return (tag: any, provider: any) => {
|
|
292
|
+
const def = getEffectProcedureDef(context);
|
|
293
|
+
|
|
294
|
+
if (def.effectHandler) {
|
|
295
|
+
return new EffectDecoratedProcedure(
|
|
296
|
+
appendEffectStep(def, {
|
|
297
|
+
_tag: "provideOptional",
|
|
298
|
+
provider,
|
|
299
|
+
tag,
|
|
300
|
+
}),
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
return new EffectDecoratedProcedure({
|
|
305
|
+
...def,
|
|
306
|
+
middlewares: addMiddleware(
|
|
307
|
+
def.middlewares,
|
|
308
|
+
createEffectOptionalProviderMiddleware({
|
|
309
|
+
effectErrorMap: state.effectErrorMap,
|
|
310
|
+
provider,
|
|
311
|
+
runner: state.runner,
|
|
312
|
+
tag,
|
|
313
|
+
}),
|
|
314
|
+
),
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
});
|
|
161
318
|
case "use":
|
|
162
319
|
return getOrCreateVirtualMethod(context, prop, () => {
|
|
163
320
|
return (
|
|
164
321
|
middleware: AnyMiddleware,
|
|
165
322
|
mapInput?: MapInputMiddleware<any, any>,
|
|
166
323
|
) => {
|
|
324
|
+
const def = getEffectProcedureDef(context);
|
|
325
|
+
if (!mapInput && isEffectMiddleware(middleware)) {
|
|
326
|
+
return new EffectDecoratedProcedure(
|
|
327
|
+
appendEffectStep(def, {
|
|
328
|
+
_tag: "middleware",
|
|
329
|
+
middleware,
|
|
330
|
+
}),
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const flushedDef = flushEffectSteps(def);
|
|
167
335
|
const mapped = mapInput
|
|
168
336
|
? decorateMiddleware(middleware).mapInput(mapInput)
|
|
169
337
|
: middleware;
|
|
170
338
|
|
|
171
339
|
return new EffectDecoratedProcedure({
|
|
172
|
-
...
|
|
173
|
-
middlewares: addMiddleware(
|
|
174
|
-
getEffectProcedureDef(context).middlewares,
|
|
175
|
-
mapped,
|
|
176
|
-
),
|
|
340
|
+
...flushedDef,
|
|
341
|
+
middlewares: addMiddleware(flushedDef.middlewares, mapped),
|
|
177
342
|
});
|
|
178
343
|
};
|
|
179
344
|
});
|
|
@@ -302,10 +467,13 @@ export class EffectProcedure<
|
|
|
302
467
|
>,
|
|
303
468
|
procedure?: AnyProcedureLike,
|
|
304
469
|
) {
|
|
305
|
-
|
|
306
|
-
|
|
470
|
+
const { effectSteps, effectHandler, ...procedureDef } = def;
|
|
471
|
+
super(procedureDef);
|
|
472
|
+
attachEffectState(this, procedure ?? new Procedure(procedureDef), {
|
|
473
|
+
effectSteps,
|
|
474
|
+
effectHandler,
|
|
307
475
|
effectErrorMap: def.effectErrorMap,
|
|
308
|
-
|
|
476
|
+
runner: def.runner,
|
|
309
477
|
});
|
|
310
478
|
|
|
311
479
|
if (new.target === EffectProcedure) {
|
|
@@ -402,6 +570,32 @@ export class EffectDecoratedProcedure<
|
|
|
402
570
|
TRequirementsProvided,
|
|
403
571
|
TRuntimeError
|
|
404
572
|
>["route"];
|
|
573
|
+
/**
|
|
574
|
+
* Provides a request-scoped Effect service to downstream procedures.
|
|
575
|
+
*/
|
|
576
|
+
declare provide: EffectDecoratedProcedureSurface<
|
|
577
|
+
TInitialContext,
|
|
578
|
+
TCurrentContext,
|
|
579
|
+
TInputSchema,
|
|
580
|
+
TOutputSchema,
|
|
581
|
+
TEffectErrorMap,
|
|
582
|
+
TMeta,
|
|
583
|
+
TRequirementsProvided,
|
|
584
|
+
TRuntimeError
|
|
585
|
+
>["provide"];
|
|
586
|
+
/**
|
|
587
|
+
* Optionally provides a request-scoped Effect service to downstream procedures.
|
|
588
|
+
*/
|
|
589
|
+
declare provideOptional: EffectDecoratedProcedureSurface<
|
|
590
|
+
TInitialContext,
|
|
591
|
+
TCurrentContext,
|
|
592
|
+
TInputSchema,
|
|
593
|
+
TOutputSchema,
|
|
594
|
+
TEffectErrorMap,
|
|
595
|
+
TMeta,
|
|
596
|
+
TRequirementsProvided,
|
|
597
|
+
TRuntimeError
|
|
598
|
+
>["provideOptional"];
|
|
405
599
|
/**
|
|
406
600
|
* Uses a middleware to modify the context or improve the pipeline.
|
|
407
601
|
*
|