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.
@@ -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
- try {
431
- await expect(call(procedure, 5)).resolves.toBe(6);
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
- try {
455
- await expect(call(procedure, 5)).resolves.toBe(6);
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
- try {
486
- await expect(call(procedure, 5)).resolves.toEqual({
487
- fromCustomBuilder: true,
488
- value: 6,
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 effectOs = makeEffectORPC(runtime);
196
+ const effectProcedure = makeEffectORPC(runtime);
197
197
 
198
198
  it("should support errors() with traditional format", () => {
199
- const builder = effectOs.errors({
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 = effectOs.errors({
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 = effectOs.errors({
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 = effectOs
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 = effectOs
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 = effectOs
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 effectOs = makeEffectORPC(runtime);
313
+ const effectProcedure = makeEffectORPC(runtime);
314
314
 
315
315
  it("should support adding errors to procedure", () => {
316
- const procedure = effectOs
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 = effectOs
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 ManagedRuntime provided during builder creation.
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}
@@ -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 the Effect ManagedRuntime.
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
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
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 the Effect ManagedRuntime.
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
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
100
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
106
101
  effectErrorMap: TEffectErrorMap;
107
102
  effectSteps?: readonly EffectPipelineStep[];
108
103
  effectHandler?: EffectProcedureHandlerConfig;
@@ -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 ManagedRuntime provided during builder creation.
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 ManagedRuntime provided during builder creation.
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 ManagedRuntime provided during builder creation.
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 ManagedRuntime provided during builder creation.
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 ManagedRuntime provided during builder creation.
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}