effect-orpc 1.0.0-effect-v4.3 → 1.0.0-effect-v4.5

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.
Files changed (38) hide show
  1. package/README.md +100 -5
  2. package/dist/{chunk-E5YLLTJI.js → chunk-I5EWBI42.js} +1 -1
  3. package/dist/chunk-I5EWBI42.js.map +1 -0
  4. package/dist/index.js +786 -465
  5. package/dist/index.js.map +1 -1
  6. package/dist/node.js +2 -2
  7. package/dist/node.js.map +1 -1
  8. package/package.json +4 -4
  9. package/src/contract.ts +491 -0
  10. package/src/effect-builder.ts +384 -506
  11. package/src/effect-enhance-router.ts +20 -21
  12. package/src/effect-procedure.ts +276 -221
  13. package/src/effect-runtime.ts +144 -0
  14. package/src/eoc.ts +499 -0
  15. package/src/extension/compose-surfaces.ts +15 -0
  16. package/src/extension/create-node-proxy.ts +270 -0
  17. package/src/extension/state.ts +108 -0
  18. package/src/index.ts +20 -3
  19. package/src/node.ts +3 -3
  20. package/src/service-context-bridge.ts +3 -3
  21. package/src/tagged-error.ts +24 -4
  22. package/src/tests/contract.test.ts +348 -0
  23. package/src/tests/effect-builder.proxy.test.ts +253 -0
  24. package/src/tests/effect-builder.test.ts +5 -5
  25. package/src/tests/effect-error-map.test.ts +22 -3
  26. package/src/tests/parity-shared.ts +32 -0
  27. package/src/tests/parity.contract-builder-variants.test.ts +192 -0
  28. package/src/tests/parity.contract-builder.test.ts +222 -0
  29. package/src/tests/parity.effect-builder.test.ts +210 -0
  30. package/src/tests/parity.effect-procedure.test.ts +124 -0
  31. package/src/tests/parity.implementer-variants.test.ts +249 -0
  32. package/src/tests/parity.implementer.test.ts +280 -0
  33. package/src/tests/shared.ts +2 -0
  34. package/src/types/effect-builder-surface.ts +441 -0
  35. package/src/types/effect-procedure-surface.ts +243 -0
  36. package/src/types/index.ts +22 -26
  37. package/src/types/variants.ts +100 -16
  38. package/dist/chunk-E5YLLTJI.js.map +0 -1
package/README.md CHANGED
@@ -29,7 +29,7 @@ Runnable demos live in the repository's `examples/` directory.
29
29
 
30
30
  ```ts
31
31
  import { os } from "@orpc/server";
32
- import { Effect, Layer, ManagedRuntime, ServiceMap } from "effect";
32
+ import { Effect, Layer, ManagedRuntime, Context } from "effect";
33
33
  import { makeEffectORPC, ORPCTaggedError } from "effect-orpc";
34
34
 
35
35
  interface User {
@@ -53,7 +53,7 @@ const authedOs = os
53
53
  });
54
54
 
55
55
  // Define your services
56
- class UsersRepo extends ServiceMap.Service<
56
+ class UsersRepo extends Context.Service<
57
57
  UsersRepo,
58
58
  {
59
59
  readonly get: (id: number) => User | undefined;
@@ -99,17 +99,17 @@ export type Router = typeof router;
99
99
  The wrapper enforces that Effect procedures only use services provided by the `ManagedRuntime`. If you try to use a service that isn't in the runtime, you'll get a compile-time error:
100
100
 
101
101
  ```ts
102
- import { Effect, Layer, ManagedRuntime, ServiceMap } from "effect";
102
+ import { Effect, Layer, ManagedRuntime, Context } from "effect";
103
103
  import { makeEffectORPC } from "effect-orpc";
104
104
 
105
- class ProvidedService extends ServiceMap.Service<
105
+ class ProvidedService extends Context.Service<
106
106
  ProvidedService,
107
107
  {
108
108
  readonly doSomething: () => Effect.Effect<string>;
109
109
  }
110
110
  >()("ProvidedService") {}
111
111
 
112
- class MissingService extends ServiceMap.Service<
112
+ class MissingService extends Context.Service<
113
113
  MissingService,
