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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-orpc",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "keywords": [
5
5
  "effect",
6
6
  "orpc",
package/src/contract.ts CHANGED
@@ -34,8 +34,11 @@ import { enhanceEffectRouter } from "./effect-enhance-router";
34
34
  import { EffectDecoratedProcedure } from "./effect-procedure";
35
35
  import { createEffectProcedureHandler } from "./effect-runtime";
36
36
  import { effectContractSymbol, getEffectContractErrorMap } from "./eoc";
37
- import type { EffectRuntimeSource } from "./runtime-source";
38
- import { toManagedRuntime } from "./runtime-source";
37
+ import type {
38
+ EffectRuntimeRunner,
39
+ EffectRuntimeSource,
40
+ } from "./runtime-source";
41
+ import { makeEffectRuntimeRunner } from "./runtime-source";
39
42
  import type { EffectErrorMap } from "./tagged-error";
40
43
  import { effectErrorMapToErrorMap } from "./tagged-error";
41
44
  import type { EffectErrorMapToErrorMap, EffectProcedureHandler } from "./types";
@@ -316,13 +319,13 @@ const CONTRACT_HIDDEN_METHODS = new Set([
316
319
  ]);
317
320
 
318
321
  function makeEnhanceOptions<TRequirementsProvided, TRuntimeError>(
319
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>,
322
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>,
320
323
  ) {
321
324
  return {
322
325
  middlewares: [],
323
326
  errorMap: {},
324
327
  dedupeLeadingMiddlewares: true,
325
- runtime,
328
+ runner,
326
329
  } as const;
327
330
  }
328
331
 
@@ -333,7 +336,7 @@ function wrapContractNode<
333
336
  >(
334
337
  contract: TContract,
335
338
  target: any,
336
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>,
339
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>,
337
340
  ): EffectImplementerInternal<
338
341
  TContract,
339
342
  Context,
@@ -362,9 +365,9 @@ function wrapContractNode<
362
365
  ...currentTarget["~orpc"],
363
366
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
364
367
  effectErrorMap,
365
- runtime,
368
+ runner,
366
369
  handler: createEffectProcedureHandler({
367
- runtime,
370
+ runner,
368
371
  effectErrorMap,
369
372
  effectFn,
370
373
  defaultCaptureStackTrace: addSpanStackTrace(),
@@ -385,7 +388,7 @@ function wrapContractNode<
385
388
  currentTarget,
386
389
  args,
387
390
  ),
388
- runtime,
391
+ runner,
389
392
  );
390
393
 
391
394
  cache.set(prop, use);
@@ -405,7 +408,7 @@ function wrapContractNode<
405
408
  currentTarget,
406
409
  args,
407
410
  ),
408
- runtime,
411
+ runner,
409
412
  );
410
413
 
411
414
  cache.set(prop, wrappedMethod);
@@ -420,7 +423,7 @@ function wrapContractNode<
420
423
  currentTarget,
421
424
  args,
422
425
  ) as any,
423
- makeEnhanceOptions(runtime),
426
+ makeEnhanceOptions(runner),
424
427
  );
425
428
 
426
429
  cache.set(prop, wrappedMethod);
@@ -431,7 +434,7 @@ function wrapContractNode<
431
434
  const child = wrapContractNode(
432
435
  (contract as Record<string, AnyContractRouter>)[prop]!,
433
436
  Reflect.get(currentTarget, prop, receiver),
434
- runtime,
437
+ runner,
435
438
  );
436
439
 
437
440
  cache.set(prop, child);
@@ -512,7 +515,7 @@ export function implementEffect<
512
515
  return wrapContractNode(
513
516
  contract,
514
517
  implement(contract),
515
- toManagedRuntime(source),
518
+ makeEffectRuntimeRunner(source),
516
519
  ) as EffectImplementer<
517
520
  TContract,
518
521
  Record<never, never>,
@@ -28,7 +28,7 @@ import {
28
28
  type EffectProxyTarget,
29
29
  } from "./extension/state";
30
30
  import type { EffectRuntimeSource } from "./runtime-source";
31
- import { toManagedRuntime } from "./runtime-source";
31
+ import { makeEffectRuntimeRunner } from "./runtime-source";
32
32
  import type { EffectErrorMap, MergedEffectErrorMap } from "./tagged-error";
