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.
@@ -1,14 +1,22 @@
1
1
  import type { InferSchemaOutput } from "@orpc/contract";
2
2
  import { isContractProcedure } from "@orpc/contract";
3
- import { os } from "@orpc/server";
4
- import { Effect, FiberRef, Layer, ManagedRuntime } from "effect";
3
+ import { call, os } from "@orpc/server";
4
+ import {
5
+ Context,
6
+ Effect,
7
+ FiberRef,
8
+ Layer,
9
+ ManagedRuntime,
10
+ Option,
11
+ } from "effect";
5
12
  import { beforeEach, describe, expect, expectTypeOf, it, vi } from "vitest";
6
13
  import z from "zod";
7
14
 
8
- import { EffectBuilder, makeEffectORPC } from "../effect-builder";
15
+ import { EffectBuilder, eos, makeEffectORPC } from "../effect-builder";
9
16
  import { EffectDecoratedProcedure } from "../effect-procedure";
10
17
  import { withFiberContext } from "../node";
11
- import { effectErrorMapToErrorMap, ORPCTaggedError } from "../tagged-error";
18
+ import { makeEffectRuntimeRunner } from "../runtime-source";
19
+ import { ORPCTaggedError, effectErrorMapToErrorMap } from "../tagged-error";
12
20
  import {
13
21
  baseErrorMap,
14
22
  baseMeta,
@@ -20,6 +28,7 @@ import {
20
28
 
21
29
  const mid = vi.fn();
22
30
  const runtime = ManagedRuntime.make(Layer.empty);
31
+ const runner = makeEffectRuntimeRunner(runtime);
23
32
 
24
33
  const def = {
25
34
  config: {
@@ -36,6 +45,7 @@ const def = {
36
45
  outputValidationIndex: 88,
37
46
  route: baseRoute,
38
47
  dedupeLeadingMiddlewares: true,
48
+ runner,
39
49
  runtime,
40
50
  };
41
51
 
@@ -135,7 +145,7 @@ describe("effectBuilder", () => {
135
145
  const applied = builder.effect(effectFn);
136
146
 
137
147
  expect(applied).instanceOf(EffectDecoratedProcedure);
138
- expect(applied["~effect"].runtime).toBe(runtime);
148
+ expect(applied["~effect"].runner.runtime).toBe(runtime);
139
149
  expect(applied["~effect"].handler).toBeInstanceOf(Function);
140
150
  });
141
151
 
@@ -264,7 +274,7 @@ describe("makeEffectORPC factory", () => {
264
274
  const effectBuilder = makeEffectORPC(runtime);
265
275
 
266
276
  expect(effectBuilder).instanceOf(EffectBuilder);
267
- expect(effectBuilder["~effect"].runtime).toBe(runtime);
277
+ expect(effectBuilder["~effect"].runner.runtime).toBe(runtime);
268
278
  // Should inherit os's default definition
269
279
  expect(effectBuilder["~effect"].middlewares).toEqual(
270
280
  os["~orpc"].middlewares,
@@ -278,7 +288,7 @@ describe("makeEffectORPC factory", () => {
278
288
  const effectBuilder = makeEffectORPC(runtime, os);
279
289
 
280
290
  expect(effectBuilder).instanceOf(EffectBuilder);
281
- expect(effectBuilder["~effect"].runtime).toBe(runtime);
291
+ expect(effectBuilder["~effect"].runner.runtime).toBe(runtime);
282
292
  expect(effectBuilder["~effect"].middlewares).toEqual(
283
293
  os["~orpc"].middlewares,
284
294
  );
@@ -287,6 +297,46 @@ describe("makeEffectORPC factory", () => {
287
297
  );
288
298
  });
289
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
+
290
340
  it("creates working procedure with default os", async () => {
291
341
  const effectBuilder = makeEffectORPC(runtime);
292
342
 
@@ -402,6 +452,445 @@ describe("effect with services", () => {
402
452
  // Cleanup
403
453
  await serviceRuntime.dispose();
404
454
  });
455
+
456
+ it("can create a builder directly from a Layer", async () => {
457
+ class Counter extends Effect.Tag("LayerCounter")<
458
+ Counter,
459
+ { increment: (n: number) => Effect.Effect<number> }
460
+ >() {}
461
+
462
+ const CounterLive = Layer.succeed(Counter, {
463
+ increment: (n: number) => Effect.succeed(n + 1),
464
+ });
465
+ const effectBuilder = makeEffectORPC(CounterLive);
466
+ const procedure = effectBuilder.input(z.number()).effect(function* ({
467
+ input,
468
+ }) {
469
+ const counter = yield* Counter;
470
+ return yield* counter.increment(input as number);
471
+ });
472
+
473
+ expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
474
+ await expect(call(procedure, 5)).resolves.toBe(6);
475
+ });
476
+
477
+ it("can start without a runtime and provide a Layer", async () => {
478
+ class Counter extends Effect.Tag("ProvidedLayerCounter")<
479
+ Counter,
480
+ { increment: (n: number) => Effect.Effect<number> }
481
+ >() {}
482
+
483
+ const CounterLive = Layer.succeed(Counter, {
484
+ increment: (n: number) => Effect.succeed(n + 1),
485
+ });
486
+ const effectBuilder = makeEffectORPC().provide(CounterLive);
487
+ const procedure = effectBuilder.input(z.number()).effect(function* ({
488
+ input,
489
+ }) {
490
+ const counter = yield* Counter;
491
+ return yield* counter.increment(input as number);
492
+ });
493
+
494
+ expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
495
+ await expect(call(procedure, 5)).resolves.toBe(6);
496
+ });
497
+
498
+ it("can wrap a custom builder without a runtime and provide a Layer", async () => {
499
+ class Counter extends Effect.Tag("ProvidedLayerCustomBuilderCounter")<
500
+ Counter,
501
+ { increment: (n: number) => Effect.Effect<number> }
502
+ >() {}
503
+
504
+ const CounterLive = Layer.succeed(Counter, {
505
+ increment: (n: number) => Effect.succeed(n + 1),
506
+ });
507
+ const customBuilder = os.use(({ next }) =>
508
+ next({ context: { fromCustomBuilder: true } }),
509
+ );
510
+ const effectBuilder = makeEffectORPC(customBuilder).provide(CounterLive);
511
+ const procedure = effectBuilder.input(z.number()).effect(function* ({
512
+ context,
513
+ input,
514
+ }) {
515
+ const counter = yield* Counter;
516
+ return {
517
+ fromCustomBuilder: context.fromCustomBuilder,
518
+ value: yield* counter.increment(input as number),
519
+ };
520
+ });
521
+
522
+ expect(effectBuilder["~effect"].runner.runtime).toBeUndefined();
523
+ await expect(call(procedure, 5)).resolves.toEqual({
524
+ fromCustomBuilder: true,
525
+ value: 6,
526
+ });
527
+ });
528
+
529
+ it(".provide makes a request-scoped service available to handlers", async () => {
530
+ class CurrentUser extends Context.Tag("CurrentUser")<
531
+ CurrentUser,
532
+ { id: string }
533
+ >() {}
534
+
535
+ const effectBuilder = makeEffectORPC(runtime).$context<{
536
+ user: { id: string };
537
+ }>();
538
+ const procedure = effectBuilder
539
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
540
+ .effect(function* () {
541
+ return yield* CurrentUser;
542
+ });
543
+
544
+ await expect(
545
+ call(procedure, undefined, { context: { user: { id: "u-1" } } }),
546
+ ).resolves.toEqual({ id: "u-1" });
547
+ });
548
+
549
+ it(".provide service overrides the same service from the runtime", async () => {
550
+ class CurrentUser extends Context.Tag("CurrentUserOverride")<
551
+ CurrentUser,
552
+ { id: string }
553
+ >() {}
554
+
555
+ const serviceRuntime = ManagedRuntime.make(
556
+ Layer.succeed(CurrentUser, { id: "runtime" }),
557
+ );
558
+ const effectBuilder = makeEffectORPC(serviceRuntime).$context<{
559
+ user: { id: string };
560
+ }>();
561
+ const procedure = effectBuilder
562
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
563
+ .effect(function* () {
564
+ return yield* CurrentUser;
565
+ });
566
+
567
+ try {
568
+ await expect(
569
+ call(procedure, undefined, { context: { user: { id: "request" } } }),
570
+ ).resolves.toEqual({ id: "request" });
571
+ } finally {
572
+ await serviceRuntime.dispose();
573
+ }
574
+ });
575
+
576
+ it("Effect .use yield* next() without return runs handler once", async () => {
577
+ let runs = 0;
578
+ const procedure = makeEffectORPC(runtime)
579
+ .use(function* ({ next }) {
580
+ yield* Effect.void;
581
+ yield* next();
582
+ })
583
+ .effect(function* () {
584
+ runs += 1;
585
+ return "ok";
586
+ });
587
+
588
+ await expect(call(procedure, undefined)).resolves.toBe("ok");
589
+ expect(runs).toBe(1);
590
+ });
591
+
592
+ it("Effect .use guard-only middleware without next runs handler once", async () => {
593
+ let runs = 0;
594
+ const procedure = makeEffectORPC(runtime)
595
+ .use(function* () {
596
+ yield* Effect.void;
597
+ })
598
+ .effect(function* () {
599
+ runs += 1;
600
+ return "ok";
601
+ });
602
+
603
+ await expect(call(procedure, undefined)).resolves.toBe("ok");
604
+ expect(runs).toBe(1);
605
+ });
606
+
607
+ it("Effect .use yield* next() without return stays in one runtime boundary", async () => {
608
+ const runPromiseExit = vi.spyOn(runtime, "runPromiseExit");
609
+ const procedure = makeEffectORPC(runtime)
610
+ .use(function* ({ next }) {
611
+ yield* next();
612
+ })
613
+ .effect(function* () {
614
+ return "ok";
615
+ });
616
+
617
+ await expect(call(procedure, undefined)).resolves.toBe("ok");
618
+ expect(runPromiseExit).toHaveBeenCalledTimes(1);
619
+ });
620
+
621
+ it("Effect .use can read services from upstream .provide", async () => {
622
+ class CurrentUser extends Context.Tag("MiddlewareCurrentUser")<
623
+ CurrentUser,
624
+ { id: string }
625
+ >() {}
626
+
627
+ let seenUser: { id: string } | undefined;
628
+ const effectBuilder = makeEffectORPC(runtime).$context<{
629
+ user: { id: string };
630
+ }>();
631
+ const procedure = effectBuilder
632
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
633
+ .use(function* () {
634
+ seenUser = yield* CurrentUser;
635
+ })
636
+ .effect(function* () {
637
+ return "ok";
638
+ });
639
+
640
+ await expect(
641
+ call(procedure, undefined, { context: { user: { id: "u-2" } } }),
642
+ ).resolves.toBe("ok");
643
+ expect(seenUser).toEqual({ id: "u-2" });
644
+ });
645
+
646
+ it("Effect .middleware can create reusable generator middleware", async () => {
647
+ const eos = makeEffectORPC(runtime);
648
+
649
+ const reusable = eos.middleware(function* ({ next }, input: string) {
650
+ expectTypeOf(input).toEqualTypeOf<string>();
651
+ return yield* next({ context: { seenInput: input } });
652
+ });
653
+
654
+ const procedure = eos
655
+ .input(z.string())
656
+ .use(reusable)
657
+ .effect(function* ({ context }) {
658
+ expectTypeOf(context.seenInput).toEqualTypeOf<string>();
659
+ return context.seenInput;
660
+ });
661
+
662
+ await expect(call(procedure, "ok")).resolves.toBe("ok");
663
+ });
664
+
665
+ it("Effect .middleware can use builder-provided services", async () => {
666
+ class MiddlewareService extends Context.Tag("MiddlewareService")<
667
+ MiddlewareService,
668
+ { value: string }
669
+ >() {}
670
+
671
+ const eos = makeEffectORPC(runtime).provide(MiddlewareService, () =>
672
+ Effect.succeed({ value: "provided" }),
673
+ );
674
+
675
+ const reusable = eos.middleware(function* ({ next }) {
676
+ const service = yield* MiddlewareService;
677
+ return yield* next({ context: { serviceValue: service.value } });
678
+ });
679
+
680
+ const procedure = eos.use(reusable).effect(function* ({ context }) {
681
+ return context.serviceValue;
682
+ });
683
+
684
+ await expect(call(procedure, undefined)).resolves.toBe("provided");
685
+ });
686
+
687
+ it("Effect .use can enrich context through next", async () => {
688
+ class CurrentUser extends Context.Tag("NextCurrentUser")<
689
+ CurrentUser,
690
+ { id: string }
691
+ >() {}
692
+
693
+ const effectBuilder = makeEffectORPC(runtime).$context<{
694
+ user: { id: string };
695
+ }>();
696
+ const procedure = effectBuilder
697
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
698
+ .use(function* ({ next }, _input) {
699
+ const user = yield* CurrentUser;
700
+ return yield* next({ context: { userId: user.id } });
701
+ })
702
+ .effect(function* ({ context }) {
703
+ return context.userId;
704
+ });
705
+
706
+ await expect(
707
+ call(procedure, undefined, { context: { user: { id: "u-3" } } }),
708
+ ).resolves.toBe("u-3");
709
+ });
710
+
711
+ it("Effect .use can transform downstream output", async () => {
712
+ const procedure = makeEffectORPC(runtime)
713
+ .use(function* ({ next }, _input, output) {
714
+ const result = yield* next();
715
+ return yield* output(`${result.output}-wrapped`);
716
+ })
717
+ .effect(function* () {
718
+ return "ok";
719
+ });
720
+
721
+ await expect(call(procedure, undefined)).resolves.toBe("ok-wrapped");
722
+ });
723
+
724
+ it("Effect .use can transform typed downstream output after .output", async () => {
725
+ const procedure = makeEffectORPC(runtime)
726
+ .output(z.string())
727
+ .use(function* ({ next }, _input, output) {
728
+ const result = yield* next();
729
+ expectTypeOf(result.output).toEqualTypeOf<string>();
730
+ return yield* output(`${result.output}-wrapped`);
731
+ })
732
+ .effect(function* () {
733
+ return "ok";
734
+ });
735
+
736
+ await expect(call(procedure, undefined)).resolves.toBe("ok-wrapped");
737
+ });
738
+
739
+ it("Effect .use can read typed input after .input", async () => {
740
+ const procedure = makeEffectORPC(runtime)
741
+ .input(z.object({ value: z.number() }))
742
+ .use(function* ({ next }, input) {
743
+ expectTypeOf(input).toMatchTypeOf<{ value: number }>();
744
+ return yield* next({ context: { doubled: input.value * 2 } });
745
+ })
746
+ .effect(function* ({ context }) {
747
+ return context.doubled;
748
+ });
749
+
750
+ await expect(call(procedure, { value: 21 })).resolves.toBe(42);
751
+ });
752
+
753
+ it("Effect .use can read typed input and output after .input().output()", async () => {
754
+ const procedure = makeEffectORPC(runtime)
755
+ .input(z.object({ value: z.number() }))
756
+ .output(z.string())
757
+ .use(function* ({ next }, input, output) {
758
+ expectTypeOf(input).toMatchTypeOf<{ value: number }>();
759
+ const result = yield* next();
760
+ expectTypeOf(result.output).toEqualTypeOf<string>();
761
+ return yield* output(`${input.value}:${result.output}`);
762
+ })
763
+ .effect(function* () {
764
+ return "ok";
765
+ });
766
+
767
+ await expect(call(procedure, { value: 21 })).resolves.toBe("21:ok");
768
+ });
769
+
770
+ it("Effect .use can transform typed downstream output after .effect", async () => {
771
+ const procedure = makeEffectORPC(runtime)
772
+ .effect(function* () {
773
+ return "ok";
774
+ })
775
+ .use(function* ({ next }, _input, output) {
776
+ const result = yield* next();
777
+ expectTypeOf(result.output).toEqualTypeOf<string>();
778
+ return yield* output(`${result.output}-wrapped`);
779
+ });
780
+
781
+ await expect(call(procedure, undefined)).resolves.toBe("ok-wrapped");
782
+ });
783
+
784
+ it("runs contiguous Effect providers, middleware, and handler in one runtime boundary", async () => {
785
+ class CurrentUser extends Context.Tag("SingleBoundaryCurrentUser")<
786
+ CurrentUser,
787
+ { id: string }
788
+ >() {}
789
+
790
+ const runPromiseExit = vi.spyOn(runtime, "runPromiseExit");
791
+ const procedure = makeEffectORPC(runtime)
792
+ .$context<{ user: { id: string } }>()
793
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
794
+ .use(function* ({ next }) {
795
+ const user = yield* CurrentUser;
796
+ return yield* next({ context: { userId: user.id } });
797
+ })
798
+ .effect(function* ({ context }) {
799
+ const user = yield* CurrentUser;
800
+ return `${context.userId}:${user.id}`;
801
+ });
802
+
803
+ await expect(
804
+ call(procedure, undefined, { context: { user: { id: "u-4" } } }),
805
+ ).resolves.toBe("u-4:u-4");
806
+ expect(runPromiseExit).toHaveBeenCalledTimes(1);
807
+ });
808
+
809
+ it("runs procedure-level Effect providers and middleware with the handler in one runtime boundary", async () => {
810
+ class CurrentUser extends Context.Tag("ProcedureBoundaryCurrentUser")<
811
+ CurrentUser,
812
+ { id: string }
813
+ >() {}
814
+
815
+ const runPromiseExit = vi.spyOn(runtime, "runPromiseExit");
816
+ const procedure = makeEffectORPC(runtime)
817
+ .$context<{ user: { id: string } }>()
818
+ .effect(function* () {
819
+ return "ok";
820
+ })
821
+ .provide(CurrentUser, ({ context }) => Effect.succeed(context.user))
822
+ .use(function* ({ next }) {
823
+ const user = yield* CurrentUser;
824
+ const result = yield* next({ context: { userId: user.id } });
825
+ return {
826
+ ...result,
827
+ output: `${result.output}:${user.id}`,
828
+ };
829
+ });
830
+
831
+ await expect(
832
+ call(procedure, undefined, { context: { user: { id: "u-5" } } }),
833
+ ).resolves.toBe("ok:u-5");
834
+ expect(runPromiseExit).toHaveBeenCalledTimes(1);
835
+ });
836
+
837
+ it(".provideOptional makes present request-scoped services available", async () => {
838
+ class CurrentUser extends Context.Tag("OptionalCurrentUserPresent")<
839
+ CurrentUser,
840
+ { id: string }
841
+ >() {}
842
+
843
+ const procedure = makeEffectORPC(runtime)
844
+ .$context<{ user?: { id: string } }>()
845
+ .provideOptional(CurrentUser, ({ context }) =>
846
+ Effect.succeed(Option.fromNullable(context.user)),
847
+ )
848
+ .effect(function* () {
849
+ return yield* Effect.serviceOption(CurrentUser);
850
+ });
851
+
852
+ await expect(
853
+ call(procedure, undefined, { context: { user: { id: "u-6" } } }),
854
+ ).resolves.toEqual(Option.some({ id: "u-6" }));
855
+ });
856
+
857
+ it(".provideOptional leaves absent request-scoped services unavailable", async () => {
858
+ class CurrentUser extends Context.Tag("OptionalCurrentUserAbsent")<
859
+ CurrentUser,
860
+ { id: string }
861
+ >() {}
862
+
863
+ const procedure = makeEffectORPC(runtime)
864
+ .$context<{ user?: { id: string } }>()
865
+ .provideOptional(CurrentUser, ({ context }) =>
866
+ Effect.succeed(Option.fromNullable(context.user)),
867
+ )
868
+ .effect(function* () {
869
+ return yield* Effect.serviceOption(CurrentUser);
870
+ });
871
+
872
+ await expect(call(procedure, undefined, { context: {} })).resolves.toEqual(
873
+ Option.none(),
874
+ );
875
+ });
876
+
877
+ it(".provideOptional does not satisfy required service access", () => {
878
+ class OptionalService extends Context.Tag("OptionalServiceRequirement")<
879
+ OptionalService,
880
+ { readonly value: string }
881
+ >() {}
882
+
883
+ makeEffectORPC(runtime)
884
+ .provideOptional(OptionalService, () =>
885
+ Effect.succeed(Option.some({ value: "provided" })),
886
+ )
887
+ .effect(
888
+ // @ts-expect-error provideOptional does not guarantee the service exists
889
+ function* () {
890
+ return yield* OptionalService;
891
+ },
892
+ );
893
+ });
405
894
  });
406
895
 
407
896
  describe(".traced", () => {
@@ -630,4 +1119,52 @@ describe("default tracing (without .traced())", () => {
630
1119
  >;
631
1120
  expectTypeOf<ProcedureOutput>().toEqualTypeOf<{ name: string }>();
632
1121
  });
1122
+
1123
+ it("requires handler services to come from the runtime or .provide", () => {
1124
+ class MissingService extends Context.Tag("MissingService")<
1125
+ MissingService,
1126
+ { readonly value: string }
1127
+ >() {}
1128
+
1129
+ makeEffectORPC(runtime).effect(
1130
+ // @ts-expect-error MissingService is not available from the runtime or .provide
1131
+ function* () {
1132
+ return yield* MissingService;
1133
+ },
1134
+ );
1135
+
1136
+ makeEffectORPC(runtime)
1137
+ .provide(MissingService, () => Effect.succeed({ value: "provided" }))
1138
+ .effect(function* () {
1139
+ return yield* MissingService;
1140
+ });
1141
+ });
1142
+
1143
+ it("requires Effect middleware services to come from the runtime or .provide", () => {
1144
+ class MissingMiddlewareService extends Context.Tag(
1145
+ "MissingMiddlewareService",
1146
+ )<MissingMiddlewareService, { readonly value: string }>() {}
1147
+
1148
+ makeEffectORPC(runtime)
1149
+ .use(
1150
+ // @ts-expect-error MissingMiddlewareService is not available from the runtime or .provide
1151
+ function* () {
1152
+ yield* MissingMiddlewareService;
1153
+ },
1154
+ )
1155
+ .effect(function* () {
1156
+ return "ok";
1157
+ });
1158
+
1159
+ makeEffectORPC(runtime)
1160
+ .provide(MissingMiddlewareService, () =>
1161
+ Effect.succeed({ value: "provided" }),
1162
+ )
1163
+ .use(function* () {
1164
+ yield* MissingMiddlewareService;
1165
+ })
1166
+ .effect(function* () {
1167
+ return "ok";
1168
+ });
1169
+ });
633
1170
  });
@@ -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 }) {