114
114
  {
115
115
  readonly doSomething: () => Effect.Effect<string>;
@@ -327,6 +327,55 @@ runtime-agnostic.
327
327
  If you do not need framework-to-handler fiber propagation, you do not need the
328
328
  `/node` entrypoint at all.
329
329
 
330
+ ## Contract-First Usage
331
+
332
+ Use `implementEffect(contract, runtime)` when you already have an oRPC contract
333
+ and want to keep contract-first enforcement while adding Effect-native handlers.
334
+ Use `makeEffectORPC(runtime, builder?)` when you want to build procedures
335
+ directly from an oRPC builder.
336
+
337
+ ```ts
338
+ import { Effect, ManagedRuntime } from "effect";
339
+ import { eoc, implementEffect } from "effect-orpc";
340
+ import z from "zod";
341
+
342
+ class UsersRepo extends Effect.Service<UsersRepo>()("UsersRepo", {
343
+ accessors: true,
344
+ sync: () => ({
345
+ list: (amount: number) =>
346
+ Array.from({ length: amount }, (_, index) => `user-${index + 1}`),
347
+ }),
348
+ }) {}
349
+
350
+ const contract = {
351
+ users: {
352
+ list: eoc
353
+ .input(z.object({ amount: z.number().int().positive() }))
354
+ .output(z.array(z.string())),
355
+ },
356
+ };
357
+
358
+ const runtime = ManagedRuntime.make(UsersRepo.Default);
359
+ const oe = implementEffect(contract, runtime);
360
+
361
+ export const router = oe.router({
362
+ users: {
363
+ list: oe.users.list.effect(function* ({ input }) {
364
+ return yield* UsersRepo.list(input.amount);
365
+ }),
366
+ },
367
+ });
368
+ ```
369
+
370
+ Contract leaves keep the contract-defined input, output, and error surface.
371
+ They add `.effect(...)` alongside existing implementer methods such as
372
+ `.handler(...)` and `.use(...)`, but do not expose contract-changing builder
373
+ methods like `.input(...)` or `.output(...)`.
374
+
375
+ If your contract declares tagged Effect error classes, prefer `eoc.errors(...)`
376
+ instead of raw `oc.errors(...)` so the error schema and metadata are derived
377
+ directly from the `ORPCTaggedError` class.
378
+
330
379
  ## API Reference
331
380
 
332
381
  ### `makeEffectORPC(runtime, builder?)`
@@ -346,6 +395,52 @@ const effectOs = makeEffectORPC(runtime);
346
395
  const effectAuthedOs = makeEffectORPC(runtime, authedBuilder);
347
396
  ```
348
397
 
398
+ ### `implementEffect(contract, runtime)`
399
+
400
+ Creates an Effect-aware contract implementer.
401
+
402
+ - `contract` - An oRPC contract router built with `oc`
403
+ - `runtime` - A `ManagedRuntime<R, E>` instance that provides services for Effect procedures
404
+
405
+ Returns a contract-shaped implementer tree whose leaves support `.effect(...)`.
406
+
407
+ ```ts
408
+ const oe = implementEffect(contract, runtime);
409
+
410
+ const router = oe.router({
411
+ users: {
412
+ list: oe.users.list.effect(function* ({ input }) {
413
+ return yield* UsersRepo.list(input.amount);
414
+ }),
415
+ },
416
+ });
417
+ ```
418
+
419
+ ### `eoc`
420
+
421
+ An Effect-aware wrapper around oRPC's `oc` contract builder.
422
+
423
+ Use it when you want contract definitions to accept `ORPCTaggedError` classes
424
+ directly in `.errors(...)` without duplicating the error schema.
425
+
426
+ ```ts
427
+ class UserNotFoundError extends ORPCTaggedError("UserNotFoundError", {
428
+ code: "NOT_FOUND",
429
+ schema: z.object({ userId: z.string() }),
430
+ }) {}
431
+
432
+ const contract = {
433
+ users: {
434
+ find: eoc
435
+ .errors({
436
+ NOT_FOUND: UserNotFoundError,
437
+ })
438
+ .input(z.object({ userId: z.string() }))
439
+ .output(z.object({ userId: z.string() })),
440
+ },
441
+ };
442
+ ```
443
+
349
444
  ### `EffectBuilder`
350
445
 
351
446
  Wraps an oRPC Builder with Effect support. Available methods:
@@ -11,4 +11,4 @@ export {
11
11
  installServiceContextBridge,
12
12
  getCurrentServices
13
13
  };
14
- //# sourceMappingURL=chunk-E5YLLTJI.js.map
14
+ //# sourceMappingURL=chunk-I5EWBI42.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/service-context-bridge.ts"],"sourcesContent":["import type { Context } from \"effect\";\n\nexport interface ServiceContextBridge {\n readonly getCurrentServices: () => Context.Context<any> | undefined;\n}\n\nlet bridge: ServiceContextBridge | undefined;\n\nexport function installServiceContextBridge(\n nextBridge: ServiceContextBridge | undefined,\n): void {\n bridge = nextBridge;\n}\n\nexport function getCurrentServices(): Context.Context<any> | undefined {\n return bridge?.getCurrentServices();\n}\n"],"mappings":";AAMA,IAAI;AAEG,SAAS,4BACd,YACM;AACN,WAAS;AACX;AAEO,SAAS,qBAAuD;AACrE,SAAO,QAAQ,mBAAmB;AACpC;","names":[]}