33
33
  import { effectErrorMapToErrorMap } from "./tagged-error";
34
34
  import type {
@@ -106,7 +106,7 @@ function getEffectBuilderDef(
106
106
  return {
107
107
  ...context.upstream["~orpc"],
108
108
  effectErrorMap: context.state.effectErrorMap,
109
- runtime: context.state.runtime,
109
+ runner: context.state.runner,
110
110
  spanConfig: context.state.spanConfig,
111
111
  effectSteps: context.state.effectSteps,
112
112
  effectHandler: context.state.effectHandler,
@@ -121,7 +121,7 @@ function wrapBuilderLike(
121
121
  {
122
122
  ...builder["~orpc"],
123
123
  effectErrorMap: state.effectErrorMap,
124
- runtime: state.runtime,
124
+ runner: state.runner,
125
125
  spanConfig: state.spanConfig,
126
126
  effectSteps: state.effectSteps,
127
127
  effectHandler: state.effectHandler,
@@ -158,7 +158,7 @@ function flushEffectSteps(
158
158
 
159
159
  const middleware = createEffectPipelineMiddleware({
160
160
  effectErrorMap: state.effectErrorMap,
161
- runtime: state.runtime,
161
+ runner: state.runner,
162
162
  steps: state.effectSteps,
163
163
  });
164
164
  return {
@@ -238,7 +238,7 @@ function createEffectBuilderProxy(
238
238
  effectErrorMap: state.effectErrorMap,
239
239
  effectFn,
240
240
  effectSteps: state.effectSteps,
241
- runtime: state.runtime,
241
+ runner: state.runner,
242
242
  spanConfig: state.spanConfig,
243
243
  })(opts as any);
244
244
  },
@@ -251,7 +251,7 @@ function createEffectBuilderProxy(
251
251
  if (isEffectMiddleware(middleware)) {
252
252
  const effectMiddleware = createEffectPipelineMiddleware({
253
253
  effectErrorMap: state.effectErrorMap,
254
- runtime: state.runtime,
254
+ runner: state.runner,
255
255
  steps: [
256
256
  ...(state.effectSteps ?? []),
257
257
  { _tag: "middleware" as const, middleware },
@@ -698,7 +698,7 @@ export class EffectBuilder<
698
698
  *
699
699
  * @example
700
700
  * ```ts
701
- * const getUser = effectOs
701
+ * const getUser = effectProcedure
702
702
  * .input(z.object({ id: z.string() }))
703
703
  * .traced('users.getUser')
704
704
  * .effect(function* ({ input }) {
@@ -734,7 +734,7 @@ export class EffectBuilder<
734
734
  >["handler"];
735
735
  /**
736
736
  * Defines the handler of the procedure using an Effect.
737
- * The Effect is executed using the ManagedRuntime provided during builder creation.
737
+ * The Effect is executed using the configured Effect runtime source.
738
738
  * The effect is automatically wrapped with `Effect.withSpan`.
739
739
  *
740
740
  * @see {@link https://orpc.dev/docs/procedure Procedure Docs}
@@ -826,14 +826,13 @@ export class EffectBuilder<
826
826
  >,
827
827
  builder?: AnyBuilderLike,
828
828
  ) {
829
- const { runtime, spanConfig, effectErrorMap, effectSteps, ...orpcDef } =
830
- def;
829
+ const { runner, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
831
830
 
832
831
  attachEffectState(this, builder ?? new Builder(orpcDef), {
833
832
  effectSteps,
834
833
  effectHandler: def.effectHandler,
835
834
  effectErrorMap,
836
- runtime,
835
+ runner,
837
836
  spanConfig,
838
837
  });
839
838
 
@@ -853,9 +852,9 @@ export class EffectBuilder<
853
852
  * import { makeEffectORPC } from '@orpc/effect'
854
853
  * import { Effect, Layer } from 'effect'
855
854
  *
856
- * const effectOs = makeEffectORPC(Layer.empty)
855
+ * const effectProcedure = makeEffectORPC(Layer.empty)
857
856
  *
858
- * const hello = effectOs.effect(() => Effect.succeed('Hello!'))
857
+ * const hello = effectProcedure.effect(() => Effect.succeed('Hello!'))
859
858
  * ```
860
859
  */
861
860
  export function makeEffectORPC(): EffectBuilder<
@@ -943,9 +942,9 @@ export function makeEffectORPC<TRequirementsProvided, TRuntimeError>(
943
942
  * const authedOs = os.use(authMiddleware)
944
943
  *
945
944
  * // Wrap it with Effect support
946
- * const effectOs = makeEffectORPC(UserServiceLive, authedOs)
945
+ * const effectProcedure = makeEffectORPC(UserServiceLive, authedOs)
947
946
  *
948
- * const getUser = effectOs
947
+ * const getUser = effectProcedure
949
948
  * .input(z.object({ id: z.string() }))
950
949
  * .effect(
951
950
  * Effect.fn(function* ({ input }) {
@@ -1025,15 +1024,16 @@ export function makeEffectORPC(
1025
1024
  ? source
1026
1025
  : (builder ?? emptyBuilder());
1027
1026
  const effectErrorMap = getEffectErrorMap(resolvedBuilder);
1028
- const runtime = toManagedRuntime(
1029
- sourceIsBuilder || source === undefined ? Layer.empty : source,
1030
- );
1027
+ const runner =
1028
+ sourceIsBuilder || source === undefined
1029
+ ? makeEffectRuntimeRunner()
1030
+ : makeEffectRuntimeRunner(source);
1031
1031
  return new EffectBuilder(
1032
1032
  {
1033
1033
  ...resolvedBuilder["~orpc"],
1034
1034
  effectErrorMap: effectErrorMap,
1035
1035
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
1036
- runtime,
1036
+ runner,
1037
1037
  },
1038
1038
  unwrapEffectUpstream(resolvedBuilder),
1039
1039
  );
@@ -1051,3 +1051,12 @@ function emptyBuilder(): AnyBuilderLike {
1051
1051
  route: {},
1052
1052
  });
1053
1053
  }
1054
+
1055
+ /**
1056
+ * Runtime-less Effect oRPC builder, analogous to oRPC's `os` export.
1057
+ *
1058
+ * Provide application services with `.provide(layer)` or use
1059
+ * `makeEffectORPC(runtime)` when you need explicit ManagedRuntime lifecycle
1060
+ * control.
1061
+ */
1062
+ export const eos = makeEffectORPC();
@@ -16,10 +16,10 @@ import {
16
16
  type Context,
17
17
  type Lazyable,
18
18
  } from "@orpc/server";
19
- import type { ManagedRuntime } from "effect/ManagedRuntime";
20
19
 
21
20
  import { EffectProcedure } from "./effect-procedure";
22
21
  import { getEffectErrorMap, unwrapEffectUpstream } from "./extension/state";
22
+ import type { EffectRuntimeRunner } from "./runtime-source";
23
23
  import { effectErrorMapToErrorMap, type EffectErrorMap } from "./tagged-error";
24
24
  import type { EffectErrorMapToErrorMap, EnhancedEffectRouter } from "./types";
25
25
 
@@ -31,7 +31,7 @@ interface EnhanceEffectRouterOptions<
31
31
  middlewares: readonly AnyMiddleware[];
32
32
  errorMap: TEffectErrorMap;
33
33
  dedupeLeadingMiddlewares: boolean;
34
- runtime: ManagedRuntime<TRequirementsProvided, TRuntimeError>;
34
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
35
35
  }
36
36
 
37
37
  export function enhanceEffectRouter<
@@ -97,7 +97,7 @@ export function enhanceEffectRouter<
97
97
  source["~orpc"].inputValidationIndex + newMiddlewareAdded,
98
98
  outputValidationIndex:
99
99
  source["~orpc"].outputValidationIndex + newMiddlewareAdded,
100
- runtime: options.runtime,
100
+ runner: options.runner,
101
101
  }) as any;
102
102
  }
103
103
 
@@ -120,7 +120,7 @@ function getEffectProcedureDef(
120
120
  effectSteps: context.state.effectSteps,
121
121
  effectHandler: context.state.effectHandler,
122
122
  effectErrorMap: context.state.effectErrorMap,
123
- runtime: context.state.runtime,
123
+ runner: context.state.runner,
124
124
  };
125
125
  }
126
126
 
@@ -136,7 +136,7 @@ function makeEffectProcedureHandler(
136
136
  effectErrorMap: def.effectErrorMap,
137
137
  effectFn: def.effectHandler.effectFn,
138
138
  effectSteps: def.effectSteps,
139
- runtime: def.runtime,
139
+ runner: def.runner,
140
140
  spanConfig: def.effectHandler.spanConfig,
141
141
  });
142
142
  }
@@ -169,7 +169,7 @@ function flushEffectSteps(
169
169
 
170
170
  const middleware = createEffectPipelineMiddleware({
171
171
  effectErrorMap: def.effectErrorMap,
172
- runtime: def.runtime,
172
+ runner: def.runner,
173
173
  steps: def.effectSteps,
174
174
  });
175
175
 
@@ -255,7 +255,7 @@ function createEffectProcedureProxy<
255
255
  def.middlewares,
256
256
  createEffectPipelineMiddleware({
257
257
  effectErrorMap: state.effectErrorMap,
258
- runtime: state.runtime,
258
+ runner: state.runner,
259
259
  steps: [step],
260
260
  }),
261
261
  ),
@@ -279,7 +279,7 @@ function createEffectProcedureProxy<
279
279
  createEffectProviderMiddleware({
280
280
  effectErrorMap: state.effectErrorMap,
281
281
  provider,
282
- runtime: state.runtime,
282
+ runner: state.runner,
283
283
  tag: tagOrLayer,
284
284
  }),
285
285
  ),
@@ -308,7 +308,7 @@ function createEffectProcedureProxy<
308
308
  createEffectOptionalProviderMiddleware({
309
309
  effectErrorMap: state.effectErrorMap,
310
310
  provider,
311
- runtime: state.runtime,
311
+ runner: state.runner,
312
312
  tag,
313
313
  }),
314
314
  ),
@@ -473,7 +473,7 @@ export class EffectProcedure<
473
473
  effectSteps,
474
474
  effectHandler,
475
475
  effectErrorMap: def.effectErrorMap,
476
- runtime: def.runtime,
476
+ runner: def.runner,
477
477
  });
478
478
 
479
479
  if (new.target === EffectProcedure) {
@@ -9,10 +9,10 @@ import type {
9
9
  ProcedureHandlerOptions,
10
10
  } from "@orpc/server";
11
11
  import type { Promisable } from "@orpc/shared";
12
- import type { ManagedRuntime } from "effect";
13
- import { Cause, Effect, Exit, FiberRefs, Option } from "effect";
12
+ import { Cause, Effect, Exit, Option } from "effect";
14
13
 
15
- import { getCurrentFiberRefs, runWithFiberRefs } from "./fiber-context-bridge";
14
+ import { runWithFiberRefs } from "./fiber-context-bridge";
15
+ import type { EffectRuntimeRunner } from "./runtime-source";
16
16
  import type { EffectErrorConstructorMap, EffectErrorMap } from "./tagged-error";
17
17
  import {
18
18
  createEffectErrorConstructorMap,
@@ -78,7 +78,7 @@ export function createEffectProcedureHandler<
78
78
  TRuntimeError,
79
79
  TMeta extends Meta,
80
80
  >(options: {
81
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
81
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
82
82
  effectErrorMap: TEffectErrorMap;
83
83
  effectFn: EffectProcedureHandler<
84
84
  TCurrentContext,
@@ -99,7 +99,7 @@ export function createEffectProcedureHandler<
99
99
  TMeta & Record<never, never>
100
100
  > {
101
101
  const {
102
- runtime,
102
+ runner,
103
103
  effectErrorMap,
104
104
  effectFn,
105
105
  effectSteps = [],
@@ -145,10 +145,9 @@ export function createEffectProcedureHandler<
145
145
  spanName,
146
146
  { captureStackTrace },
147
147
  );
148
- const exit = await runtime.runPromiseExit(
149
- withParentFiberRefs(tracedEffect),
150
- { signal: opts.signal },
151
- );
148
+ const exit = await runner.runPromiseExit(tracedEffect, {
149
+ signal: opts.signal,
150
+ });
152
151
 
153
152
  if (Exit.isFailure(exit)) {
154
153
  throw toORPCErrorFromCause(exit.cause);
@@ -166,7 +165,7 @@ export function createEffectPipelineMiddleware<
166
165
  TRuntimeError,
167
166
  TMeta extends Meta,
168
167
  >(options: {
169
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
168
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
170
169
  effectErrorMap: TEffectErrorMap;
171
170
  steps: readonly EffectPipelineStep[];
172
171
  }): Middleware<
@@ -177,7 +176,7 @@ export function createEffectPipelineMiddleware<
177
176
  any,
178
177
  TMeta
179
178
  > {
180
- const { runtime, effectErrorMap, steps } = options;
179
+ const { runner, effectErrorMap, steps } = options;
181
180
 
182
181
  return async (opts, input) => {
183
182
  const baseOptions = makeEffectOptions<
@@ -186,7 +185,14 @@ export function createEffectPipelineMiddleware<
186
185
  TEffectErrorMap,
187
186
  TMeta
188
187
  >(opts, input, effectErrorMap);
189
- const effect = runEffectPipeline({
188
+ const effect = runEffectPipeline<
189
+ TCurrentContext,
190
+ unknown,
191
+ TOutput,
192
+ TEffectErrorMap,
193
+ TRequirementsProvided,
194
+ TMeta
195
+ >({
190
196
  baseOptions,
191
197
  effectErrorMap,
192
198
  final: (context) =>
@@ -200,10 +206,9 @@ export function createEffectPipelineMiddleware<
200
206
  input,
201
207
  steps,
202
208
  });
203
- const exit = await runtime.runPromiseExit(
204
- withParentFiberRefs(effect as any),
205
- { signal: opts.signal },
206
- );
209
+ const exit = await runner.runPromiseExit(effect, {
210
+ signal: opts.signal,
211
+ });
207
212
 
208
213
  if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
209
214
 
@@ -220,7 +225,7 @@ export function createEffectProviderMiddleware<
220
225
  TMeta extends Meta,
221
226
  TTag extends EffectTag,
222
227
  >(options: {
223
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
228
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
224
229
  effectErrorMap: TEffectErrorMap;
225
230
  tag: TTag;
226
231
  provider: EffectProvider<
@@ -232,7 +237,7 @@ export function createEffectProviderMiddleware<
232
237
  TTag
233
238
  >;
234
239
  }): Middleware<TCurrentContext, Record<never, never>, TInput, any, any, TMeta> {
235
- const { runtime, effectErrorMap, tag, provider } = options;
240
+ const { runner, effectErrorMap, tag, provider } = options;
236
241
 
237
242
  return async (opts, input) => {
238
243
  const effectOpts = makeEffectOptions<
@@ -248,7 +253,7 @@ export function createEffectProviderMiddleware<
248
253
  service,
249
254
  ),
250
255
  );
251
- const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
256
+ const exit = await runner.runPromiseExit(effect, {
252
257
  signal: opts.signal,
253
258
  });
254
259
 
@@ -267,7 +272,7 @@ export function createEffectOptionalProviderMiddleware<
267
272
  TMeta extends Meta,
268
273
  TTag extends EffectTag,
269
274
  >(options: {
270
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
275
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
271
276
  effectErrorMap: TEffectErrorMap;
272
277
  tag: TTag;
273
278
  provider: EffectOptionalProvider<
@@ -279,7 +284,7 @@ export function createEffectOptionalProviderMiddleware<
279
284
  TTag
280
285
  >;
281
286
  }): Middleware<TCurrentContext, Record<never, never>, TInput, any, any, TMeta> {
282
- const { runtime, effectErrorMap, tag, provider } = options;
287
+ const { runner, effectErrorMap, tag, provider } = options;
283
288
 
284
289
  return async (opts, input) => {
285
290
  const effectOpts = makeEffectOptions<
@@ -299,7 +304,7 @@ export function createEffectOptionalProviderMiddleware<
299
304
  ),
300
305
  }),
301
306
  );
302
- const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
307
+ const exit = await runner.runPromiseExit(effect, {
303
308
  signal: opts.signal,
304
309
  });
305
310
 
@@ -549,18 +554,3 @@ function withCurrentFiberContext<T>(fn: () => Promisable<T>): Effect.Effect<T> {
549
554
  ),
550
555
  );
551
556
  }
552
-
553
- function withParentFiberRefs<A, E, R>(
554
- effect: Effect.Effect<A, E, R>,
555
- ): Effect.Effect<A, E, R> {
556
- const parentFiberRefs = getCurrentFiberRefs();
557
- return parentFiberRefs
558
- ? Effect.fiberIdWith((fiberId) =>
559
- Effect.flatMap(Effect.getFiberRefs, (fiberRefs) =>
560
- Effect.setFiberRefs(
561
- FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs),
562
- ).pipe(Effect.andThen(effect)),
563
- ),
564
- )
565
- : effect;
566
- }
@@ -1,5 +1,4 @@
1
- import type { ManagedRuntime } from "effect";
2
-
1
+ import type { EffectRuntimeRunner } from "../runtime-source";
3
2
  import type { EffectErrorMap } from "../tagged-error";
4
3
  import type {
5
4
  EffectPipelineStep,
@@ -17,10 +16,9 @@ export interface EffectExtensionState<
17
16
  */
18
17
  effectErrorMap: EffectErrorMap;
19
18
  /**
20
- * The Effect ManagedRuntime that provides services for Effect procedures.
21
- * @see {@link ManagedRuntime.ManagedRuntime}
19
+ * Executes Effect values with the services configured for this builder.
22
20
  */
23
- runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
21
+ runner: EffectRuntimeRunner<TRequirementsProvided, TRuntimeError>;
24
22
  /**
25
23
  * Configuration for Effect span tracing.
26
24
  * @see {@link EffectSpanConfig}
package/src/index.ts CHANGED
@@ -16,6 +16,7 @@ export type {
16
16
  export {
17
17
  addSpanStackTrace,
18
18
  EffectBuilder,
19
+ eos,
19
20
  makeEffectORPC,
20
21
  } from "./effect-builder";
21
22
  export { EffectDecoratedProcedure } from "./effect-procedure";
@@ -1,18 +1,76 @@
1
- import { Layer, ManagedRuntime } from "effect";
1
+ import { Effect, Exit, FiberRefs, Layer, ManagedRuntime } from "effect";
2
+
3
+ import { getCurrentFiberRefs } from "./fiber-context-bridge";
2
4
 
3
5
  export type EffectRuntimeSource<TRequirementsProvided, TRuntimeError> =
4
6
  | ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>
5
7
  | Layer.Layer<TRequirementsProvided, TRuntimeError, never>;
6
8
 
7
- export function toManagedRuntime<TRequirementsProvided, TRuntimeError>(
8
- source: EffectRuntimeSource<TRequirementsProvided, TRuntimeError>,
9
- ): ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError> {
10
- return ManagedRuntime.isManagedRuntime(source)
11
- ? (source as ManagedRuntime.ManagedRuntime<
12
- TRequirementsProvided,
13
- TRuntimeError
14
- >)
15
- : ManagedRuntime.make(
16
- source as Layer.Layer<TRequirementsProvided, TRuntimeError, never>,
17
- );
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;
18
76
  }
@@ -341,7 +341,7 @@ export function ORPCTaggedError<
341
341
  *
342
342
  * @example
343
343
  * ```ts
344
- * const handler = effectOs.effect(function* () {
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))
@@ -76,14 +76,11 @@ describe("implementEffect", () => {
76
76
  };
77
77
  });
78
78
 
79
- try {
80
- await expect(call(procedure, { amount: 2 })).resolves.toEqual({
81
- next: 3,
82
- requestId: "layer",
83
- });
84
- } finally {
85
- await procedure["~effect"].runtime.dispose();
86
- }
79
+ expect(procedure["~effect"].runner.runtime).toBeUndefined();
80
+ await expect(call(procedure, { amount: 2 })).resolves.toEqual({
81
+ next: 3,
82
+ requestId: "layer",
83
+ });
87
84
  });
88
85
 
89
86
  it("preserves contract enforcement at the root router", async () => {
@@ -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
  );