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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Effect, Exit, FiberRefs, Layer, ManagedRuntime } from "effect";
|
|
2
|
+
|
|
3
|
+
import { getCurrentFiberRefs } from "./fiber-context-bridge";
|
|
4
|
+
|
|
5
|
+
export type EffectRuntimeSource<TRequirementsProvided, TRuntimeError> =
|
|
6
|
+
| ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>
|
|
7
|
+
| Layer.Layer<TRequirementsProvided, TRuntimeError, never>;
|
|
8
|
+
|
|
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;
|
|
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))
|
|
@@ -371,15 +371,6 @@ export type EffectErrorMapItem =
|
|
|
371
371
|
| ErrorMapItem<AnySchema>
|
|
372
372
|
| AnyORPCTaggedErrorClass;
|
|
373
373
|
|
|
374
|
-
export type ORPCTaggedErrorClassToErrorMapItem<T> =
|
|
375
|
-
T extends ORPCTaggedErrorClass<any, any, infer TData>
|
|
376
|
-
? {
|
|
377
|
-
status?: number;
|
|
378
|
-
message?: string;
|
|
379
|
-
data?: TData;
|
|
380
|
-
}
|
|
381
|
-
: never;
|
|
382
|
-
|
|
383
374
|
/**
|
|
384
375
|
* Extended error map that supports both traditional oRPC errors and ORPCTaggedError classes.
|
|
385
376
|
*
|
|
@@ -62,6 +62,27 @@ describe("implementEffect", () => {
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
it("can implement a contract directly from a Layer", async () => {
|
|
66
|
+
const CounterLive = Layer.succeed(Counter, {
|
|
67
|
+
increment: (n: number) => Effect.succeed(n + 1),
|
|
68
|
+
});
|
|
69
|
+
const oe = implementEffect(contract, CounterLive);
|
|
70
|
+
const procedure = oe.users.list.effect(function* ({ input }) {
|
|
71
|
+
const counter = yield* Counter;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
next: yield* counter.increment(input.amount),
|
|
75
|
+
requestId: "layer",
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(procedure["~effect"].runner.runtime).toBeUndefined();
|
|
80
|
+
await expect(call(procedure, { amount: 2 })).resolves.toEqual({
|
|
81
|
+
next: 3,
|
|
82
|
+
requestId: "layer",
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
65
86
|
it("preserves contract enforcement at the root router", async () => {
|
|
66
87
|
const oe = implementEffect(contract, runtime);
|
|
67
88
|
|
|
@@ -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
|
);
|