effect-orpc 0.3.0 → 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 +63 -64
- package/dist/index.js +78 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/contract.ts +15 -12
- package/src/effect-builder.ts +28 -19
- package/src/effect-enhance-router.ts +3 -3
- package/src/effect-procedure.ts +7 -7
- package/src/effect-runtime.ts +27 -37
- package/src/extension/state.ts +3 -5
- package/src/index.ts +1 -0
- package/src/runtime-source.ts +70 -12
- package/src/tagged-error.ts +1 -1
- package/src/tests/contract.test.ts +5 -8
- package/src/tests/effect-builder.proxy.test.ts +4 -4
- package/src/tests/effect-builder.test.ts +56 -22
- package/src/tests/effect-error-map.test.ts +10 -10
- package/src/tests/effect-procedure.test.ts +9 -6
- package/src/types/effect-builder-surface.ts +1 -1
- package/src/types/index.ts +6 -11
- package/src/types/variants.ts +5 -5
package/package.json
CHANGED
package/src/contract.ts
CHANGED
|
@@ -34,8 +34,11 @@ import { enhanceEffectRouter } from "./effect-enhance-router";
|
|
|
34
34
|
import { EffectDecoratedProcedure } from "./effect-procedure";
|
|
35
35
|
import { createEffectProcedureHandler } from "./effect-runtime";
|
|
36
36
|
import { effectContractSymbol, getEffectContractErrorMap } from "./eoc";
|
|
37
|
-
import type {
|
|
38
|
-
|
|
37
|
+
import type {
|
|
38
|
+
EffectRuntimeRunner,
|
|
39
|
+
EffectRuntimeSource,
|
|
40
|
+
} from "./runtime-source";
|
|
41
|
+
import { makeEffectRuntimeRunner } from "./runtime-source";
|
|
39
42
|
import type { EffectErrorMap } from "./tagged-error";
|
|
40
43
|
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
41
44
|
import type { EffectErrorMapToErrorMap, EffectProcedureHandler } from "./types";
|
|
@@ -316,13 +319,13 @@ const CONTRACT_HIDDEN_METHODS = new Set([
|
|
|
316
319
|
]);
|
|
317
320
|
|
|
318
321
|
function makeEnhanceOptions<TRequirementsProvided, TRuntimeError>(
|
|
319
|
-
|
|
322
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>,
|
|
320
323
|
) {
|
|
321
324
|
return {
|
|
322
325
|
middlewares: [],
|
|
323
326
|
errorMap: {},
|
|
324
327
|
dedupeLeadingMiddlewares: true,
|
|
325
|
-
|
|
328
|
+
runner,
|
|
326
329
|
} as const;
|
|
327
330
|
}
|
|
328
331
|
|
|
@@ -333,7 +336,7 @@ function wrapContractNode<
|
|
|
333
336
|
>(
|
|
334
337
|
contract: TContract,
|
|
335
338
|
target: any,
|
|
336
|
-
|
|
339
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>,
|
|
337
340
|
): EffectImplementerInternal<
|
|
338
341
|
TContract,
|
|
339
342
|
Context,
|
|
@@ -362,9 +365,9 @@ function wrapContractNode<
|
|
|
362
365
|
...currentTarget["~orpc"],
|
|
363
366
|
errorMap: effectErrorMapToErrorMap(effectErrorMap),
|
|
364
367
|
effectErrorMap,
|
|
365
|
-
|
|
368
|
+
runner,
|
|
366
369
|
handler: createEffectProcedureHandler({
|
|
367
|
-
|
|
370
|
+
runner,
|
|
368
371
|
effectErrorMap,
|
|
369
372
|
effectFn,
|
|
370
373
|
defaultCaptureStackTrace: addSpanStackTrace(),
|
|
@@ -385,7 +388,7 @@ function wrapContractNode<
|
|
|
385
388
|
currentTarget,
|
|
386
389
|
args,
|
|
387
390
|
),
|
|
388
|
-
|
|
391
|
+
runner,
|
|
389
392
|
);
|
|
390
393
|
|
|
391
394
|
cache.set(prop, use);
|
|
@@ -405,7 +408,7 @@ function wrapContractNode<
|
|
|
405
408
|
currentTarget,
|
|
406
409
|
args,
|
|
407
410
|
),
|
|
408
|
-
|
|
411
|
+
runner,
|
|
409
412
|
);
|
|
410
413
|
|
|
411
414
|
cache.set(prop, wrappedMethod);
|
|
@@ -420,7 +423,7 @@ function wrapContractNode<
|
|
|
420
423
|
currentTarget,
|
|
421
424
|
args,
|
|
422
425
|
) as any,
|
|
423
|
-
makeEnhanceOptions(
|
|
426
|
+
makeEnhanceOptions(runner),
|
|
424
427
|
);
|
|
425
428
|
|
|
426
429
|
cache.set(prop, wrappedMethod);
|
|
@@ -431,7 +434,7 @@ function wrapContractNode<
|
|
|
431
434
|
const child = wrapContractNode(
|
|
432
435
|
(contract as Record<string, AnyContractRouter>)[prop]!,
|
|
433
436
|
Reflect.get(currentTarget, prop, receiver),
|
|
434
|
-
|
|
437
|
+
runner,
|
|
435
438
|
);
|
|
436
439
|
|
|
437
440
|
cache.set(prop, child);
|
|
@@ -512,7 +515,7 @@ export function implementEffect<
|
|
|
512
515
|
return wrapContractNode(
|
|
513
516
|
contract,
|
|
514
517
|
implement(contract),
|
|
515
|
-
|
|
518
|
+
makeEffectRuntimeRunner(source),
|
|
516
519
|
) as EffectImplementer<
|
|
517
520
|
TContract,
|
|
518
521
|
Record<never, never>,
|
package/src/effect-builder.ts
CHANGED
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
type EffectProxyTarget,
|
|
29
29
|
} from "./extension/state";
|
|
30
30
|
import type { EffectRuntimeSource } from "./runtime-source";
|
|
31
|
-
import {
|
|
31
|
+
import { makeEffectRuntimeRunner } from "./runtime-source";
|
|
32
32
|
import type { EffectErrorMap, MergedEffectErrorMap } from "./tagged-error";
|
|
33
33
|
import { effectErrorMapToErrorMap } from "./tagged-error";
|
|
34
34
|
import type {
|
|
@@ -106,7 +106,7 @@ function getEffectBuilderDef(
|
|
|
106
106
|
return {
|
|
107
107
|
...context.upstream["~orpc"],
|
|
108
108
|
effectErrorMap: context.state.effectErrorMap,
|
|
109
|
-
|
|
109
|
+
runner: context.state.runner,
|
|
110
110
|
spanConfig: context.state.spanConfig,
|
|
111
111
|
effectSteps: context.state.effectSteps,
|
|
112
112
|
effectHandler: context.state.effectHandler,
|
|
@@ -121,7 +121,7 @@ function wrapBuilderLike(
|
|
|
121
121
|
{
|
|
122
122
|
...builder["~orpc"],
|
|
123
123
|
effectErrorMap: state.effectErrorMap,
|
|
124
|
-
|
|
124
|
+
runner: state.runner,
|
|
125
125
|
spanConfig: state.spanConfig,
|
|
126
126
|
effectSteps: state.effectSteps,
|
|
127
127
|
effectHandler: state.effectHandler,
|
|
@@ -158,7 +158,7 @@ function flushEffectSteps(
|
|
|
158
158
|
|
|
159
159
|
const middleware = createEffectPipelineMiddleware({
|
|
160
160
|
effectErrorMap: state.effectErrorMap,
|
|
161
|
-
|
|
161
|
+
runner: state.runner,
|
|
162
162
|
steps: state.effectSteps,
|
|
163
163
|
});
|
|
164
164
|
return {
|
|
@@ -238,7 +238,7 @@ function createEffectBuilderProxy(
|
|
|
238
238
|
effectErrorMap: state.effectErrorMap,
|
|
239
239
|
effectFn,
|
|
240
240
|
effectSteps: state.effectSteps,
|
|
241
|
-
|
|
241
|
+
runner: state.runner,
|
|
242
242
|
spanConfig: state.spanConfig,
|
|
243
243
|
})(opts as any);
|
|
244
244
|
},
|
|
@@ -251,7 +251,7 @@ function createEffectBuilderProxy(
|
|
|
251
251
|
if (isEffectMiddleware(middleware)) {
|
|
252
252
|
const effectMiddleware = createEffectPipelineMiddleware({
|
|
253
253
|
effectErrorMap: state.effectErrorMap,
|
|
254
|
-
|
|
254
|
+
runner: state.runner,
|
|
255
255
|
steps: [
|
|
256
256
|
...(state.effectSteps ?? []),
|
|
257
257
|
{ _tag: "middleware" as const, middleware },
|
|
@@ -698,7 +698,7 @@ export class EffectBuilder<
|
|
|
698
698
|
*
|
|
699
699
|
* @example
|
|
700
700
|
* ```ts
|
|
701
|
-
* const getUser =
|
|
701
|
+
* const getUser = effectProcedure
|
|
702
702
|
* .input(z.object({ id: z.string() }))
|
|
703
703
|
* .traced('users.getUser')
|
|
704
704
|
* .effect(function* ({ input }) {
|
|
@@ -734,7 +734,7 @@ export class EffectBuilder<
|
|
|
734
734
|
>["handler"];
|
|
735
735
|
/**
|
|
736
736
|
* Defines the handler of the procedure using an Effect.
|
|
737
|
-
* The Effect is executed using the
|
|
737
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
738
738
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
739
739
|
*
|
|
740
740
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
|
@@ -826,14 +826,13 @@ export class EffectBuilder<
|
|
|
826
826
|
>,
|
|
827
827
|
builder?: AnyBuilderLike,
|
|
828
828
|
) {
|
|
829
|
-
const {
|
|
830
|
-
def;
|
|
829
|
+
const { runner, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
|
|
831
830
|
|
|
832
831
|
attachEffectState(this, builder ?? new Builder(orpcDef), {
|
|
833
832
|
effectSteps,
|
|
834
833
|
effectHandler: def.effectHandler,
|
|
835
834
|
effectErrorMap,
|
|
836
|
-
|
|
835
|
+
runner,
|
|
837
836
|
spanConfig,
|
|
838
837
|
});
|
|
839
838
|
|
|
@@ -853,9 +852,9 @@ export class EffectBuilder<
|
|
|
853
852
|
* import { makeEffectORPC } from '@orpc/effect'
|
|
854
853
|
* import { Effect, Layer } from 'effect'
|
|
855
854
|
*
|
|
856
|
-
* const
|
|
855
|
+
* const effectProcedure = makeEffectORPC(Layer.empty)
|
|
857
856
|
*
|
|
858
|
-
* const hello =
|
|
857
|
+
* const hello = effectProcedure.effect(() => Effect.succeed('Hello!'))
|
|
859
858
|
* ```
|
|
860
859
|
*/
|
|
861
860
|
export function makeEffectORPC(): EffectBuilder<
|
|
@@ -943,9 +942,9 @@ export function makeEffectORPC<TRequirementsProvided, TRuntimeError>(
|
|
|
943
942
|
* const authedOs = os.use(authMiddleware)
|
|
944
943
|
*
|
|
945
944
|
* // Wrap it with Effect support
|
|
946
|
-
* const
|
|
945
|
+
* const effectProcedure = makeEffectORPC(UserServiceLive, authedOs)
|
|
947
946
|
*
|
|
948
|
-
* const getUser =
|
|
947
|
+
* const getUser = effectProcedure
|
|
949
948
|
* .input(z.object({ id: z.string() }))
|
|
950
949
|
* .effect(
|
|
951
950
|
* Effect.fn(function* ({ input }) {
|
|
@@ -1025,15 +1024,16 @@ export function makeEffectORPC(
|
|
|
1025
1024
|
? source
|
|
1026
1025
|
: (builder ?? emptyBuilder());
|
|
1027
1026
|
const effectErrorMap = getEffectErrorMap(resolvedBuilder);
|
|
1028
|
-
const
|
|
1029
|
-
sourceIsBuilder || source === undefined
|
|
1030
|
-
|
|
1027
|
+
const runner =
|
|
1028
|
+
sourceIsBuilder || source === undefined
|
|
1029
|
+
? makeEffectRuntimeRunner()
|
|
1030
|
+
: makeEffectRuntimeRunner(source);
|
|
1031
1031
|
return new EffectBuilder(
|
|
1032
1032
|
{
|
|
1033
1033
|
...resolvedBuilder["~orpc"],
|
|
1034
1034
|
effectErrorMap: effectErrorMap,
|
|
1035
1035
|
errorMap: effectErrorMapToErrorMap(effectErrorMap),
|
|
1036
|
-
|
|
1036
|
+
runner,
|
|
1037
1037
|
},
|
|
1038
1038
|
unwrapEffectUpstream(resolvedBuilder),
|
|
1039
1039
|
);
|
|
@@ -1051,3 +1051,12 @@ function emptyBuilder(): AnyBuilderLike {
|
|
|
1051
1051
|
route: {},
|
|
1052
1052
|
});
|
|
1053
1053
|
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Runtime-less Effect oRPC builder, analogous to oRPC's `os` export.
|
|
1057
|
+
*
|
|
1058
|
+
* Provide application services with `.provide(layer)` or use
|
|
1059
|
+
* `makeEffectORPC(runtime)` when you need explicit ManagedRuntime lifecycle
|
|
1060
|
+
* control.
|
|
1061
|
+
*/
|
|
1062
|
+
export const eos = makeEffectORPC();
|
|
@@ -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
|
@@ -120,7 +120,7 @@ function getEffectProcedureDef(
|
|
|
120
120
|
effectSteps: context.state.effectSteps,
|
|
121
121
|
effectHandler: context.state.effectHandler,
|
|
122
122
|
effectErrorMap: context.state.effectErrorMap,
|
|
123
|
-
|
|
123
|
+
runner: context.state.runner,
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -136,7 +136,7 @@ function makeEffectProcedureHandler(
|
|
|
136
136
|
effectErrorMap: def.effectErrorMap,
|
|
137
137
|
effectFn: def.effectHandler.effectFn,
|
|
138
138
|
effectSteps: def.effectSteps,
|
|
139
|
-
|
|
139
|
+
runner: def.runner,
|
|
140
140
|
spanConfig: def.effectHandler.spanConfig,
|
|
141
141
|
});
|
|
142
142
|
}
|
|
@@ -169,7 +169,7 @@ function flushEffectSteps(
|
|
|
169
169
|
|
|
170
170
|
const middleware = createEffectPipelineMiddleware({
|
|
171
171
|
effectErrorMap: def.effectErrorMap,
|
|
172
|
-
|
|
172
|
+
runner: def.runner,
|
|
173
173
|
steps: def.effectSteps,
|
|
174
174
|
});
|
|
175
175
|
|
|
@@ -255,7 +255,7 @@ function createEffectProcedureProxy<
|
|
|
255
255
|
def.middlewares,
|
|
256
256
|
createEffectPipelineMiddleware({
|
|
257
257
|
effectErrorMap: state.effectErrorMap,
|
|
258
|
-
|
|
258
|
+
runner: state.runner,
|
|
259
259
|
steps: [step],
|
|
260
260
|
}),
|
|
261
261
|
),
|
|
@@ -279,7 +279,7 @@ function createEffectProcedureProxy<
|
|
|
279
279
|
createEffectProviderMiddleware({
|
|
280
280
|
effectErrorMap: state.effectErrorMap,
|
|
281
281
|
provider,
|
|
282
|
-
|
|
282
|
+
runner: state.runner,
|
|
283
283
|
tag: tagOrLayer,
|
|
284
284
|
}),
|
|
285
285
|
),
|
|
@@ -308,7 +308,7 @@ function createEffectProcedureProxy<
|
|
|
308
308
|
createEffectOptionalProviderMiddleware({
|
|
309
309
|
effectErrorMap: state.effectErrorMap,
|
|
310
310
|
provider,
|
|
311
|
-
|
|
311
|
+
runner: state.runner,
|
|
312
312
|
tag,
|
|
313
313
|
}),
|
|
314
314
|
),
|
|
@@ -473,7 +473,7 @@ export class EffectProcedure<
|
|
|
473
473
|
effectSteps,
|
|
474
474
|
effectHandler,
|
|
475
475
|
effectErrorMap: def.effectErrorMap,
|
|
476
|
-
|
|
476
|
+
runner: def.runner,
|
|
477
477
|
});
|
|
478
478
|
|
|
479
479
|
if (new.target === EffectProcedure) {
|
package/src/effect-runtime.ts
CHANGED
|
@@ -9,10 +9,10 @@ import type {
|
|
|
9
9
|
ProcedureHandlerOptions,
|
|
10
10
|
} from "@orpc/server";
|
|
11
11
|
import type { Promisable } from "@orpc/shared";
|
|
12
|
-
import
|
|
13
|
-
import { Cause, Effect, Exit, FiberRefs, Option } from "effect";
|
|
12
|
+
import { Cause, Effect, Exit, Option } from "effect";
|
|
14
13
|
|
|
15
|
-
import {
|
|
14
|
+
import { runWithFiberRefs } from "./fiber-context-bridge";
|
|
15
|
+
import type { EffectRuntimeRunner } from "./runtime-source";
|
|
16
16
|
import type { EffectErrorConstructorMap, EffectErrorMap } from "./tagged-error";
|
|
17
17
|
import {
|
|
18
18
|
createEffectErrorConstructorMap,
|
|
@@ -78,7 +78,7 @@ export function createEffectProcedureHandler<
|
|
|
78
78
|
TRuntimeError,
|
|
79
79
|
TMeta extends Meta,
|
|
80
80
|
>(options: {
|
|
81
|
-
|
|
81
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
82
82
|
effectErrorMap: TEffectErrorMap;
|
|
83
83
|
effectFn: EffectProcedureHandler<
|
|
84
84
|
TCurrentContext,
|
|
@@ -99,7 +99,7 @@ export function createEffectProcedureHandler<
|
|
|
99
99
|
TMeta & Record<never, never>
|
|
100
100
|
> {
|
|
101
101
|
const {
|
|
102
|
-
|
|
102
|
+
runner,
|
|
103
103
|
effectErrorMap,
|
|
104
104
|
effectFn,
|
|
105
105
|
effectSteps = [],
|
|
@@ -145,10 +145,9 @@ export function createEffectProcedureHandler<
|
|
|
145
145
|
spanName,
|
|
146
146
|
{ captureStackTrace },
|
|
147
147
|
);
|
|
148
|
-
const exit = await
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
);
|
|
148
|
+
const exit = await runner.runPromiseExit(tracedEffect, {
|
|
149
|
+
signal: opts.signal,
|
|
150
|
+
});
|
|
152
151
|
|
|
153
152
|
if (Exit.isFailure(exit)) {
|
|
154
153
|
throw toORPCErrorFromCause(exit.cause);
|
|
@@ -166,7 +165,7 @@ export function createEffectPipelineMiddleware<
|
|
|
166
165
|
TRuntimeError,
|
|
167
166
|
TMeta extends Meta,
|
|
168
167
|
>(options: {
|
|
169
|
-
|
|
168
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
170
169
|
effectErrorMap: TEffectErrorMap;
|
|
171
170
|
steps: readonly EffectPipelineStep[];
|
|
172
171
|
}): Middleware<
|
|
@@ -177,7 +176,7 @@ export function createEffectPipelineMiddleware<
|
|
|
177
176
|
any,
|
|
178
177
|
TMeta
|
|
179
178
|
> {
|
|
180
|
-
const {
|
|
179
|
+
const { runner, effectErrorMap, steps } = options;
|
|
181
180
|
|
|
182
181
|
return async (opts, input) => {
|
|
183
182
|
const baseOptions = makeEffectOptions<
|
|
@@ -186,7 +185,14 @@ export function createEffectPipelineMiddleware<
|
|
|
186
185
|
TEffectErrorMap,
|
|
187
186
|
TMeta
|
|
188
187
|
>(opts, input, effectErrorMap);
|
|
189
|
-
const effect = runEffectPipeline
|
|
188
|
+
const effect = runEffectPipeline<
|
|
189
|
+
TCurrentContext,
|
|
190
|
+
unknown,
|
|
191
|
+
TOutput,
|
|
192
|
+
TEffectErrorMap,
|
|
193
|
+
TRequirementsProvided,
|
|
194
|
+
TMeta
|
|
195
|
+
>({
|
|
190
196
|
baseOptions,
|
|
191
197
|
effectErrorMap,
|
|
192
198
|
final: (context) =>
|
|
@@ -200,10 +206,9 @@ export function createEffectPipelineMiddleware<
|
|
|
200
206
|
input,
|
|
201
207
|
steps,
|
|
202
208
|
});
|
|
203
|
-
const exit = await
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
);
|
|
209
|
+
const exit = await runner.runPromiseExit(effect, {
|
|
210
|
+
signal: opts.signal,
|
|
211
|
+
});
|
|
207
212
|
|
|
208
213
|
if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
|
|
209
214
|
|
|
@@ -220,7 +225,7 @@ export function createEffectProviderMiddleware<
|
|
|
220
225
|
TMeta extends Meta,
|
|
221
226
|
TTag extends EffectTag,
|
|
222
227
|
>(options: {
|
|
223
|
-
|
|
228
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
224
229
|
effectErrorMap: TEffectErrorMap;
|
|
225
230
|
tag: TTag;
|
|
226
231
|
provider: EffectProvider<
|
|
@@ -232,7 +237,7 @@ export function createEffectProviderMiddleware<
|
|
|
232
237
|
TTag
|
|
233
238
|
>;
|
|
234
239
|
}): Middleware<TCurrentContext, Record<never, never>, TInput, any, any, TMeta> {
|
|
235
|
-
const {
|
|
240
|
+
const { runner, effectErrorMap, tag, provider } = options;
|
|
236
241
|
|
|
237
242
|
return async (opts, input) => {
|
|
238
243
|
const effectOpts = makeEffectOptions<
|
|
@@ -248,7 +253,7 @@ export function createEffectProviderMiddleware<
|
|
|
248
253
|
service,
|
|
249
254
|
),
|
|
250
255
|
);
|
|
251
|
-
const exit = await
|
|
256
|
+
const exit = await runner.runPromiseExit(effect, {
|
|
252
257
|
signal: opts.signal,
|
|
253
258
|
});
|
|
254
259
|
|
|
@@ -267,7 +272,7 @@ export function createEffectOptionalProviderMiddleware<
|
|
|
267
272
|
TMeta extends Meta,
|
|
268
273
|
TTag extends EffectTag,
|
|
269
274
|
>(options: {
|
|
270
|
-
|
|
275
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
271
276
|
effectErrorMap: TEffectErrorMap;
|
|
272
277
|
tag: TTag;
|
|
273
278
|
provider: EffectOptionalProvider<
|
|
@@ -279,7 +284,7 @@ export function createEffectOptionalProviderMiddleware<
|
|
|
279
284
|
TTag
|
|
280
285
|
>;
|
|
281
286
|
}): Middleware<TCurrentContext, Record<never, never>, TInput, any, any, TMeta> {
|
|
282
|
-
const {
|
|
287
|
+
const { runner, effectErrorMap, tag, provider } = options;
|
|
283
288
|
|
|
284
289
|
return async (opts, input) => {
|
|
285
290
|
const effectOpts = makeEffectOptions<
|
|
@@ -299,7 +304,7 @@ export function createEffectOptionalProviderMiddleware<
|
|
|
299
304
|
),
|
|
300
305
|
}),
|
|
301
306
|
);
|
|
302
|
-
const exit = await
|
|
307
|
+
const exit = await runner.runPromiseExit(effect, {
|
|
303
308
|
signal: opts.signal,
|
|
304
309
|
});
|
|
305
310
|
|
|
@@ -549,18 +554,3 @@ function withCurrentFiberContext<T>(fn: () => Promisable<T>): Effect.Effect<T> {
|
|
|
549
554
|
),
|
|
550
555
|
);
|
|
551
556
|
}
|
|
552
|
-
|
|
553
|
-
function withParentFiberRefs<A, E, R>(
|
|
554
|
-
effect: Effect.Effect<A, E, R>,
|
|
555
|
-
): Effect.Effect<A, E, R> {
|
|
556
|
-
const parentFiberRefs = getCurrentFiberRefs();
|
|
557
|
-
return parentFiberRefs
|
|
558
|
-
? Effect.fiberIdWith((fiberId) =>
|
|
559
|
-
Effect.flatMap(Effect.getFiberRefs, (fiberRefs) =>
|
|
560
|
-
Effect.setFiberRefs(
|
|
561
|
-
FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs),
|
|
562
|
-
).pipe(Effect.andThen(effect)),
|
|
563
|
-
),
|
|
564
|
-
)
|
|
565
|
-
: effect;
|
|
566
|
-
}
|
package/src/extension/state.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { EffectRuntimeRunner } from "../runtime-source";
|
|
3
2
|
import type { EffectErrorMap } from "../tagged-error";
|
|
4
3
|
import type {
|
|
5
4
|
EffectPipelineStep,
|
|
@@ -17,10 +16,9 @@ export interface EffectExtensionState<
|
|
|
17
16
|
*/
|
|
18
17
|
effectErrorMap: EffectErrorMap;
|
|
19
18
|
/**
|
|
20
|
-
*
|
|
21
|
-
* @see {@link ManagedRuntime.ManagedRuntime}
|
|
19
|
+
* Executes Effect values with the services configured for this builder.
|
|
22
20
|
*/
|
|
23
|
-
|
|
21
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
24
22
|
/**
|
|
25
23
|
* Configuration for Effect span tracing.
|
|
26
24
|
* @see {@link EffectSpanConfig}
|
package/src/index.ts
CHANGED
package/src/runtime-source.ts
CHANGED
|
@@ -1,18 +1,76 @@
|
|
|
1
|
-
import { Layer, ManagedRuntime } from "effect";
|
|
1
|
+
import { Effect, Exit, FiberRefs, Layer, ManagedRuntime } from "effect";
|
|
2
|
+
|
|
3
|
+
import { getCurrentFiberRefs } from "./fiber-context-bridge";
|
|
2
4
|
|
|
3
5
|
export type EffectRuntimeSource<TRequirementsProvided, TRuntimeError> =
|
|
4
6
|
| ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>
|
|
5
7
|
| Layer.Layer<TRequirementsProvided, TRuntimeError, never>;
|
|
6
8
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
export interface EffectRuntimeRunner<TRequirementsProvided, TRuntimeError> {
|
|
10
|
+
readonly runtime?: ManagedRuntime.ManagedRuntime<
|
|
11
|
+
TRequirementsProvided,
|
|
12
|
+
TRuntimeError
|
|
13
|
+
>;
|
|
14
|
+
readonly runPromiseExit: <A, E>(
|
|
15
|
+
effect: Effect.Effect<A, E, TRequirementsProvided>,
|
|
16
|
+
options?: { readonly signal?: AbortSignal },
|
|
17
|
+
) => Promise<Exit.Exit<A, E | TRuntimeError>>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function makeEffectRuntimeRunner<
|
|
21
|
+
TRequirementsProvided = never,
|
|
22
|
+
TRuntimeError = never,
|
|
23
|
+
>(
|
|
24
|
+
source?: EffectRuntimeSource<TRequirementsProvided, TRuntimeError>,
|
|
25
|
+
): EffectRuntimeRunner<TRequirementsProvided, TRuntimeError> {
|
|
26
|
+
if (source === undefined) {
|
|
27
|
+
return {
|
|
28
|
+
runPromiseExit: (effect, options) =>
|
|
29
|
+
Effect.runPromiseExit(withParentFiberRefs(effect as any), {
|
|
30
|
+
signal: options?.signal,
|
|
31
|
+
}) as Promise<Exit.Exit<any, any>>,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ManagedRuntime.isManagedRuntime(source)) {
|
|
36
|
+
const runtime = source as ManagedRuntime.ManagedRuntime<
|
|
37
|
+
TRequirementsProvided,
|
|
38
|
+
TRuntimeError
|
|
39
|
+
>;
|
|
40
|
+
return {
|
|
41
|
+
runtime,
|
|
42
|
+
runPromiseExit: (effect, options) =>
|
|
43
|
+
runtime.runPromiseExit(withParentFiberRefs(effect), {
|
|
44
|
+
signal: options?.signal,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const layer = source as Layer.Layer<
|
|
50
|
+
TRequirementsProvided,
|
|
51
|
+
TRuntimeError,
|
|
52
|
+
never
|
|
53
|
+
>;
|
|
54
|
+
return {
|
|
55
|
+
runPromiseExit: (effect, options) =>
|
|
56
|
+
Effect.runPromiseExit(
|
|
57
|
+
withParentFiberRefs(Effect.provide(effect as any, layer)),
|
|
58
|
+
{ signal: options?.signal },
|
|
59
|
+
) as Promise<Exit.Exit<any, any>>,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function withParentFiberRefs<A, E, R>(
|
|
64
|
+
effect: Effect.Effect<A, E, R>,
|
|
65
|
+
): Effect.Effect<A, E, R> {
|
|
66
|
+
const parentFiberRefs = getCurrentFiberRefs();
|
|
67
|
+
return parentFiberRefs
|
|
68
|
+
? Effect.fiberIdWith((fiberId) =>
|
|
69
|
+
Effect.flatMap(Effect.getFiberRefs, (fiberRefs) =>
|
|
70
|
+
Effect.setFiberRefs(
|
|
71
|
+
FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs),
|
|
72
|
+
).pipe(Effect.andThen(effect)),
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
: effect;
|
|
18
76
|
}
|
package/src/tagged-error.ts
CHANGED
|
@@ -341,7 +341,7 @@ export function ORPCTaggedError<
|
|
|
341
341
|
*
|
|
342
342
|
* @example
|
|
343
343
|
* ```ts
|
|
344
|
-
* const handler =
|
|
344
|
+
* const handler = effectProcedure.effect(function* () {
|
|
345
345
|
* const result = yield* someOperation.pipe(
|
|
346
346
|
* Effect.catchTag('UserNotFoundError', (e) =>
|
|
347
347
|
* Effect.fail(toORPCError(e))
|
|
@@ -76,14 +76,11 @@ describe("implementEffect", () => {
|
|
|
76
76
|
};
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
} finally {
|
|
85
|
-
await procedure["~effect"].runtime.dispose();
|
|
86
|
-
}
|
|
79
|
+
expect(procedure["~effect"].runner.runtime).toBeUndefined();
|
|
80
|
+
await expect(call(procedure, { amount: 2 })).resolves.toEqual({
|
|
81
|
+
next: 3,
|
|
82
|
+
requestId: "layer",
|
|
83
|
+
});
|
|
87
84
|
});
|
|
88
85
|
|
|
89
86
|
it("preserves contract enforcement at the root router", async () => {
|
|
@@ -121,7 +121,7 @@ describe("effectBuilder proxy compatibility", () => {
|
|
|
121
121
|
({ input }: { input: { id: string } }) => input,
|
|
122
122
|
);
|
|
123
123
|
expect(procedure).toBeInstanceOf(EffectDecoratedProcedure);
|
|
124
|
-
expect(procedure["~effect"].runtime).toBe(runtime);
|
|
124
|
+
expect(procedure["~effect"].runner.runtime).toBe(runtime);
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
it("preserves tagged class support in errors()", () => {
|
|
@@ -155,11 +155,11 @@ describe("effectBuilder proxy compatibility", () => {
|
|
|
155
155
|
|
|
156
156
|
expect(handled).toBeInstanceOf(EffectDecoratedProcedure);
|
|
157
157
|
expect(effected).toBeInstanceOf(EffectDecoratedProcedure);
|
|
158
|
-
expect(routed.ping["~effect"].runtime).toBe(runtime);
|
|
158
|
+
expect(routed.ping["~effect"].runner.runtime).toBe(runtime);
|
|
159
159
|
expect(isLazy(lazied)).toBe(true);
|
|
160
160
|
|
|
161
161
|
const { default: resolved } = await unlazy(lazied as any);
|
|
162
|
-
expect(resolved.ping["~effect"].runtime).toBe(runtime);
|
|
162
|
+
expect(resolved.ping["~effect"].runner.runtime).toBe(runtime);
|
|
163
163
|
});
|
|
164
164
|
|
|
165
165
|
it("preserves decorated procedure proxy reflection and extracted methods", () => {
|
|
@@ -214,7 +214,7 @@ describe("effectBuilder proxy compatibility", () => {
|
|
|
214
214
|
|
|
215
215
|
await expect(callable("hello")).resolves.toEqual({ echoed: "hello" });
|
|
216
216
|
expect(callable).toSatisfy(isProcedure);
|
|
217
|
-
expect(callable["~effect"].runtime).toBe(runtime);
|
|
217
|
+
expect(callable["~effect"].runner.runtime).toBe(runtime);
|
|
218
218
|
expect(callable.route({ path: "/echo" })).toBeInstanceOf(
|
|
219
219
|
EffectDecoratedProcedure,
|
|
220
220
|
);
|