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
|
@@ -12,9 +12,10 @@ import {
|
|
|
12
12
|
import { beforeEach, describe, expect, expectTypeOf, it, vi } from "vitest";
|
|
13
13
|
import z from "zod";
|
|
14
14
|
|
|
15
|
-
import { EffectBuilder, makeEffectORPC } from "../effect-builder";
|
|
15
|
+
import { EffectBuilder, eos, makeEffectORPC } from "../effect-builder";
|
|
16
16
|
import { EffectDecoratedProcedure } from "../effect-procedure";
|
|
17
17
|
import { withFiberContext } from "../node";
|
|
18
|
+
import { makeEffectRuntimeRunner } from "../runtime-source";
|
|
18
19
|
import { ORPCTaggedError, effectErrorMapToErrorMap } from "../tagged-error";
|
|
19
20
|
import {
|
|
20
21
|
baseErrorMap,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
|
|
28
29
|
const mid = vi.fn();
|
|
29
30
|
const runtime = ManagedRuntime.make(Layer.empty);
|
|
31
|
+
const runner = makeEffectRuntimeRunner(runtime);
|
|
30
32
|
|
|
31
33
|
const def = {
|
|
32
34
|
config: {
|
|
@@ -43,6 +45,7 @@ const def = {
|
|
|
43
45
|
outputValidationIndex: 88,
|
|
44
46
|
route: baseRoute,
|
|
45
47
|
dedupeLeadingMiddlewares: true,
|
|
48
|
+
runner,
|
|
46
49
|
runtime,
|
|
47
50
|
};
|
|
48
51
|
|
|
@@ -142,7 +145,7 @@ describe("effectBuilder", () => {
|
|
|
142
145
|
const applied = builder.effect(effectFn);
|
|
143
146
|
|
|
144
147
|
expect(applied).instanceOf(EffectDecoratedProcedure);
|
|
145
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
148
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
146
149
|
expect(applied["~effect"].handler).toBeInstanceOf(Function);
|
|
147
150
|
});
|
|
148
151
|
|
|
@@ -271,7 +274,7 @@ describe("makeEffectORPC factory", () => {
|
|
|
271
274
|
const effectBuilder = makeEffectORPC(runtime);
|
|
272
275
|
|
|
273
276
|
expect(effectBuilder).instanceOf(EffectBuilder);
|
|
274
|
-
expect(effectBuilder["~effect"].runtime).toBe(runtime);
|
|
277
|
+
expect(effectBuilder["~effect"].runner.runtime).toBe(runtime);
|
|
275
278
|
// Should inherit os's default definition
|
|
276
279
|
expect(effectBuilder["~effect"].middlewares).toEqual(
|
|
277
280
|
os["~orpc"].middlewares,
|
|
@@ -285,7 +288,7 @@ describe("makeEffectORPC factory", () => {
|
|
|
285
288
|
const effectBuilder = makeEffectORPC(runtime, os);
|
|
286
289
|
|
|
287
290
|
expect(effectBuilder).instanceOf(EffectBuilder);
|
|
288
|
-
expect(effectBuilder["~effect"].runtime).toBe(runtime);
|
|
291
|
+
expect(effectBuilder["~effect"].runner.runtime).toBe(runtime);
|
|
289
292
|
expect(effectBuilder["~effect"].middlewares).toEqual(
|
|
290
293
|
os["~orpc"].middlewares,
|
|
291
294
|
);
|
|
@@ -294,6 +297,46 @@ describe("makeEffectORPC factory", () => {
|
|
|
294
297
|
);
|
|
295
298
|
});
|
|
296
299
|
|
|
300
|
+
it("exports an eos builder that works with provide", async () => {
|
|
301
|
+
class Counter extends Effect.Tag("EosCounter")<
|
|
302
|
+
Counter,
|
|
303
|
+
{ increment: (n: number) => Effect.Effect<number> }
|
|
304
|
+
>() {}
|
|
305
|
+
|
|
306
|
+
const procedure = eos
|
|
307
|
+
.provide(
|
|
308
|
+
Layer.succeed(Counter, {
|
|
309
|
+
increment: (n: number) => Effect.succeed(n + 1),
|
|
310
|
+
}),
|
|
311
|
+
)
|
|
312
|
+
.input(z.number())
|
|
313
|
+
.effect(function* ({ input }) {
|
|
314
|
+
const counter = yield* Counter;
|
|
315
|
+
return yield* counter.increment(input as number);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
expect(eos["~effect"].runner.runtime).toBeUndefined();
|
|
319
|
+
await expect(call(procedure, 5)).resolves.toBe(6);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it("does not own a ManagedRuntime when no source is provided", () => {
|
|
323
|
+
const effectBuilder = makeEffectORPC();
|
|
324
|
+
|
|
325
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("does not own a ManagedRuntime when only a builder is provided", () => {
|
|
329
|
+
const effectBuilder = makeEffectORPC(os);
|
|
330
|
+
|
|
331
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("does not own a ManagedRuntime when a Layer is provided", () => {
|
|
335
|
+
const effectBuilder = makeEffectORPC(Layer.empty);
|
|
336
|
+
|
|
337
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
338
|
+
});
|
|
339
|
+
|
|
297
340
|
it("creates working procedure with default os", async () => {
|
|
298
341
|
const effectBuilder = makeEffectORPC(runtime);
|
|
299
342
|
|
|
@@ -427,11 +470,8 @@ describe("effect with services", () => {
|
|
|
427
470
|
return yield* counter.increment(input as number);
|
|
428
471
|
});
|
|
429
472
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
} finally {
|
|
433
|
-
await effectBuilder["~effect"].runtime.dispose();
|
|
434
|
-
}
|
|
473
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
474
|
+
await expect(call(procedure, 5)).resolves.toBe(6);
|
|
435
475
|
});
|
|
436
476
|
|
|
437
477
|
it("can start without a runtime and provide a Layer", async () => {
|
|
@@ -451,11 +491,8 @@ describe("effect with services", () => {
|
|
|
451
491
|
return yield* counter.increment(input as number);
|
|
452
492
|
});
|
|
453
493
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
} finally {
|
|
457
|
-
await effectBuilder["~effect"].runtime.dispose();
|
|
458
|
-
}
|
|
494
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
495
|
+
await expect(call(procedure, 5)).resolves.toBe(6);
|
|
459
496
|
});
|
|
460
497
|
|
|
461
498
|
it("can wrap a custom builder without a runtime and provide a Layer", async () => {
|
|
@@ -482,14 +519,11 @@ describe("effect with services", () => {
|
|
|
482
519
|
};
|
|
483
520
|
});
|
|
484
521
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
} finally {
|
|
491
|
-
await effectBuilder["~effect"].runtime.dispose();
|
|
492
|
-
}
|
|
522
|
+
expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
|
|
523
|
+
await expect(call(procedure, 5)).resolves.toEqual({
|
|
524
|
+
fromCustomBuilder: true,
|
|
525
|
+
value: 6,
|
|
526
|
+
});
|
|
493
527
|
});
|
|
494
528
|
|
|
495
529
|
it(".provide makes a request-scoped service available to handlers", async () => {
|
|
@@ -193,10 +193,10 @@ describe("effectErrorMapToErrorMap", () => {
|
|
|
193
193
|
|
|
194
194
|
describe("effectBuilder with EffectErrorMap", () => {
|
|
195
195
|
const runtime = ManagedRuntime.make(Layer.empty);
|
|
196
|
-
const
|
|
196
|
+
const effectProcedure = makeEffectORPC(runtime);
|
|
197
197
|
|
|
198
198
|
it("should support errors() with traditional format", () => {
|
|
199
|
-
const builder =
|
|
199
|
+
const builder = effectProcedure.errors({
|
|
200
200
|
BAD_REQUEST: { status: 400, message: "Bad request" },
|
|
201
201
|
});
|
|
202
202
|
|
|
@@ -206,7 +206,7 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
206
206
|
});
|
|
207
207
|
|
|
208
208
|
it("should support errors() with tagged error classes", () => {
|
|
209
|
-
const builder =
|
|
209
|
+
const builder = effectProcedure.errors({
|
|
210
210
|
USER_NOT_FOUND_ERROR: UserNotFoundError,
|
|
211
211
|
FORBIDDEN: PermissionDenied,
|
|
212
212
|
});
|
|
@@ -218,7 +218,7 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
218
218
|
});
|
|
219
219
|
|
|
220
220
|
it("should support mixed error format", () => {
|
|
221
|
-
const builder =
|
|
221
|
+
const builder = effectProcedure.errors({
|
|
222
222
|
BAD_REQUEST: { status: 400 },
|
|
223
223
|
USER_NOT_FOUND_ERROR: UserNotFoundError,
|
|
224
224
|
});
|
|
@@ -232,7 +232,7 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
232
232
|
});
|
|
233
233
|
|
|
234
234
|
it("should merge errors correctly", () => {
|
|
235
|
-
const builder =
|
|
235
|
+
const builder = effectProcedure
|
|
236
236
|
.errors({ BAD_REQUEST: { status: 400 } })
|
|
237
237
|
.errors({ USER_NOT_FOUND_ERROR: UserNotFoundError })
|
|
238
238
|
.errors({ FORBIDDEN: PermissionDenied });
|
|
@@ -245,7 +245,7 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
245
245
|
});
|
|
246
246
|
|
|
247
247
|
it("should create procedure with effect handler", async () => {
|
|
248
|
-
const procedure =
|
|
248
|
+
const procedure = effectProcedure
|
|
249
249
|
.errors({
|
|
250
250
|
USER_NOT_FOUND_ERROR: UserNotFoundError,
|
|
251
251
|
BAD_REQUEST: { status: 400 },
|
|
@@ -267,7 +267,7 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
267
267
|
});
|
|
268
268
|
|
|
269
269
|
it("should allow throwing tagged errors in effect handler", async () => {
|
|
270
|
-
const procedure =
|
|
270
|
+
const procedure = effectProcedure
|
|
271
271
|
.errors({
|
|
272
272
|
USER_NOT_FOUND_ERROR: UserNotFoundError,
|
|
273
273
|
})
|
|
@@ -310,10 +310,10 @@ describe("effectBuilder with EffectErrorMap", () => {
|
|
|
310
310
|
|
|
311
311
|
describe("effectDecoratedProcedure.errors()", () => {
|
|
312
312
|
const runtime = ManagedRuntime.make(Layer.empty);
|
|
313
|
-
const
|
|
313
|
+
const effectProcedure = makeEffectORPC(runtime);
|
|
314
314
|
|
|
315
315
|
it("should support adding errors to procedure", () => {
|
|
316
|
-
const procedure =
|
|
316
|
+
const procedure = effectProcedure
|
|
317
317
|
.input(z.object({ id: z.string() }))
|
|
318
318
|
.effect(function* ({ input }) {
|
|
319
319
|
return { id: input.id };
|
|
@@ -326,7 +326,7 @@ describe("effectDecoratedProcedure.errors()", () => {
|
|
|
326
326
|
});
|
|
327
327
|
|
|
328
328
|
it("should merge errors on procedure", () => {
|
|
329
|
-
const procedure =
|
|
329
|
+
const procedure = effectProcedure
|
|
330
330
|
.errors({ BAD_REQUEST: { status: 400 } })
|
|
331
331
|
.input(z.object({ id: z.string() }))
|
|
332
332
|
.effect(function* ({ input }) {
|
|
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import z from "zod";
|
|
5
5
|
|
|
6
6
|
import { EffectDecoratedProcedure } from "../effect-procedure";
|
|
7
|
+
import { makeEffectRuntimeRunner } from "../runtime-source";
|
|
7
8
|
import {
|
|
8
9
|
baseErrorMap,
|
|
9
10
|
baseMeta,
|
|
@@ -25,6 +26,7 @@ vi.mock("@orpc/server", async (importOriginal) => {
|
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
const runtime = ManagedRuntime.make(Layer.empty);
|
|
29
|
+
const runner = makeEffectRuntimeRunner(runtime);
|
|
28
30
|
|
|
29
31
|
const handler = vi.fn();
|
|
30
32
|
const middleware = vi.fn();
|
|
@@ -40,6 +42,7 @@ const def = {
|
|
|
40
42
|
meta: baseMeta,
|
|
41
43
|
route: baseRoute,
|
|
42
44
|
handler,
|
|
45
|
+
runner,
|
|
43
46
|
runtime,
|
|
44
47
|
};
|
|
45
48
|
|
|
@@ -80,7 +83,7 @@ describe("effectDecoratedProcedure", () => {
|
|
|
80
83
|
});
|
|
81
84
|
|
|
82
85
|
// Preserves runtime
|
|
83
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
86
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
84
87
|
});
|
|
85
88
|
|
|
86
89
|
it(".meta", () => {
|
|
@@ -96,7 +99,7 @@ describe("effectDecoratedProcedure", () => {
|
|
|
96
99
|
});
|
|
97
100
|
|
|
98
101
|
// Preserves runtime
|
|
99
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
102
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
100
103
|
});
|
|
101
104
|
|
|
102
105
|
it(".route", () => {
|
|
@@ -112,7 +115,7 @@ describe("effectDecoratedProcedure", () => {
|
|
|
112
115
|
});
|
|
113
116
|
|
|
114
117
|
// Preserves runtime
|
|
115
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
118
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
116
119
|
});
|
|
117
120
|
|
|
118
121
|
describe(".use", () => {
|
|
@@ -129,7 +132,7 @@ describe("effectDecoratedProcedure", () => {
|
|
|
129
132
|
});
|
|
130
133
|
|
|
131
134
|
// Preserves runtime
|
|
132
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
135
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
133
136
|
});
|
|
134
137
|
|
|
135
138
|
it("with map input", () => {
|
|
@@ -146,7 +149,7 @@ describe("effectDecoratedProcedure", () => {
|
|
|
146
149
|
});
|
|
147
150
|
|
|
148
151
|
// Preserves runtime
|
|
149
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
152
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
150
153
|
});
|
|
151
154
|
});
|
|
152
155
|
|
|
@@ -207,7 +210,7 @@ describe("effectDecoratedProcedure chaining", () => {
|
|
|
207
210
|
.route({ path: "/custom" });
|
|
208
211
|
|
|
209
212
|
expect(applied).toBeInstanceOf(EffectDecoratedProcedure);
|
|
210
|
-
expect(applied["~effect"].runtime).toBe(runtime);
|
|
213
|
+
expect(applied["~effect"].runner.runtime).toBe(runtime);
|
|
211
214
|
expect(applied["~effect"].errorMap).toHaveProperty("CUSTOM");
|
|
212
215
|
});
|
|
213
216
|
});
|
|
@@ -474,7 +474,7 @@ export interface EffectBuilderSurface<
|
|
|
474
474
|
>;
|
|
475
475
|
/**
|
|
476
476
|
* Defines the handler of the procedure using an Effect.
|
|
477
|
-
* The Effect is executed using the
|
|
477
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
478
478
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
479
479
|
*
|
|
480
480
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
package/src/types/index.ts
CHANGED
|
@@ -24,15 +24,10 @@ import type {
|
|
|
24
24
|
RouterBuilder,
|
|
25
25
|
} from "@orpc/server";
|
|
26
26
|
import type { MaybeOptionalOptions } from "@orpc/shared";
|
|
27
|
-
import type {
|
|
28
|
-
Context as EffectContext,
|
|
29
|
-
Effect,
|
|
30
|
-
Layer,
|
|
31
|
-
ManagedRuntime,
|
|
32
|
-
Option,
|
|
33
|
-
} from "effect";
|
|
27
|
+
import type { Context as EffectContext, Effect, Layer, Option } from "effect";
|
|
34
28
|
import type { YieldWrap } from "effect/Utils";
|
|
35
29
|
|
|
30
|
+
import type { EffectRuntimeRunner } from "../runtime-source";
|
|
36
31
|
import type {
|
|
37
32
|
EffectErrorConstructorMap,
|
|
38
33
|
EffectErrorMap,
|
|
@@ -54,7 +49,7 @@ type EffectBuilderDefBase<
|
|
|
54
49
|
>;
|
|
55
50
|
|
|
56
51
|
/**
|
|
57
|
-
* Extended builder definition that includes
|
|
52
|
+
* Extended builder definition that includes Effect execution state.
|
|
58
53
|
*/
|
|
59
54
|
export interface EffectBuilderDef<
|
|
60
55
|
TInputSchema extends AnySchema,
|
|
@@ -69,7 +64,7 @@ export interface EffectBuilderDef<
|
|
|
69
64
|
TEffectErrorMap,
|
|
70
65
|
TMeta
|
|
71
66
|
> {
|
|
72
|
-
|
|
67
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
73
68
|
/**
|
|
74
69
|
* Optional span configuration for Effect tracing.
|
|
75
70
|
*/
|
|
@@ -83,7 +78,7 @@ export interface EffectBuilderDef<
|
|
|
83
78
|
}
|
|
84
79
|
|
|
85
80
|
/**
|
|
86
|
-
* Extended procedure definition that includes
|
|
81
|
+
* Extended procedure definition that includes Effect execution state.
|
|
87
82
|
*/
|
|
88
83
|
export interface EffectProcedureDef<
|
|
89
84
|
TInitialContext extends Context,
|
|
@@ -102,7 +97,7 @@ export interface EffectProcedureDef<
|
|
|
102
97
|
EffectErrorMapToErrorMap<TEffectErrorMap>,
|
|
103
98
|
TMeta
|
|
104
99
|
> {
|
|
105
|
-
|
|
100
|
+
runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
|
|
106
101
|
effectErrorMap: TEffectErrorMap;
|
|
107
102
|
effectSteps?: readonly EffectPipelineStep[];
|
|
108
103
|
effectHandler?: EffectProcedureHandlerConfig;
|
package/src/types/variants.ts
CHANGED
|
@@ -294,7 +294,7 @@ export interface EffectBuilderWithMiddlewares<
|
|
|
294
294
|
|
|
295
295
|
/**
|
|
296
296
|
* Defines the handler of the procedure using an Effect.
|
|
297
|
-
* The Effect is executed using the
|
|
297
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
298
298
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
299
299
|
*
|
|
300
300
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
|
@@ -648,7 +648,7 @@ export interface EffectProcedureBuilder<
|
|
|
648
648
|
|
|
649
649
|
/**
|
|
650
650
|
* Defines the handler of the procedure using an Effect.
|
|
651
|
-
* The Effect is executed using the
|
|
651
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
652
652
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
653
653
|
*
|
|
654
654
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
|
@@ -958,7 +958,7 @@ export interface EffectProcedureBuilderWithInput<
|
|
|
958
958
|
|
|
959
959
|
/**
|
|
960
960
|
* Defines the handler of the procedure using an Effect.
|
|
961
|
-
* The Effect is executed using the
|
|
961
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
962
962
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
963
963
|
*
|
|
964
964
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
|
@@ -1234,7 +1234,7 @@ export interface EffectProcedureBuilderWithOutput<
|
|
|
1234
1234
|
|
|
1235
1235
|
/**
|
|
1236
1236
|
* Defines the handler of the procedure using an Effect.
|
|
1237
|
-
* The Effect is executed using the
|
|
1237
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
1238
1238
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
1239
1239
|
*
|
|
1240
1240
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|
|
@@ -1526,7 +1526,7 @@ export interface EffectProcedureBuilderWithInputOutput<
|
|
|
1526
1526
|
|
|
1527
1527
|
/**
|
|
1528
1528
|
* Defines the handler of the procedure using an Effect.
|
|
1529
|
-
* The Effect is executed using the
|
|
1529
|
+
* The Effect is executed using the configured Effect runtime source.
|
|
1530
1530
|
* The effect is automatically wrapped with `Effect.withSpan`.
|
|
1531
1531
|
*
|
|
1532
1532
|
* @see {@link https://orpc.dev/docs/procedure Procedure Docs}
|