effect-orpc 0.3.0 → 0.5.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/dist/index.js CHANGED
@@ -175,6 +175,7 @@ function effectErrorMapToErrorMap(errorMap) {
175
175
  }
176
176
 
177
177
  // src/effect-runtime.ts
178
+ var HybridContinuationSymbol = /* @__PURE__ */ Symbol("effect-orpc/HybridContinuation");
178
179
  function toORPCErrorFromCause(cause) {
179
180
  return Cause2.match(cause, {
180
181
  onDie(defect) {
@@ -211,7 +212,7 @@ function toORPCErrorFromCause(cause) {
211
212
  }
212
213
  function createEffectProcedureHandler(options) {
213
214
  const {
214
- runtime,
215
+ runner,
215
216
  effectErrorMap,
216
217
  effectFn,
217
218
  effectSteps = [],
@@ -230,26 +231,25 @@ function createEffectProcedureHandler(options) {
230
231
  };
231
232
  const spanName = spanConfig?.name ?? opts.path.join(".");
232
233
  const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
233
- const resolver = Effect.fnUntraced(effectFn);
234
- const handlerEffect = resolver(effectOpts);
234
+ const handlerEffect = callEffectCallback(effectFn, effectOpts);
235
235
  const tracedEffect = Effect.withSpan(
236
236
  runEffectPipeline({
237
237
  baseOptions: effectOpts,
238
238
  effectErrorMap,
239
239
  final: (context) => Effect.map(
240
- context === effectOpts.context ? handlerEffect : resolver({ ...effectOpts, context }),
240
+ context === effectOpts.context ? handlerEffect : callEffectCallback(effectFn, { ...effectOpts, context }),
241
241
  (output) => ({ output, context: {} })
242
242
  ),
243
243
  input: opts.input,
244
+ runner,
244
245
  steps: effectSteps
245
246
  }),
246
247
  spanName,
247
248
  { captureStackTrace }
248
249
  );
249
- const exit = await runtime.runPromiseExit(
250
- withParentFiberRefs(tracedEffect),
251
- { signal: opts.signal }
252
- );
250
+ const exit = await runner.runPromiseExit(tracedEffect, {
251
+ signal: opts.signal
252
+ });
253
253
  if (Exit.isFailure(exit)) {
254
254
  throw toORPCErrorFromCause(exit.cause);
255
255
  }
@@ -257,7 +257,7 @@ function createEffectProcedureHandler(options) {
257
257
  };
258
258
  }
259
259
  function createEffectPipelineMiddleware(options) {
260
- const { runtime, effectErrorMap, steps } = options;
260
+ const { runner, effectErrorMap, steps } = options;
261
261
  return async (opts, input) => {
262
262
  const baseOptions = makeEffectOptions(opts, input, effectErrorMap);
263
263
  const effect = runEffectPipeline({
@@ -269,29 +269,169 @@ function createEffectPipelineMiddleware(options) {
269
269
  )
270
270
  ),
271
271
  input,
272
+ runner,
272
273
  steps
273
274
  });
274
- const exit = await runtime.runPromiseExit(
275
- withParentFiberRefs(effect),
276
- { signal: opts.signal }
277
- );
275
+ const exit = await runner.runPromiseExit(effect, {
276
+ signal: opts.signal
277
+ });
278
278
  if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
279
279
  return exit.value;
280
280
  };
281
281
  }
282
+ function createEffectOrORPCMiddleware(options) {
283
+ const { runner, effectErrorMap, middleware } = options;
284
+ return async (opts, input, output) => {
285
+ const effectOptions = makeEffectMiddlewareOptions({
286
+ effectErrorMap,
287
+ final: opts.next,
288
+ options: opts,
289
+ output
290
+ });
291
+ return runEffectOrORPCMiddlewareCallback({
292
+ effectOptions,
293
+ input,
294
+ middleware,
295
+ nativeNext: opts.next,
296
+ runner,
297
+ signal: opts.signal
298
+ });
299
+ };
300
+ }
301
+ async function runEffectOrORPCMiddlewareCallback(options) {
302
+ const result = options.middleware(
303
+ options.effectOptions,
304
+ options.input,
305
+ options.effectOptions.output
306
+ );
307
+ const classified = classifyEffectOrORPCMiddlewareResult(result);
308
+ switch (classified._tag) {
309
+ case "nativeContinuation":
310
+ return classified.result;
311
+ case "nativeGuardOnly":
312
+ return options.nativeNext();
313
+ case "nativeResult":
314
+ return classified.result;
315
+ case "effect": {
316
+ const exit = await options.runner.runPromiseExit(
317
+ runEffectMiddlewareResult({
318
+ autoNext: () => options.effectOptions.next(),
319
+ effect: classified.effect,
320
+ nextInvoked: options.effectOptions.nextTracker.nextInvoked,
321
+ nextResult: options.effectOptions.nextTracker.nextResult
322
+ }),
323
+ { signal: options.signal }
324
+ );
325
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
326
+ return exit.value;
327
+ }
328
+ }
329
+ }
330
+ function classifyEffectOrORPCMiddlewareResult(result) {
331
+ if (isHybridContinuation(result)) {
332
+ return {
333
+ _tag: "nativeContinuation",
334
+ result
335
+ };
336
+ }
337
+ if (Effect.isEffect(result) || isGeneratorIterator(result)) {
338
+ return {
339
+ _tag: "effect",
340
+ effect: effectFromCallbackResult(result)
341
+ };
342
+ }
343
+ if (result === void 0) {
344
+ return { _tag: "nativeGuardOnly" };
345
+ }
346
+ return {
347
+ _tag: "nativeResult",
348
+ result
349
+ };
350
+ }
351
+ function runEffectMiddlewareResult(options) {
352
+ return Effect.flatMap(
353
+ options.effect,
354
+ (result) => resolveEffectMiddlewareContinuation({
355
+ autoNext: options.autoNext,
356
+ nextInvoked: options.nextInvoked,
357
+ nextResult: options.nextResult,
358
+ result
359
+ })
360
+ );
361
+ }
362
+ function makeEffectMiddlewareOptions(options) {
363
+ const nextTracker = createMiddlewareNextTracker();
364
+ const effectOptions = {
365
+ context: options.options.context,
366
+ path: options.options.path,
367
+ procedure: options.options.procedure,
368
+ signal: options.options.signal,
369
+ lastEventId: options.options.lastEventId,
370
+ errors: createEffectErrorConstructorMap(options.effectErrorMap),
371
+ next: nextTracker.wrapNext(
372
+ (...rest) => makeHybridMiddlewareContinuation({
373
+ final: options.final,
374
+ nextTracker,
375
+ rest
376
+ })
377
+ ),
378
+ nextTracker,
379
+ output: makeEffectMiddlewareOutput(options.output)
380
+ };
381
+ return effectOptions;
382
+ }
383
+ function makeHybridMiddlewareContinuation(options) {
384
+ const nextContext = options.rest[0]?.context ?? {};
385
+ const toEffectResult = (result) => ({
386
+ output: result.output,
387
+ context: nextContext
388
+ });
389
+ const effect = Effect.map(
390
+ withCurrentFiberContext(() => options.final(...options.rest)),
391
+ toEffectResult
392
+ );
393
+ return makeHybridContinuation(effect, {
394
+ onResult: options.nextTracker.setNextResult,
395
+ run: () => options.final(...options.rest),
396
+ toEffectResult
397
+ });
398
+ }
399
+ function makeHybridContinuation(effect, options) {
400
+ markHybridContinuation(effect);
401
+ attachPromiseLikeContinuation(
402
+ effect,
403
+ (onFulfilled, onRejected) => Promise.resolve(options.run()).then(options.toEffectResult).then((result) => {
404
+ options.onResult?.(result);
405
+ return result;
406
+ }).then(onFulfilled, onRejected)
407
+ );
408
+ return effect;
409
+ }
410
+ function markHybridContinuation(value) {
411
+ Object.defineProperty(value, HybridContinuationSymbol, {
412
+ configurable: true,
413
+ value: true
414
+ });
415
+ }
416
+ function attachPromiseLikeContinuation(value, then) {
417
+ Object.defineProperty(value, "then", {
418
+ configurable: true,
419
+ value: then
420
+ });
421
+ }
282
422
  function createEffectProviderMiddleware(options) {
283
- const { runtime, effectErrorMap, tag, provider } = options;
423
+ const { runner, effectErrorMap, tag, provider } = options;
284
424
  return async (opts, input) => {
285
425
  const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
286
426
  const effect = Effect.flatMap(
287
- provider(effectOpts),
427
+ callEffectCallback(provider, effectOpts),
288
428
  (service) => Effect.provideService(
289
429
  withCurrentFiberContext(() => opts.next()),
290
430
  tag,
291
431
  service
292
432
  )
293
433
  );
294
- const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
434
+ const exit = await runner.runPromiseExit(effect, {
295
435
  signal: opts.signal
296
436
  });
297
437
  if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
@@ -299,11 +439,11 @@ function createEffectProviderMiddleware(options) {
299
439
  };
300
440
  }
301
441
  function createEffectOptionalProviderMiddleware(options) {
302
- const { runtime, effectErrorMap, tag, provider } = options;
442
+ const { runner, effectErrorMap, tag, provider } = options;
303
443
  return async (opts, input) => {
304
444
  const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
305
445
  const effect = Effect.flatMap(
306
- provider(effectOpts),
446
+ callEffectCallback(provider, effectOpts),
307
447
  (service) => Option.match(service, {
308
448
  onNone: () => withCurrentFiberContext(() => opts.next()),
309
449
  onSome: (value) => Effect.provideService(
@@ -313,16 +453,57 @@ function createEffectOptionalProviderMiddleware(options) {
313
453
  )
314
454
  })
315
455
  );
316
- const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
456
+ const exit = await runner.runPromiseExit(effect, {
317
457
  signal: opts.signal
318
458
  });
319
459
  if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
320
460
  return exit.value;
321
461
  };
322
462
  }
323
- function isEffectMiddleware(value) {
463
+ function callEffectCallback(callback, ...args) {
464
+ if (isGeneratorFunction(callback)) {
465
+ return Effect.fnUntraced(callback)(...args);
466
+ }
467
+ return Effect.suspend(() => {
468
+ try {
469
+ return effectFromCallbackResult(callback(...args));
470
+ } catch (error) {
471
+ return Effect.fail(error);
472
+ }
473
+ });
474
+ }
475
+ function effectFromCallbackResult(result) {
476
+ if (Effect.isEffect(result)) {
477
+ return result;
478
+ }
479
+ if (isGeneratorIterator(result)) {
480
+ return Effect.fnUntraced(function* () {
481
+ return yield* result;
482
+ })();
483
+ }
484
+ if (isPromiseLike(result)) {
485
+ return Effect.promise(() => result);
486
+ }
487
+ return Effect.succeed(result);
488
+ }
489
+ function isGeneratorIterator(value) {
490
+ return typeof value === "object" && value !== null && "next" in value && typeof value.next === "function" && "throw" in value && typeof value.throw === "function";
491
+ }
492
+ function isHybridContinuation(value) {
493
+ return (typeof value === "object" || typeof value === "function") && value !== null && HybridContinuationSymbol in value;
494
+ }
495
+ function isPromiseLike(value) {
496
+ return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
497
+ }
498
+ function isGeneratorFunction(value) {
324
499
  return typeof value === "function" && value.constructor?.name === "GeneratorFunction";
325
500
  }
501
+ function isEffectMiddleware(value) {
502
+ return isGeneratorFunction(value);
503
+ }
504
+ function isDecoratedMiddleware(value) {
505
+ return typeof value === "function" && "mapInput" in value && "concat" in value;
506
+ }
326
507
  function makeEffectOptions(opts, input, effectErrorMap) {
327
508
  return {
328
509
  context: opts.context,
@@ -341,13 +522,13 @@ function runEffectPipeline(options) {
341
522
  const stepOptions = { ...options.baseOptions, context };
342
523
  if (step._tag === "provide") {
343
524
  return Effect.flatMap(
344
- step.provider(stepOptions),
525
+ callEffectCallback(step.provider, stepOptions),
345
526
  (service) => Effect.provideService(run(index + 1, context), step.tag, service)
346
527
  );
347
528
  }
348
529
  if (step._tag === "provideOptional") {
349
530
  return Effect.flatMap(
350
- step.provider(stepOptions),
531
+ callEffectCallback(step.provider, stepOptions),
351
532
  (service) => Option.match(service, {
352
533
  onNone: () => run(index + 1, context),
353
534
  onSome: (value) => Effect.provideService(run(index + 1, context), step.tag, value)
@@ -357,46 +538,57 @@ function runEffectPipeline(options) {
357
538
  if (step._tag === "provideLayer") {
358
539
  return Effect.provide(run(index + 1, context), step.layer);
359
540
  }
360
- const nextTracker = createMiddlewareNextTracker();
361
- const effectOptions = {
362
- context,
363
- path: stepOptions.path,
364
- procedure: stepOptions.procedure,
365
- signal: stepOptions.signal,
366
- lastEventId: stepOptions.lastEventId,
367
- errors: createEffectErrorConstructorMap(options.effectErrorMap),
368
- next: nextTracker.wrapNext(
369
- (...rest) => {
370
- const nextContext = rest[0]?.context ?? {};
371
- return Effect.map(
372
- run(index + 1, { ...context, ...nextContext }),
373
- (result) => ({
374
- output: result.output,
375
- context: nextContext
376
- })
377
- );
378
- }
379
- )
380
- };
381
- const effectOutput = makeEffectMiddlewareOutput((output) => ({ output, context: {} }));
382
- const middlewareEffect = Effect.fnUntraced(step.middleware)(
383
- effectOptions,
384
- options.input,
385
- effectOutput
386
- );
387
- return Effect.flatMap(
388
- middlewareEffect,
389
- (result) => resolveEffectMiddlewareContinuation({
390
- autoNext: () => effectOptions.next(),
391
- nextInvoked: nextTracker.nextInvoked,
392
- nextResult: nextTracker.nextResult,
393
- result
394
- })
395
- );
541
+ return Effect.flatMap(Effect.getFiberRefs, (fiberRefs) => {
542
+ const makeThenable = (effect) => makeThenableEffect(
543
+ effect,
544
+ options.runner,
545
+ fiberRefs,
546
+ stepOptions.signal
547
+ );
548
+ const nextTracker = createMiddlewareNextTracker(
549
+ makeThenable
550
+ );
551
+ const effectOptions = {
552
+ context,
553
+ path: stepOptions.path,
554
+ procedure: stepOptions.procedure,
555
+ signal: stepOptions.signal,
556
+ lastEventId: stepOptions.lastEventId,
557
+ errors: createEffectErrorConstructorMap(options.effectErrorMap),
558
+ next: nextTracker.wrapNext(
559
+ (...rest) => {
560
+ const nextContext = rest[0]?.context ?? {};
561
+ return Effect.map(
562
+ run(index + 1, { ...context, ...nextContext }),
563
+ (result) => ({
564
+ output: result.output,
565
+ context: nextContext
566
+ })
567
+ );
568
+ }
569
+ )
570
+ };
571
+ const effectOutput = makeEffectMiddlewareOutput((output) => ({ output, context: {} }), makeThenable);
572
+ const middlewareEffect = callEffectCallback(
573
+ step.middleware,
574
+ effectOptions,
575
+ options.input,
576
+ effectOutput
577
+ );
578
+ return Effect.flatMap(
579
+ middlewareEffect,
580
+ (result) => resolveEffectMiddlewareContinuation({
581
+ autoNext: () => effectOptions.next(),
582
+ nextInvoked: nextTracker.nextInvoked,
583
+ nextResult: nextTracker.nextResult,
584
+ result
585
+ })
586
+ );
587
+ });
396
588
  };
397
589
  return run(0, options.baseOptions.context);
398
590
  }
399
- function createMiddlewareNextTracker() {
591
+ function createMiddlewareNextTracker(makeThenable) {
400
592
  let nextInvoked = false;
401
593
  let nextResult;
402
594
  return {
@@ -406,13 +598,26 @@ function createMiddlewareNextTracker() {
406
598
  get nextResult() {
407
599
  return nextResult;
408
600
  },
601
+ setNextResult(result) {
602
+ nextResult = result;
603
+ },
409
604
  wrapNext(nextFn) {
410
605
  return ((...args) => {
411
606
  nextInvoked = true;
412
- return Effect.map(nextFn(...args), (result) => {
607
+ const inner = nextFn(...args);
608
+ const tracked = Effect.map(inner, (result) => {
413
609
  nextResult = result;
414
610
  return result;
415
611
  });
612
+ if (isHybridContinuation(inner)) {
613
+ markHybridContinuation(tracked);
614
+ attachPromiseLikeContinuation(
615
+ tracked,
616
+ inner.then.bind(inner)
617
+ );
618
+ return tracked;
619
+ }
620
+ return makeThenable ? makeThenable(tracked) : tracked;
416
621
  });
417
622
  }
418
623
  };
@@ -434,27 +639,51 @@ function resolveEffectMiddlewareContinuation(options) {
434
639
  }
435
640
  return autoNext();
436
641
  }
437
- function makeEffectMiddlewareOutput(output) {
438
- return (value) => withCurrentFiberContext(() => output(value));
642
+ function makeEffectMiddlewareOutput(output, makeThenable) {
643
+ return (value) => {
644
+ const effect = withCurrentFiberContext(() => output(value));
645
+ return makeThenable ? makeThenable(effect) : effect;
646
+ };
439
647
  }
440
- function withCurrentFiberContext(fn) {
441
- return Effect.flatMap(
442
- Effect.getFiberRefs,
443
- (fiberRefs) => Effect.promise(
444
- () => runWithFiberRefs(fiberRefs, () => Promise.resolve(fn()))
648
+ function makeThenableEffect(effect, runner, fiberRefs, signal) {
649
+ if ("then" in effect) {
650
+ return effect;
651
+ }
652
+ attachPromiseLikeContinuation(
653
+ effect,
654
+ (onFulfilled, onRejected) => runNestedEffect(effect, runner, fiberRefs, signal).then(
655
+ onFulfilled,
656
+ onRejected
445
657
  )
446
658
  );
659
+ return effect;
447
660
  }
448
- function withParentFiberRefs(effect) {
449
- const parentFiberRefs = getCurrentFiberRefs();
450
- return parentFiberRefs ? Effect.fiberIdWith(
661
+ async function runNestedEffect(effect, runner, fiberRefs, signal) {
662
+ const exit = await runner.runPromiseExit(withFiberRefs(effect, fiberRefs), {
663
+ signal
664
+ });
665
+ if (Exit.isFailure(exit)) {
666
+ throw toORPCErrorFromCause(exit.cause);
667
+ }
668
+ return exit.value;
669
+ }
670
+ function withFiberRefs(effect, parentFiberRefs) {
671
+ return Effect.fiberIdWith(
451
672
  (fiberId) => Effect.flatMap(
452
673
  Effect.getFiberRefs,
453
674
  (fiberRefs) => Effect.setFiberRefs(
454
675
  FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
455
676
  ).pipe(Effect.andThen(effect))
456
677
  )
457
- ) : effect;
678
+ );
679
+ }
680
+ function withCurrentFiberContext(fn) {
681
+ return Effect.flatMap(
682
+ Effect.getFiberRefs,
683
+ (fiberRefs) => Effect.promise(
684
+ () => runWithFiberRefs(fiberRefs, () => Promise.resolve(fn()))
685
+ )
686
+ );
458
687
  }
459
688
 
460
689
  // src/extension/compose-surfaces.ts
@@ -668,7 +897,7 @@ function getEffectProcedureDef(context) {
668
897
  effectSteps: context.state.effectSteps,
669
898
  effectHandler: context.state.effectHandler,
670
899
  effectErrorMap: context.state.effectErrorMap,
671
- runtime: context.state.runtime
900
+ runner: context.state.runner
672
901
  };
673
902
  }
674
903
  function makeEffectProcedureHandler(def) {
@@ -680,7 +909,7 @@ function makeEffectProcedureHandler(def) {
680
909
  effectErrorMap: def.effectErrorMap,
681
910
  effectFn: def.effectHandler.effectFn,
682
911
  effectSteps: def.effectSteps,
683
- runtime: def.runtime,
912
+ runner: def.runner,
684
913
  spanConfig: def.effectHandler.spanConfig
685
914
  });
686
915
  }
@@ -702,7 +931,7 @@ function flushEffectSteps(def) {
702
931
  }
703
932
  const middleware = createEffectPipelineMiddleware({
704
933
  effectErrorMap: def.effectErrorMap,
705
- runtime: def.runtime,
934
+ runner: def.runner,
706
935
  steps: def.effectSteps
707
936
  });
708
937
  return withRebuiltEffectHandler({
@@ -770,7 +999,7 @@ function createEffectProcedureProxy(target, decorated) {
770
999
  def.middlewares,
771
1000
  createEffectPipelineMiddleware({
772
1001
  effectErrorMap: state.effectErrorMap,
773
- runtime: state.runtime,
1002
+ runner: state.runner,
774
1003
  steps: [step]
775
1004
  })
776
1005
  )
@@ -792,7 +1021,7 @@ function createEffectProcedureProxy(target, decorated) {
792
1021
  createEffectProviderMiddleware({
793
1022
  effectErrorMap: state.effectErrorMap,
794
1023
  provider,
795
- runtime: state.runtime,
1024
+ runner: state.runner,
796
1025
  tag: tagOrLayer
797
1026
  })
798
1027
  )
@@ -819,7 +1048,7 @@ function createEffectProcedureProxy(target, decorated) {
819
1048
  createEffectOptionalProviderMiddleware({
820
1049
  effectErrorMap: state.effectErrorMap,
821
1050
  provider,
822
- runtime: state.runtime,
1051
+ runner: state.runner,
823
1052
  tag
824
1053
  })
825
1054
  )
@@ -831,15 +1060,33 @@ function createEffectProcedureProxy(target, decorated) {
831
1060
  return (middleware, mapInput) => {
832
1061
  const def = getEffectProcedureDef(context);
833
1062
  if (!mapInput && isEffectMiddleware(middleware)) {
834
- return new EffectDecoratedProcedure(
835
- appendEffectStep(def, {
836
- _tag: "middleware",
837
- middleware
838
- })
839
- );
1063
+ const step = {
1064
+ _tag: "middleware",
1065
+ middleware
1066
+ };
1067
+ if (def.effectHandler) {
1068
+ return new EffectDecoratedProcedure(
1069
+ appendEffectStep(def, step)
1070
+ );
1071
+ }
1072
+ return new EffectDecoratedProcedure({
1073
+ ...def,
1074
+ middlewares: addMiddleware(
1075
+ def.middlewares,
1076
+ createEffectPipelineMiddleware({
1077
+ effectErrorMap: state.effectErrorMap,
1078
+ runner: state.runner,
1079
+ steps: [step]
1080
+ })
1081
+ )
1082
+ });
840
1083
  }
841
1084
  const flushedDef = flushEffectSteps(def);
842
- const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
1085
+ const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : isDecoratedMiddleware(middleware) ? middleware : createEffectOrORPCMiddleware({
1086
+ effectErrorMap: state.effectErrorMap,
1087
+ middleware,
1088
+ runner: state.runner
1089
+ });
843
1090
  return new EffectDecoratedProcedure({
844
1091
  ...flushedDef,
845
1092
  middlewares: addMiddleware(flushedDef.middlewares, mapped)
@@ -885,7 +1132,7 @@ var EffectProcedure = class _EffectProcedure extends Procedure {
885
1132
  effectSteps,
886
1133
  effectHandler,
887
1134
  effectErrorMap: def.effectErrorMap,
888
- runtime: def.runtime
1135
+ runner: def.runner
889
1136
  });
890
1137
  if (new.target === _EffectProcedure) {
891
1138
  return createEffectProcedureProxy(this, false);
@@ -940,7 +1187,7 @@ function enhanceEffectRouter(router, options) {
940
1187
  middlewares,
941
1188
  inputValidationIndex: source["~orpc"].inputValidationIndex + newMiddlewareAdded,
942
1189
  outputValidationIndex: source["~orpc"].outputValidationIndex + newMiddlewareAdded,
943
- runtime: options.runtime
1190
+ runner: options.runner
944
1191
  });
945
1192
  }
946
1193
  const enhanced = {};
@@ -951,11 +1198,42 @@ function enhanceEffectRouter(router, options) {
951
1198
  }
952
1199
 
953
1200
  // src/runtime-source.ts
954
- import { ManagedRuntime } from "effect";
955
- function toManagedRuntime(source) {
956
- return ManagedRuntime.isManagedRuntime(source) ? source : ManagedRuntime.make(
957
- source
958
- );
1201
+ import { Effect as Effect2, FiberRefs as FiberRefs2, ManagedRuntime } from "effect";
1202
+ function makeEffectRuntimeRunner(source) {
1203
+ if (source === void 0) {
1204
+ return {
1205
+ runPromiseExit: (effect, options) => Effect2.runPromiseExit(withParentFiberRefs(effect), {
1206
+ signal: options?.signal
1207
+ })
1208
+ };
1209
+ }
1210
+ if (ManagedRuntime.isManagedRuntime(source)) {
1211
+ const runtime = source;
1212
+ return {
1213
+ runtime,
1214
+ runPromiseExit: (effect, options) => runtime.runPromiseExit(withParentFiberRefs(effect), {
1215
+ signal: options?.signal
1216
+ })
1217
+ };
1218
+ }
1219
+ const layer = source;
1220
+ return {
1221
+ runPromiseExit: (effect, options) => Effect2.runPromiseExit(
1222
+ withParentFiberRefs(Effect2.provide(effect, layer)),
1223
+ { signal: options?.signal }
1224
+ )
1225
+ };
1226
+ }
1227
+ function withParentFiberRefs(effect) {
1228
+ const parentFiberRefs = getCurrentFiberRefs();
1229
+ return parentFiberRefs ? Effect2.fiberIdWith(
1230
+ (fiberId) => Effect2.flatMap(
1231
+ Effect2.getFiberRefs,
1232
+ (fiberRefs) => Effect2.setFiberRefs(
1233
+ FiberRefs2.joinAs(fiberRefs, fiberId, parentFiberRefs)
1234
+ ).pipe(Effect2.andThen(effect))
1235
+ )
1236
+ ) : effect;
959
1237
  }
960
1238
 
961
1239
  // src/effect-builder.ts
@@ -999,7 +1277,7 @@ function getEffectBuilderDef(context) {
999
1277
  return {
1000
1278
  ...context.upstream["~orpc"],
1001
1279
  effectErrorMap: context.state.effectErrorMap,
1002
- runtime: context.state.runtime,
1280
+ runner: context.state.runner,
1003
1281
  spanConfig: context.state.spanConfig,
1004
1282
  effectSteps: context.state.effectSteps,
1005
1283
  effectHandler: context.state.effectHandler
@@ -1010,7 +1288,7 @@ function wrapBuilderLike(builder, state) {
1010
1288
  {
1011
1289
  ...builder["~orpc"],
1012
1290
  effectErrorMap: state.effectErrorMap,
1013
- runtime: state.runtime,
1291
+ runner: state.runner,
1014
1292
  spanConfig: state.spanConfig,
1015
1293
  effectSteps: state.effectSteps,
1016
1294
  effectHandler: state.effectHandler
@@ -1030,7 +1308,7 @@ function flushEffectSteps2(builder, state) {
1030
1308
  }
1031
1309
  const middleware = createEffectPipelineMiddleware({
1032
1310
  effectErrorMap: state.effectErrorMap,
1033
- runtime: state.runtime,
1311
+ runner: state.runner,
1034
1312
  steps: state.effectSteps
1035
1313
  });
1036
1314
  return {
@@ -1088,7 +1366,7 @@ function createEffectBuilderProxy(target) {
1088
1366
  effectErrorMap: state.effectErrorMap,
1089
1367
  effectFn,
1090
1368
  effectSteps: state.effectSteps,
1091
- runtime: state.runtime,
1369
+ runner: state.runner,
1092
1370
  spanConfig: state.spanConfig
1093
1371
  })(opts);
1094
1372
  }
@@ -1098,25 +1376,22 @@ function createEffectBuilderProxy(target) {
1098
1376
  case "middleware":
1099
1377
  return getOrCreateVirtualMethod2(context, prop, () => {
1100
1378
  return (middleware) => {
1101
- if (isEffectMiddleware(middleware)) {
1102
- const effectMiddleware = createEffectPipelineMiddleware({
1103
- effectErrorMap: state.effectErrorMap,
1104
- runtime: state.runtime,
1105
- steps: [
1106
- ...state.effectSteps ?? [],
1107
- { _tag: "middleware", middleware }
1108
- ]
1109
- });
1110
- return Reflect.apply(
1111
- Reflect.get(source, "middleware", source),
1112
- source,
1113
- [effectMiddleware]
1114
- );
1115
- }
1379
+ const effectMiddleware = isEffectMiddleware(middleware) ? createEffectPipelineMiddleware({
1380
+ effectErrorMap: state.effectErrorMap,
1381
+ runner: state.runner,
1382
+ steps: [
1383
+ ...state.effectSteps ?? [],
1384
+ { _tag: "middleware", middleware }
1385
+ ]
1386
+ }) : createEffectOrORPCMiddleware({
1387
+ effectErrorMap: state.effectErrorMap,
1388
+ middleware,
1389
+ runner: state.runner
1390
+ });
1116
1391
  return Reflect.apply(
1117
1392
  Reflect.get(source, "middleware", source),
1118
1393
  source,
1119
- [middleware]
1394
+ [effectMiddleware]
1120
1395
  );
1121
1396
  };
1122
1397
  });
@@ -1148,7 +1423,7 @@ function createEffectBuilderProxy(target) {
1148
1423
  case "use":
1149
1424
  return getOrCreateVirtualMethod2(context, prop, () => {
1150
1425
  return (middleware, ...rest) => {
1151
- if (isEffectMiddleware(middleware) && rest.length === 0) {
1426
+ if (rest.length === 0 && isEffectMiddleware(middleware)) {
1152
1427
  return wrapBuilderLike(
1153
1428
  source,
1154
1429
  appendEffectStep2(state, {
@@ -1161,7 +1436,14 @@ function createEffectBuilderProxy(target) {
1161
1436
  const nextBuilder = Reflect.apply(
1162
1437
  Reflect.get(flushed.builder, "use", flushed.builder),
1163
1438
  flushed.builder,
1164
- [middleware, ...rest]
1439
+ [
1440
+ rest.length === 0 && !isDecoratedMiddleware(middleware) ? createEffectOrORPCMiddleware({
1441
+ effectErrorMap: flushed.state.effectErrorMap,
1442
+ middleware,
1443
+ runner: flushed.state.runner
1444
+ }) : middleware,
1445
+ ...rest
1446
+ ]
1165
1447
  );
1166
1448
  return wrapBuilderLike(nextBuilder, flushed.state);
1167
1449
  };
@@ -1178,10 +1460,16 @@ function createEffectBuilderProxy(target) {
1178
1460
  });
1179
1461
  case "handler":
1180
1462
  return getOrCreateVirtualMethod2(context, prop, () => {
1181
- return (handler) => new EffectDecoratedProcedure({
1182
- ...effectDef,
1183
- handler
1184
- });
1463
+ return (handler) => {
1464
+ const flushed = flushEffectSteps2(source, state);
1465
+ return new EffectDecoratedProcedure({
1466
+ ...flushed.builder["~orpc"],
1467
+ effectErrorMap: flushed.state.effectErrorMap,
1468
+ runner: flushed.state.runner,
1469
+ effectSteps: flushed.state.effectSteps,
1470
+ handler
1471
+ });
1472
+ };
1185
1473
  });
1186
1474
  case "router":
1187
1475
  return getOrCreateVirtualMethod2(context, prop, () => {
@@ -1227,12 +1515,12 @@ function addSpanStackTrace() {
1227
1515
  }
1228
1516
  var EffectBuilder = class {
1229
1517
  constructor(def, builder) {
1230
- const { runtime, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
1518
+ const { runner, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
1231
1519
  attachEffectState(this, builder ?? new Builder(orpcDef), {
1232
1520
  effectSteps,
1233
1521
  effectHandler: def.effectHandler,
1234
1522
  effectErrorMap,
1235
- runtime,
1523
+ runner,
1236
1524
  spanConfig
1237
1525
  });
1238
1526
  return createEffectBuilderProxy(this);
@@ -1242,15 +1530,13 @@ function makeEffectORPC(source, builder) {
1242
1530
  const sourceIsBuilder = source !== void 0 && isBuilderLike(source);
1243
1531
  const resolvedBuilder = sourceIsBuilder ? source : builder ?? emptyBuilder();
1244
1532
  const effectErrorMap = getEffectErrorMap(resolvedBuilder);
1245
- const runtime = toManagedRuntime(
1246
- sourceIsBuilder || source === void 0 ? Layer3.empty : source
1247
- );
1533
+ const runner = sourceIsBuilder || source === void 0 ? makeEffectRuntimeRunner() : makeEffectRuntimeRunner(source);
1248
1534
  return new EffectBuilder(
1249
1535
  {
1250
1536
  ...resolvedBuilder["~orpc"],
1251
1537
  effectErrorMap,
1252
1538
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
1253
- runtime
1539
+ runner
1254
1540
  },
1255
1541
  unwrapEffectUpstream(resolvedBuilder)
1256
1542
  );
@@ -1267,6 +1553,7 @@ function emptyBuilder() {
1267
1553
  route: {}
1268
1554
  });
1269
1555
  }
1556
+ var eos = makeEffectORPC();
1270
1557
 
1271
1558
  // src/eoc.ts
1272
1559
  import { isContractProcedure, oc } from "@orpc/contract";
@@ -1405,15 +1692,15 @@ var CONTRACT_HIDDEN_METHODS = /* @__PURE__ */ new Set([
1405
1692
  "router",
1406
1693
  "tag"
1407
1694
  ]);
1408
- function makeEnhanceOptions(runtime) {
1695
+ function makeEnhanceOptions(runner) {
1409
1696
  return {
1410
1697
  middlewares: [],
1411
1698
  errorMap: {},
1412
1699
  dedupeLeadingMiddlewares: true,
1413
- runtime
1700
+ runner
1414
1701
  };
1415
1702
  }
1416
- function wrapContractNode(contract, target, runtime) {
1703
+ function wrapContractNode(contract, target, runner) {
1417
1704
  const cache = /* @__PURE__ */ new Map();
1418
1705
  return new Proxy(target, {
1419
1706
  get(currentTarget, prop, receiver) {
@@ -1428,9 +1715,9 @@ function wrapContractNode(contract, target, runtime) {
1428
1715
  ...currentTarget["~orpc"],
1429
1716
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
1430
1717
  effectErrorMap,
1431
- runtime,
1718
+ runner,
1432
1719
  handler: createEffectProcedureHandler({
1433
- runtime,
1720
+ runner,
1434
1721
  effectErrorMap,
1435
1722
  effectFn,
1436
1723
  defaultCaptureStackTrace: addSpanStackTrace()
@@ -1448,7 +1735,7 @@ function wrapContractNode(contract, target, runtime) {
1448
1735
  currentTarget,
1449
1736
  args
1450
1737
  ),
1451
- runtime
1738
+ runner
1452
1739
  );
1453
1740
  cache.set(prop, use);
1454
1741
  return use;
@@ -1465,7 +1752,7 @@ function wrapContractNode(contract, target, runtime) {
1465
1752
  currentTarget,
1466
1753
  args
1467
1754
  ),
1468
- runtime
1755
+ runner
1469
1756
  );
1470
1757
  cache.set(prop, wrappedMethod);
1471
1758
  return wrappedMethod;
@@ -1477,7 +1764,7 @@ function wrapContractNode(contract, target, runtime) {
1477
1764
  currentTarget,
1478
1765
  args
1479
1766
  ),
1480
- makeEnhanceOptions(runtime)
1767
+ makeEnhanceOptions(runner)
1481
1768
  );
1482
1769
  cache.set(prop, wrappedMethod);
1483
1770
  return wrappedMethod;
@@ -1486,7 +1773,7 @@ function wrapContractNode(contract, target, runtime) {
1486
1773
  const child = wrapContractNode(
1487
1774
  contract[prop],
1488
1775
  Reflect.get(currentTarget, prop, receiver),
1489
- runtime
1776
+ runner
1490
1777
  );
1491
1778
  cache.set(prop, child);
1492
1779
  return child;
@@ -1514,7 +1801,7 @@ function implementEffect(contract, source) {
1514
1801
  return wrapContractNode(
1515
1802
  contract,
1516
1803
  implement(contract),
1517
- toManagedRuntime(source)
1804
+ makeEffectRuntimeRunner(source)
1518
1805
  );
1519
1806
  }
1520
1807
  export {
@@ -1526,6 +1813,7 @@ export {
1526
1813
  createEffectErrorConstructorMap,
1527
1814
  effectErrorMapToErrorMap,
1528
1815
  eoc,
1816
+ eos,
1529
1817
  implementEffect,
1530
1818
  isORPCTaggedError,
1531
1819
  isORPCTaggedErrorClass,