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.
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
- getCurrentFiberRefs
3
- } from "./chunk-VOWRLWZZ.js";
2
+ getCurrentFiberRefs,
3
+ runWithFiberRefs
4
+ } from "./chunk-IJP6L2XR.js";
4
5
 
5
6
  // src/contract.ts
6
7
  import { isContractProcedure as isContractProcedure2 } from "@orpc/contract";
@@ -8,6 +9,7 @@ import { implement } from "@orpc/server";
8
9
 
9
10
  // src/effect-builder.ts
10
11
  import { Builder, fallbackConfig, lazy as lazy2 } from "@orpc/server";
12
+ import { Layer as Layer3 } from "effect";
11
13
 
12
14
  // src/effect-enhance-router.ts
13
15
  import {
@@ -27,12 +29,420 @@ import {
27
29
  // src/effect-procedure.ts
28
30
  import { mergeMeta, mergeRoute } from "@orpc/contract";
29
31
  import {
32
+ Procedure,
30
33
  addMiddleware,
31
34
  createActionableClient,
32
35
  createProcedureClient,
33
- decorateMiddleware,
34
- Procedure
36
+ decorateMiddleware
35
37
  } from "@orpc/server";
38
+ import { Layer } from "effect";
39
+
40
+ // src/effect-runtime.ts
41
+ import { ORPCError as ORPCError2 } from "@orpc/contract";
42
+ import { Cause as Cause2, Effect, Exit, Option } from "effect";
43
+
44
+ // src/tagged-error.ts
45
+ import {
46
+ fallbackORPCErrorMessage,
47
+ fallbackORPCErrorStatus,
48
+ isORPCErrorStatus,
49
+ ORPCError
50
+ } from "@orpc/client";
51
+ import { resolveMaybeOptionalOptions } from "@orpc/shared";
52
+ import "effect/Cause";
53
+ import * as Data from "effect/Data";
54
+ var ORPCErrorSymbol = /* @__PURE__ */ Symbol.for(
55
+ "@orpc/effect/ORPCTaggedError"
56
+ );
57
+ function isORPCTaggedErrorClass(value) {
58
+ return typeof value === "function" && "_tag" in value && "code" in value && typeof value._tag === "string" && typeof value.code === "string";
59
+ }
60
+ function isORPCTaggedError(value) {
61
+ return typeof value === "object" && value !== null && ORPCErrorSymbol in value;
62
+ }
63
+ function toConstantCase(str) {
64
+ return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toUpperCase();
65
+ }
66
+ function ORPCTaggedError(tag, props) {
67
+ const code = props?.code ?? toConstantCase(tag);
68
+ class ORPCTaggedErrorBase extends Data.TaggedError(tag) {
69
+ status;
70
+ defined;
71
+ data;
72
+ code = code;
73
+ schema = props?.schema;
74
+ [ORPCErrorSymbol];
75
+ constructor(...rest) {
76
+ super();
77
+ const opts = resolveMaybeOptionalOptions(rest);
78
+ const status = opts.status ?? props?.status;
79
+ if (status !== void 0 && !isORPCErrorStatus(status)) {
80
+ throw new globalThis.Error(
81
+ "[ORPCTaggedError] Invalid error status code."
82
+ );
83
+ }
84
+ this.status = fallbackORPCErrorStatus(code, status);
85
+ this.defined = opts.defined ?? true;
86
+ this.data = opts.data;
87
+ this.message = fallbackORPCErrorMessage(
88
+ this.code,
89
+ opts.message ?? props?.message
90
+ );
91
+ this.cause = opts.cause;
92
+ this[ORPCErrorSymbol] = new ORPCError(
93
+ this.code,
94
+ {
95
+ status: this.status,
96
+ message: this.message,
97
+ data: this.data,
98
+ defined: this.defined,
99
+ cause: this.cause
100
+ }
101
+ );
102
+ }
103
+ /**
104
+ * Converts this error to a plain ORPCError.
105
+ * Useful when you need to return from an oRPC handler.
106
+ */
107
+ toORPCError() {
108
+ return this[ORPCErrorSymbol];
109
+ }
110
+ toJSON() {
111
+ return {
112
+ _tag: this._tag,
113
+ defined: this[ORPCErrorSymbol].defined,
114
+ code: this[ORPCErrorSymbol].code,
115
+ status: this[ORPCErrorSymbol].status,
116
+ message: this[ORPCErrorSymbol].message,
117
+ data: this[ORPCErrorSymbol].data
118
+ };
119
+ }
120
+ }
121
+ return Object.assign(ORPCTaggedErrorBase, {
122
+ _tag: tag,
123
+ code
124
+ });
125
+ }
126
+ function toORPCError(error) {
127
+ return error[ORPCErrorSymbol];
128
+ }
129
+ function createEffectErrorConstructorMap(errors) {
130
+ const target = errors ?? {};
131
+ const proxy = new Proxy(target, {
132
+ get(proxyTarget, code) {
133
+ if (typeof code !== "string") {
134
+ return Reflect.get(proxyTarget, code);
135
+ }
136
+ const config = target[code];
137
+ if (isORPCTaggedErrorClass(config)) {
138
+ return (...opts) => new config(...opts);
139
+ }
140
+ return (...rest) => {
141
+ const options = resolveMaybeOptionalOptions(rest);
142
+ return new ORPCError(code, {
143
+ defined: Boolean(config),
144
+ status: config?.status,
145
+ message: options.message ?? config?.message,
146
+ data: options.data,
147
+ cause: options.cause
148
+ });
149
+ };
150
+ }
151
+ });
152
+ return proxy;
153
+ }
154
+ function effectErrorMapToErrorMap(errorMap) {
155
+ const result = {};
156
+ if (!errorMap) {
157
+ return result;
158
+ }
159
+ for (const [code, ClassOrErrorItem] of Object.entries(errorMap)) {
160
+ if (!ClassOrErrorItem) {
161
+ continue;
162
+ }
163
+ if (isORPCTaggedErrorClass(ClassOrErrorItem)) {
164
+ const classInstance = new ClassOrErrorItem();
165
+ result[classInstance.code] = {
166
+ status: classInstance.status,
167
+ message: classInstance.message,
168
+ data: classInstance.schema
169
+ };
170
+ } else {
171
+ result[code] = ClassOrErrorItem;
172
+ }
173
+ }
174
+ return result;
175
+ }
176
+
177
+ // src/effect-runtime.ts
178
+ function toORPCErrorFromCause(cause) {
179
+ return Cause2.match(cause, {
180
+ onDie(defect) {
181
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
182
+ cause: defect
183
+ });
184
+ },
185
+ onFail(error) {
186
+ if (isORPCTaggedError(error)) {
187
+ return error.toORPCError();
188
+ }
189
+ if (error instanceof ORPCError2) {
190
+ return error;
191
+ }
192
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
193
+ cause: error
194
+ });
195
+ },
196
+ onInterrupt(fiberId) {
197
+ return new ORPCError2("INTERNAL_SERVER_ERROR", {
198
+ cause: new Error(`${fiberId} Interrupted`)
199
+ });
200
+ },
201
+ onSequential(left) {
202
+ return left;
203
+ },
204
+ onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
205
+ cause: new Error("Unknown error")
206
+ }),
207
+ onParallel(left) {
208
+ return left;
209
+ }
210
+ });
211
+ }
212
+ function createEffectProcedureHandler(options) {
213
+ const {
214
+ runner,
215
+ effectErrorMap,
216
+ effectFn,
217
+ effectSteps = [],
218
+ spanConfig,
219
+ defaultCaptureStackTrace
220
+ } = options;
221
+ return async (opts) => {
222
+ const effectOpts = {
223
+ context: opts.context,
224
+ input: opts.input,
225
+ path: opts.path,
226
+ procedure: opts.procedure,
227
+ signal: opts.signal,
228
+ lastEventId: opts.lastEventId,
229
+ errors: createEffectErrorConstructorMap(effectErrorMap)
230
+ };
231
+ const spanName = spanConfig?.name ?? opts.path.join(".");
232
+ const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
233
+ const resolver = Effect.fnUntraced(effectFn);
234
+ const handlerEffect = resolver(effectOpts);
235
+ const tracedEffect = Effect.withSpan(
236
+ runEffectPipeline({
237
+ baseOptions: effectOpts,
238
+ effectErrorMap,
239
+ final: (context) => Effect.map(
240
+ context === effectOpts.context ? handlerEffect : resolver({ ...effectOpts, context }),
241
+ (output) => ({ output, context: {} })
242
+ ),
243
+ input: opts.input,
244
+ steps: effectSteps
245
+ }),
246
+ spanName,
247
+ { captureStackTrace }
248
+ );
249
+ const exit = await runner.runPromiseExit(tracedEffect, {
250
+ signal: opts.signal
251
+ });
252
+ if (Exit.isFailure(exit)) {
253
+ throw toORPCErrorFromCause(exit.cause);
254
+ }
255
+ return exit.value.output;
256
+ };
257
+ }
258
+ function createEffectPipelineMiddleware(options) {
259
+ const { runner, effectErrorMap, steps } = options;
260
+ return async (opts, input) => {
261
+ const baseOptions = makeEffectOptions(opts, input, effectErrorMap);
262
+ const effect = runEffectPipeline({
263
+ baseOptions,
264
+ effectErrorMap,
265
+ final: (context) => withCurrentFiberContext(
266
+ () => opts.next(
267
+ context === opts.context ? void 0 : { context }
268
+ )
269
+ ),
270
+ input,
271
+ steps
272
+ });
273
+ const exit = await runner.runPromiseExit(effect, {
274
+ signal: opts.signal
275
+ });
276
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
277
+ return exit.value;
278
+ };
279
+ }
280
+ function createEffectProviderMiddleware(options) {
281
+ const { runner, effectErrorMap, tag, provider } = options;
282
+ return async (opts, input) => {
283
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
284
+ const effect = Effect.flatMap(
285
+ provider(effectOpts),
286
+ (service) => Effect.provideService(
287
+ withCurrentFiberContext(() => opts.next()),
288
+ tag,
289
+ service
290
+ )
291
+ );
292
+ const exit = await runner.runPromiseExit(effect, {
293
+ signal: opts.signal
294
+ });
295
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
296
+ return exit.value;
297
+ };
298
+ }
299
+ function createEffectOptionalProviderMiddleware(options) {
300
+ const { runner, effectErrorMap, tag, provider } = options;
301
+ return async (opts, input) => {
302
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
303
+ const effect = Effect.flatMap(
304
+ provider(effectOpts),
305
+ (service) => Option.match(service, {
306
+ onNone: () => withCurrentFiberContext(() => opts.next()),
307
+ onSome: (value) => Effect.provideService(
308
+ withCurrentFiberContext(() => opts.next()),
309
+ tag,
310
+ value
311
+ )
312
+ })
313
+ );
314
+ const exit = await runner.runPromiseExit(effect, {
315
+ signal: opts.signal
316
+ });
317
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
318
+ return exit.value;
319
+ };
320
+ }
321
+ function isEffectMiddleware(value) {
322
+ return typeof value === "function" && value.constructor?.name === "GeneratorFunction";
323
+ }
324
+ function makeEffectOptions(opts, input, effectErrorMap) {
325
+ return {
326
+ context: opts.context,
327
+ input,
328
+ path: opts.path,
329
+ procedure: opts.procedure,
330
+ signal: opts.signal,
331
+ lastEventId: opts.lastEventId,
332
+ errors: createEffectErrorConstructorMap(effectErrorMap)
333
+ };
334
+ }
335
+ function runEffectPipeline(options) {
336
+ const run = (index, context) => {
337
+ const step = options.steps[index];
338
+ if (!step) return options.final(context);
339
+ const stepOptions = { ...options.baseOptions, context };
340
+ if (step._tag === "provide") {
341
+ return Effect.flatMap(
342
+ step.provider(stepOptions),
343
+ (service) => Effect.provideService(run(index + 1, context), step.tag, service)
344
+ );
345
+ }
346
+ if (step._tag === "provideOptional") {
347
+ return Effect.flatMap(
348
+ step.provider(stepOptions),
349
+ (service) => Option.match(service, {
350
+ onNone: () => run(index + 1, context),
351
+ onSome: (value) => Effect.provideService(run(index + 1, context), step.tag, value)
352
+ })
353
+ );
354
+ }
355
+ if (step._tag === "provideLayer") {
356
+ return Effect.provide(run(index + 1, context), step.layer);
357
+ }
358
+ const nextTracker = createMiddlewareNextTracker();
359
+ const effectOptions = {
360
+ context,
361
+ path: stepOptions.path,
362
+ procedure: stepOptions.procedure,
363
+ signal: stepOptions.signal,
364
+ lastEventId: stepOptions.lastEventId,
365
+ errors: createEffectErrorConstructorMap(options.effectErrorMap),
366
+ next: nextTracker.wrapNext(
367
+ (...rest) => {
368
+ const nextContext = rest[0]?.context ?? {};
369
+ return Effect.map(
370
+ run(index + 1, { ...context, ...nextContext }),
371
+ (result) => ({
372
+ output: result.output,
373
+ context: nextContext
374
+ })
375
+ );
376
+ }
377
+ )
378
+ };
379
+ const effectOutput = makeEffectMiddlewareOutput((output) => ({ output, context: {} }));
380
+ const middlewareEffect = Effect.fnUntraced(step.middleware)(
381
+ effectOptions,
382
+ options.input,
383
+ effectOutput
384
+ );
385
+ return Effect.flatMap(
386
+ middlewareEffect,
387
+ (result) => resolveEffectMiddlewareContinuation({
388
+ autoNext: () => effectOptions.next(),
389
+ nextInvoked: nextTracker.nextInvoked,
390
+ nextResult: nextTracker.nextResult,
391
+ result
392
+ })
393
+ );
394
+ };
395
+ return run(0, options.baseOptions.context);
396
+ }
397
+ function createMiddlewareNextTracker() {
398
+ let nextInvoked = false;
399
+ let nextResult;
400
+ return {
401
+ get nextInvoked() {
402
+ return nextInvoked;
403
+ },
404
+ get nextResult() {
405
+ return nextResult;
406
+ },
407
+ wrapNext(nextFn) {
408
+ return ((...args) => {
409
+ nextInvoked = true;
410
+ return Effect.map(nextFn(...args), (result) => {
411
+ nextResult = result;
412
+ return result;
413
+ });
414
+ });
415
+ }
416
+ };
417
+ }
418
+ function resolveEffectMiddlewareContinuation(options) {
419
+ const { result, nextInvoked, nextResult, autoNext } = options;
420
+ if (result !== void 0) {
421
+ return Effect.succeed(result);
422
+ }
423
+ if (nextInvoked) {
424
+ if (nextResult === void 0) {
425
+ return Effect.die(
426
+ new Error(
427
+ "Effect middleware invoked next() but did not return its result"
428
+ )
429
+ );
430
+ }
431
+ return Effect.succeed(nextResult);
432
+ }
433
+ return autoNext();
434
+ }
435
+ function makeEffectMiddlewareOutput(output) {
436
+ return (value) => withCurrentFiberContext(() => output(value));
437
+ }
438
+ function withCurrentFiberContext(fn) {
439
+ return Effect.flatMap(
440
+ Effect.getFiberRefs,
441
+ (fiberRefs) => Effect.promise(
442
+ () => runWithFiberRefs(fiberRefs, () => Promise.resolve(fn()))
443
+ )
444
+ );
445
+ }
36
446
 
37
447
  // src/extension/compose-surfaces.ts
38
448
  function composeSurfaceProxy(surface, target) {
@@ -98,7 +508,8 @@ function createBoundMethod(context, prop, value, config, receiver) {
98
508
  return cache.get(prop);
99
509
  }
100
510
  const wrapped = (...args) => {
101
- const result = Reflect.apply(value, context.upstream, args);
511
+ const nextArgs = config.wrapArgs?.(context, prop, args, receiver) ?? args;
512
+ const result = Reflect.apply(value, context.upstream, nextArgs);
102
513
  return config.wrapResult?.(context, prop, result, receiver) ?? result;
103
514
  };
104
515
  cache.set(prop, wrapped);
@@ -158,184 +569,51 @@ function createNodeProxy(target, config) {
158
569
  for (const key of Reflect.ownKeys(context.upstream)) {
159
570
  keys.add(key);
160
571
  }
161
- for (const key of virtualKeys) {
162
- keys.add(key);
163
- }
164
- return [...keys];
165
- },
166
- getOwnPropertyDescriptor(currentTarget, prop) {
167
- const context = createNodeProxyContext(
168
- currentTarget
169
- );
170
- if (virtualKeys.has(prop)) {
171
- const value = config.getVirtual?.(context, prop, currentTarget);
172
- if (value !== void 0 && value !== unhandledProperty) {
173
- return {
174
- configurable: true,
175
- enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
176
- value,
177
- writable: false
178
- };
179
- }
180
- }
181
- const descriptor = Reflect.getOwnPropertyDescriptor(
182
- context.upstream,
183
- prop
184
- );
185
- if (descriptor === void 0) {
186
- return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
187
- }
188
- if ("value" in descriptor && typeof descriptor.value === "function") {
189
- return {
190
- ...descriptor,
191
- value: createBoundMethod(
192
- context,
193
- prop,
194
- descriptor.value,
195
- config,
196
- currentTarget
197
- )
198
- };
199
- }
200
- return descriptor;
201
- }
202
- });
203
- }
204
- function unhandled() {
205
- return unhandledProperty;
206
- }
207
-
208
- // src/tagged-error.ts
209
- import {
210
- fallbackORPCErrorMessage,
211
- fallbackORPCErrorStatus,
212
- isORPCErrorStatus,
213
- ORPCError
214
- } from "@orpc/client";
215
- import { resolveMaybeOptionalOptions } from "@orpc/shared";
216
- import "effect/Cause";
217
- import * as Data from "effect/Data";
218
- var ORPCErrorSymbol = /* @__PURE__ */ Symbol.for(
219
- "@orpc/effect/ORPCTaggedError"
220
- );
221
- function isORPCTaggedErrorClass(value) {
222
- return typeof value === "function" && "_tag" in value && "code" in value && typeof value._tag === "string" && typeof value.code === "string";
223
- }
224
- function isORPCTaggedError(value) {
225
- return typeof value === "object" && value !== null && ORPCErrorSymbol in value;
226
- }
227
- function toConstantCase(str) {
228
- return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toUpperCase();
229
- }
230
- function ORPCTaggedError(tag, props) {
231
- const code = props?.code ?? toConstantCase(tag);
232
- class ORPCTaggedErrorBase extends Data.TaggedError(tag) {
233
- status;
234
- defined;
235
- data;
236
- code = code;
237
- schema = props?.schema;
238
- [ORPCErrorSymbol];
239
- constructor(...rest) {
240
- super();
241
- const opts = resolveMaybeOptionalOptions(rest);
242
- const status = opts.status ?? props?.status;
243
- if (status !== void 0 && !isORPCErrorStatus(status)) {
244
- throw new globalThis.Error(
245
- "[ORPCTaggedError] Invalid error status code."
246
- );
247
- }
248
- this.status = fallbackORPCErrorStatus(code, status);
249
- this.defined = opts.defined ?? true;
250
- this.data = opts.data;
251
- this.message = fallbackORPCErrorMessage(
252
- this.code,
253
- opts.message ?? props?.message
572
+ for (const key of virtualKeys) {
573
+ keys.add(key);
574
+ }
575
+ return [...keys];
576
+ },
577
+ getOwnPropertyDescriptor(currentTarget, prop) {
578
+ const context = createNodeProxyContext(
579
+ currentTarget
254
580
  );
255
- this.cause = opts.cause;
256
- this[ORPCErrorSymbol] = new ORPCError(
257
- this.code,
258
- {
259
- status: this.status,
260
- message: this.message,
261
- data: this.data,
262
- defined: this.defined,
263
- cause: this.cause
581
+ if (virtualKeys.has(prop)) {
582
+ const value = config.getVirtual?.(context, prop, currentTarget);
583
+ if (value !== void 0 && value !== unhandledProperty) {
584
+ return {
585
+ configurable: true,
586
+ enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
587
+ value,
588
+ writable: false
589
+ };
264
590
  }
591
+ }
592
+ const descriptor = Reflect.getOwnPropertyDescriptor(
593
+ context.upstream,
594
+ prop
265
595
  );
266
- }
267
- /**
268
- * Converts this error to a plain ORPCError.
269
- * Useful when you need to return from an oRPC handler.
270
- */
271
- toORPCError() {
272
- return this[ORPCErrorSymbol];
273
- }
274
- toJSON() {
275
- return {
276
- _tag: this._tag,
277
- defined: this[ORPCErrorSymbol].defined,
278
- code: this[ORPCErrorSymbol].code,
279
- status: this[ORPCErrorSymbol].status,
280
- message: this[ORPCErrorSymbol].message,
281
- data: this[ORPCErrorSymbol].data
282
- };
283
- }
284
- }
285
- return Object.assign(ORPCTaggedErrorBase, {
286
- _tag: tag,
287
- code
288
- });
289
- }
290
- function toORPCError(error) {
291
- return error[ORPCErrorSymbol];
292
- }
293
- function createEffectErrorConstructorMap(errors) {
294
- const target = errors ?? {};
295
- const proxy = new Proxy(target, {
296
- get(proxyTarget, code) {
297
- if (typeof code !== "string") {
298
- return Reflect.get(proxyTarget, code);
596
+ if (descriptor === void 0) {
597
+ return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
299
598
  }
300
- const config = target[code];
301
- if (isORPCTaggedErrorClass(config)) {
302
- return (...opts) => new config(...opts);
599
+ if ("value" in descriptor && typeof descriptor.value === "function") {
600
+ return {
601
+ ...descriptor,
602
+ value: createBoundMethod(
603
+ context,
604
+ prop,
605
+ descriptor.value,
606
+ config,
607
+ currentTarget
608
+ )
609
+ };
303
610
  }
304
- return (...rest) => {
305
- const options = resolveMaybeOptionalOptions(rest);
306
- return new ORPCError(code, {
307
- defined: Boolean(config),
308
- status: config?.status,
309
- message: options.message ?? config?.message,
310
- data: options.data,
311
- cause: options.cause
312
- });
313
- };
611
+ return descriptor;
314
612
  }
315
613
  });
316
- return proxy;
317
614
  }
318
- function effectErrorMapToErrorMap(errorMap) {
319
- const result = {};
320
- if (!errorMap) {
321
- return result;
322
- }
323
- for (const [code, ClassOrErrorItem] of Object.entries(errorMap)) {
324
- if (!ClassOrErrorItem) {
325
- continue;
326
- }
327
- if (isORPCTaggedErrorClass(ClassOrErrorItem)) {
328
- const classInstance = new ClassOrErrorItem();
329
- result[classInstance.code] = {
330
- status: classInstance.status,
331
- message: classInstance.message,
332
- data: classInstance.schema
333
- };
334
- } else {
335
- result[code] = ClassOrErrorItem;
336
- }
337
- }
338
- return result;
615
+ function unhandled() {
616
+ return unhandledProperty;
339
617
  }
340
618
 
341
619
  // src/effect-procedure.ts
@@ -345,6 +623,8 @@ var procedureVirtualDescriptors = {
345
623
  callable: { enumerable: false },
346
624
  errors: { enumerable: false },
347
625
  meta: { enumerable: false },
626
+ provide: { enumerable: false },
627
+ provideOptional: { enumerable: false },
348
628
  route: { enumerable: false },
349
629
  use: { enumerable: false }
350
630
  };
@@ -353,6 +633,8 @@ var decoratedProcedureVirtualKeys = [
353
633
  ...baseProcedureVirtualKeys,
354
634
  "errors",
355
635
  "meta",
636
+ "provide",
637
+ "provideOptional",
356
638
  "route",
357
639
  "use",
358
640
  "callable",
@@ -370,10 +652,52 @@ function getOrCreateVirtualMethod(context, prop, factory) {
370
652
  function getEffectProcedureDef(context) {
371
653
  return {
372
654
  ...context.upstream["~orpc"],
655
+ effectSteps: context.state.effectSteps,
656
+ effectHandler: context.state.effectHandler,
373
657
  effectErrorMap: context.state.effectErrorMap,
374
- runtime: context.state.runtime
658
+ runner: context.state.runner
659
+ };
660
+ }
661
+ function makeEffectProcedureHandler(def) {
662
+ if (!def.effectHandler) {
663
+ return def.handler;
664
+ }
665
+ return createEffectProcedureHandler({
666
+ defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
667
+ effectErrorMap: def.effectErrorMap,
668
+ effectFn: def.effectHandler.effectFn,
669
+ effectSteps: def.effectSteps,
670
+ runner: def.runner,
671
+ spanConfig: def.effectHandler.spanConfig
672
+ });
673
+ }
674
+ function withRebuiltEffectHandler(def) {
675
+ return {
676
+ ...def,
677
+ handler: makeEffectProcedureHandler(def)
375
678
  };
376
679
  }
680
+ function appendEffectStep(def, step) {
681
+ return withRebuiltEffectHandler({
682
+ ...def,
683
+ effectSteps: [...def.effectSteps ?? [], step]
684
+ });
685
+ }
686
+ function flushEffectSteps(def) {
687
+ if (!def.effectSteps?.length) {
688
+ return def;
689
+ }
690
+ const middleware = createEffectPipelineMiddleware({
691
+ effectErrorMap: def.effectErrorMap,
692
+ runner: def.runner,
693
+ steps: def.effectSteps
694
+ });
695
+ return withRebuiltEffectHandler({
696
+ ...def,
697
+ effectSteps: void 0,
698
+ middlewares: addMiddleware(def.middlewares, middleware)
699
+ });
700
+ }
377
701
  function createEffectProcedureProxy(target, decorated) {
378
702
  return createNodeProxy(target, {
379
703
  getVirtual(context, prop, receiver) {
@@ -413,16 +737,99 @@ function createEffectProcedureProxy(target, decorated) {
413
737
  route: mergeRoute(getEffectProcedureDef(context).route, route)
414
738
  });
415
739
  });
740
+ case "provide":
741
+ return getOrCreateVirtualMethod(context, prop, () => {
742
+ return (tagOrLayer, provider) => {
743
+ const def = getEffectProcedureDef(context);
744
+ if (Layer.isLayer(tagOrLayer)) {
745
+ const step = {
746
+ _tag: "provideLayer",
747
+ layer: tagOrLayer
748
+ };
749
+ if (def.effectHandler) {
750
+ return new EffectDecoratedProcedure(
751
+ appendEffectStep(def, step)
752
+ );
753
+ }
754
+ return new EffectDecoratedProcedure({
755
+ ...def,
756
+ middlewares: addMiddleware(
757
+ def.middlewares,
758
+ createEffectPipelineMiddleware({
759
+ effectErrorMap: state.effectErrorMap,
760
+ runner: state.runner,
761
+ steps: [step]
762
+ })
763
+ )
764
+ });
765
+ }
766
+ if (def.effectHandler) {
767
+ return new EffectDecoratedProcedure(
768
+ appendEffectStep(def, {
769
+ _tag: "provide",
770
+ provider,
771
+ tag: tagOrLayer
772
+ })
773
+ );
774
+ }
775
+ return new EffectDecoratedProcedure({
776
+ ...def,
777
+ middlewares: addMiddleware(
778
+ def.middlewares,
779
+ createEffectProviderMiddleware({
780
+ effectErrorMap: state.effectErrorMap,
781
+ provider,
782
+ runner: state.runner,
783
+ tag: tagOrLayer
784
+ })
785
+ )
786
+ });
787
+ };
788
+ });
789
+ case "provideOptional":
790
+ return getOrCreateVirtualMethod(context, prop, () => {
791
+ return (tag, provider) => {
792
+ const def = getEffectProcedureDef(context);
793
+ if (def.effectHandler) {
794
+ return new EffectDecoratedProcedure(
795
+ appendEffectStep(def, {
796
+ _tag: "provideOptional",
797
+ provider,
798
+ tag
799
+ })
800
+ );
801
+ }
802
+ return new EffectDecoratedProcedure({
803
+ ...def,
804
+ middlewares: addMiddleware(
805
+ def.middlewares,
806
+ createEffectOptionalProviderMiddleware({
807
+ effectErrorMap: state.effectErrorMap,
808
+ provider,
809
+ runner: state.runner,
810
+ tag
811
+ })
812
+ )
813
+ });
814
+ };
815
+ });
416
816
  case "use":
417
817
  return getOrCreateVirtualMethod(context, prop, () => {
418
818
  return (middleware, mapInput) => {
819
+ const def = getEffectProcedureDef(context);
820
+ if (!mapInput && isEffectMiddleware(middleware)) {
821
+ return new EffectDecoratedProcedure(
822
+ appendEffectStep(def, {
823
+ _tag: "middleware",
824
+ middleware
825
+ })
826
+ );
827
+ }
828
+ const flushedDef = flushEffectSteps(def);
419
829
  const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
420
830
  return new EffectDecoratedProcedure({
421
- ...getEffectProcedureDef(context),
422
- middlewares: addMiddleware(
423
- getEffectProcedureDef(context).middlewares,
424
- mapped
425
- )
831
+ ...flushedDef,
832
+ middlewares: addMiddleware(flushedDef.middlewares, mapped)
426
833
  });
427
834
  };
428
835
  });
@@ -459,10 +866,13 @@ function createEffectProcedureProxy(target, decorated) {
459
866
  }
460
867
  var EffectProcedure = class _EffectProcedure extends Procedure {
461
868
  constructor(def, procedure) {
462
- super(def);
463
- attachEffectState(this, procedure ?? new Procedure(def), {
869
+ const { effectSteps, effectHandler, ...procedureDef } = def;
870
+ super(procedureDef);
871
+ attachEffectState(this, procedure ?? new Procedure(procedureDef), {
872
+ effectSteps,
873
+ effectHandler,
464
874
  effectErrorMap: def.effectErrorMap,
465
- runtime: def.runtime
875
+ runner: def.runner
466
876
  });
467
877
  if (new.target === _EffectProcedure) {
468
878
  return createEffectProcedureProxy(this, false);
@@ -517,7 +927,7 @@ function enhanceEffectRouter(router, options) {
517
927
  middlewares,
518
928
  inputValidationIndex: source["~orpc"].inputValidationIndex + newMiddlewareAdded,
519
929
  outputValidationIndex: source["~orpc"].outputValidationIndex + newMiddlewareAdded,
520
- runtime: options.runtime
930
+ runner: options.runner
521
931
  });
522
932
  }
523
933
  const enhanced = {};
@@ -527,85 +937,44 @@ function enhanceEffectRouter(router, options) {
527
937
  return enhanced;
528
938
  }
529
939
 
530
- // src/effect-runtime.ts
531
- import { ORPCError as ORPCError2 } from "@orpc/contract";
532
- import { Cause as Cause2, Effect, Exit, FiberRefs } from "effect";
533
- function toORPCErrorFromCause(cause) {
534
- return Cause2.match(cause, {
535
- onDie(defect) {
536
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
537
- cause: defect
538
- });
539
- },
540
- onFail(error) {
541
- if (isORPCTaggedError(error)) {
542
- return error.toORPCError();
543
- }
544
- if (error instanceof ORPCError2) {
545
- return error;
546
- }
547
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
548
- cause: error
549
- });
550
- },
551
- onInterrupt(fiberId) {
552
- return new ORPCError2("INTERNAL_SERVER_ERROR", {
553
- cause: new Error(`${fiberId} Interrupted`)
554
- });
555
- },
556
- onSequential(left) {
557
- return left;
558
- },
559
- onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
560
- cause: new Error("Unknown error")
561
- }),
562
- onParallel(left) {
563
- return left;
564
- }
565
- });
566
- }
567
- function createEffectProcedureHandler(options) {
568
- const {
569
- runtime,
570
- effectErrorMap,
571
- effectFn,
572
- spanConfig,
573
- defaultCaptureStackTrace
574
- } = options;
575
- return async (opts) => {
576
- const effectOpts = {
577
- context: opts.context,
578
- input: opts.input,
579
- path: opts.path,
580
- procedure: opts.procedure,
581
- signal: opts.signal,
582
- lastEventId: opts.lastEventId,
583
- errors: createEffectErrorConstructorMap(effectErrorMap)
940
+ // src/runtime-source.ts
941
+ import { Effect as Effect2, FiberRefs, ManagedRuntime } from "effect";
942
+ function makeEffectRuntimeRunner(source) {
943
+ if (source === void 0) {
944
+ return {
945
+ runPromiseExit: (effect, options) => Effect2.runPromiseExit(withParentFiberRefs(effect), {
946
+ signal: options?.signal
947
+ })
584
948
  };
585
- const spanName = spanConfig?.name ?? opts.path.join(".");
586
- const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
587
- const resolver = Effect.fnUntraced(effectFn);
588
- const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
589
- captureStackTrace
590
- });
591
- const parentFiberRefs = getCurrentFiberRefs();
592
- const effectWithRefs = parentFiberRefs ? Effect.fiberIdWith(
593
- (fiberId) => Effect.flatMap(
594
- Effect.getFiberRefs,
595
- (fiberRefs) => Effect.setFiberRefs(
596
- FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
597
- ).pipe(Effect.andThen(tracedEffect))
598
- )
599
- ) : tracedEffect;
600
- const exit = await runtime.runPromiseExit(effectWithRefs, {
601
- signal: opts.signal
602
- });
603
- if (Exit.isFailure(exit)) {
604
- throw toORPCErrorFromCause(exit.cause);
605
- }
606
- return exit.value;
949
+ }
950
+ if (ManagedRuntime.isManagedRuntime(source)) {
951
+ const runtime = source;
952
+ return {
953
+ runtime,
954
+ runPromiseExit: (effect, options) => runtime.runPromiseExit(withParentFiberRefs(effect), {
955
+ signal: options?.signal
956
+ })
957
+ };
958
+ }
959
+ const layer = source;
960
+ return {
961
+ runPromiseExit: (effect, options) => Effect2.runPromiseExit(
962
+ withParentFiberRefs(Effect2.provide(effect, layer)),
963
+ { signal: options?.signal }
964
+ )
607
965
  };
608
966
  }
967
+ function withParentFiberRefs(effect) {
968
+ const parentFiberRefs = getCurrentFiberRefs();
969
+ return parentFiberRefs ? Effect2.fiberIdWith(
970
+ (fiberId) => Effect2.flatMap(
971
+ Effect2.getFiberRefs,
972
+ (fiberRefs) => Effect2.setFiberRefs(
973
+ FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
974
+ ).pipe(Effect2.andThen(effect))
975
+ )
976
+ ) : effect;
977
+ }
609
978
 
610
979
  // src/effect-builder.ts
611
980
  var builderVirtualDescriptors = {
@@ -614,6 +983,9 @@ var builderVirtualDescriptors = {
614
983
  errors: { enumerable: false },
615
984
  handler: { enumerable: false },
616
985
  lazy: { enumerable: false },
986
+ middleware: { enumerable: false },
987
+ provide: { enumerable: false },
988
+ provideOptional: { enumerable: false },
617
989
  router: { enumerable: false },
618
990
  traced: { enumerable: false }
619
991
  };
@@ -621,6 +993,9 @@ var builderVirtualKeys = [
621
993
  "~effect",
622
994
  "errors",
623
995
  "effect",
996
+ "middleware",
997
+ "provide",
998
+ "provideOptional",
624
999
  "traced",
625
1000
  "handler",
626
1001
  "router",
@@ -642,8 +1017,10 @@ function getEffectBuilderDef(context) {
642
1017
  return {
643
1018
  ...context.upstream["~orpc"],
644
1019
  effectErrorMap: context.state.effectErrorMap,
645
- runtime: context.state.runtime,
646
- spanConfig: context.state.spanConfig
1020
+ runner: context.state.runner,
1021
+ spanConfig: context.state.spanConfig,
1022
+ effectSteps: context.state.effectSteps,
1023
+ effectHandler: context.state.effectHandler
647
1024
  };
648
1025
  }
649
1026
  function wrapBuilderLike(builder, state) {
@@ -651,12 +1028,39 @@ function wrapBuilderLike(builder, state) {
651
1028
  {
652
1029
  ...builder["~orpc"],
653
1030
  effectErrorMap: state.effectErrorMap,
654
- runtime: state.runtime,
655
- spanConfig: state.spanConfig
1031
+ runner: state.runner,
1032
+ spanConfig: state.spanConfig,
1033
+ effectSteps: state.effectSteps,
1034
+ effectHandler: state.effectHandler
656
1035
  },
657
1036
  unwrapEffectUpstream(builder)
658
1037
  );
659
1038
  }
1039
+ function appendEffectStep2(state, step) {
1040
+ return {
1041
+ ...state,
1042
+ effectSteps: [...state.effectSteps ?? [], step]
1043
+ };
1044
+ }
1045
+ function flushEffectSteps2(builder, state) {
1046
+ if (!state.effectSteps?.length) {
1047
+ return { builder, state };
1048
+ }
1049
+ const middleware = createEffectPipelineMiddleware({
1050
+ effectErrorMap: state.effectErrorMap,
1051
+ runner: state.runner,
1052
+ steps: state.effectSteps
1053
+ });
1054
+ return {
1055
+ builder: Reflect.apply(Reflect.get(builder, "use", builder), builder, [
1056
+ middleware
1057
+ ]),
1058
+ state: {
1059
+ ...state,
1060
+ effectSteps: void 0
1061
+ }
1062
+ };
1063
+ }
660
1064
  function createEffectBuilderProxy(target) {
661
1065
  return createNodeProxy(target, {
662
1066
  getVirtual(context, prop) {
@@ -688,20 +1092,98 @@ function createEffectBuilderProxy(target) {
688
1092
  return getOrCreateVirtualMethod2(context, prop, () => {
689
1093
  return (effectFn) => {
690
1094
  const defaultCaptureStackTrace = addSpanStackTrace();
1095
+ const effectHandler = {
1096
+ defaultCaptureStackTrace,
1097
+ effectFn,
1098
+ spanConfig: state.spanConfig
1099
+ };
691
1100
  return new EffectDecoratedProcedure({
692
1101
  ...effectDef,
1102
+ effectHandler,
693
1103
  handler: async (opts) => {
694
1104
  return createEffectProcedureHandler({
695
1105
  defaultCaptureStackTrace,
696
1106
  effectErrorMap: state.effectErrorMap,
697
1107
  effectFn,
698
- runtime: state.runtime,
1108
+ effectSteps: state.effectSteps,
1109
+ runner: state.runner,
699
1110
  spanConfig: state.spanConfig
700
1111
  })(opts);
701
1112
  }
702
1113
  });
703
1114
  };
704
1115
  });
1116
+ case "middleware":
1117
+ return getOrCreateVirtualMethod2(context, prop, () => {
1118
+ return (middleware) => {
1119
+ if (isEffectMiddleware(middleware)) {
1120
+ const effectMiddleware = createEffectPipelineMiddleware({
1121
+ effectErrorMap: state.effectErrorMap,
1122
+ runner: state.runner,
1123
+ steps: [
1124
+ ...state.effectSteps ?? [],
1125
+ { _tag: "middleware", middleware }
1126
+ ]
1127
+ });
1128
+ return Reflect.apply(
1129
+ Reflect.get(source, "middleware", source),
1130
+ source,
1131
+ [effectMiddleware]
1132
+ );
1133
+ }
1134
+ return Reflect.apply(
1135
+ Reflect.get(source, "middleware", source),
1136
+ source,
1137
+ [middleware]
1138
+ );
1139
+ };
1140
+ });
1141
+ case "provide":
1142
+ return getOrCreateVirtualMethod2(context, prop, () => {
1143
+ return (tagOrLayer, provider) => {
1144
+ return wrapBuilderLike(
1145
+ source,
1146
+ appendEffectStep2(
1147
+ state,
1148
+ Layer3.isLayer(tagOrLayer) ? { _tag: "provideLayer", layer: tagOrLayer } : { _tag: "provide", provider, tag: tagOrLayer }
1149
+ )
1150
+ );
1151
+ };
1152
+ });
1153
+ case "provideOptional":
1154
+ return getOrCreateVirtualMethod2(context, prop, () => {
1155
+ return (tag, provider) => {
1156
+ return wrapBuilderLike(
1157
+ source,
1158
+ appendEffectStep2(state, {
1159
+ _tag: "provideOptional",
1160
+ provider,
1161
+ tag
1162
+ })
1163
+ );
1164
+ };
1165
+ });
1166
+ case "use":
1167
+ return getOrCreateVirtualMethod2(context, prop, () => {
1168
+ return (middleware, ...rest) => {
1169
+ if (isEffectMiddleware(middleware) && rest.length === 0) {
1170
+ return wrapBuilderLike(
1171
+ source,
1172
+ appendEffectStep2(state, {
1173
+ _tag: "middleware",
1174
+ middleware
1175
+ })
1176
+ );
1177
+ }
1178
+ const flushed = flushEffectSteps2(source, state);
1179
+ const nextBuilder = Reflect.apply(
1180
+ Reflect.get(flushed.builder, "use", flushed.builder),
1181
+ flushed.builder,
1182
+ [middleware, ...rest]
1183
+ );
1184
+ return wrapBuilderLike(nextBuilder, flushed.state);
1185
+ };
1186
+ });
705
1187
  case "traced":
706
1188
  return getOrCreateVirtualMethod2(context, prop, () => {
707
1189
  return (spanName) => wrapBuilderLike(source, {
@@ -763,24 +1245,28 @@ function addSpanStackTrace() {
763
1245
  }
764
1246
  var EffectBuilder = class {
765
1247
  constructor(def, builder) {
766
- const { runtime, spanConfig, effectErrorMap, ...orpcDef } = def;
1248
+ const { runner, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
767
1249
  attachEffectState(this, builder ?? new Builder(orpcDef), {
1250
+ effectSteps,
1251
+ effectHandler: def.effectHandler,
768
1252
  effectErrorMap,
769
- runtime,
1253
+ runner,
770
1254
  spanConfig
771
1255
  });
772
1256
  return createEffectBuilderProxy(this);
773
1257
  }
774
1258
  };
775
- function makeEffectORPC(runtime, builder) {
776
- const resolvedBuilder = builder ?? emptyBuilder();
1259
+ function makeEffectORPC(source, builder) {
1260
+ const sourceIsBuilder = source !== void 0 && isBuilderLike(source);
1261
+ const resolvedBuilder = sourceIsBuilder ? source : builder ?? emptyBuilder();
777
1262
  const effectErrorMap = getEffectErrorMap(resolvedBuilder);
1263
+ const runner = sourceIsBuilder || source === void 0 ? makeEffectRuntimeRunner() : makeEffectRuntimeRunner(source);
778
1264
  return new EffectBuilder(
779
1265
  {
780
1266
  ...resolvedBuilder["~orpc"],
781
1267
  effectErrorMap,
782
1268
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
783
- runtime
1269
+ runner
784
1270
  },
785
1271
  unwrapEffectUpstream(resolvedBuilder)
786
1272
  );
@@ -797,6 +1283,7 @@ function emptyBuilder() {
797
1283
  route: {}
798
1284
  });
799
1285
  }
1286
+ var eos = makeEffectORPC();
800
1287
 
801
1288
  // src/eoc.ts
802
1289
  import { isContractProcedure, oc } from "@orpc/contract";
@@ -935,15 +1422,15 @@ var CONTRACT_HIDDEN_METHODS = /* @__PURE__ */ new Set([
935
1422
  "router",
936
1423
  "tag"
937
1424
  ]);
938
- function makeEnhanceOptions(runtime) {
1425
+ function makeEnhanceOptions(runner) {
939
1426
  return {
940
1427
  middlewares: [],
941
1428
  errorMap: {},
942
1429
  dedupeLeadingMiddlewares: true,
943
- runtime
1430
+ runner
944
1431
  };
945
1432
  }
946
- function wrapContractNode(contract, target, runtime) {
1433
+ function wrapContractNode(contract, target, runner) {
947
1434
  const cache = /* @__PURE__ */ new Map();
948
1435
  return new Proxy(target, {
949
1436
  get(currentTarget, prop, receiver) {
@@ -958,9 +1445,9 @@ function wrapContractNode(contract, target, runtime) {
958
1445
  ...currentTarget["~orpc"],
959
1446
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
960
1447
  effectErrorMap,
961
- runtime,
1448
+ runner,
962
1449
  handler: createEffectProcedureHandler({
963
- runtime,
1450
+ runner,
964
1451
  effectErrorMap,
965
1452
  effectFn,
966
1453
  defaultCaptureStackTrace: addSpanStackTrace()
@@ -978,7 +1465,7 @@ function wrapContractNode(contract, target, runtime) {
978
1465
  currentTarget,
979
1466
  args
980
1467
  ),
981
- runtime
1468
+ runner
982
1469
  );
983
1470
  cache.set(prop, use);
984
1471
  return use;
@@ -995,7 +1482,7 @@ function wrapContractNode(contract, target, runtime) {
995
1482
  currentTarget,
996
1483
  args
997
1484
  ),
998
- runtime
1485
+ runner
999
1486
  );
1000
1487
  cache.set(prop, wrappedMethod);
1001
1488
  return wrappedMethod;
@@ -1007,7 +1494,7 @@ function wrapContractNode(contract, target, runtime) {
1007
1494
  currentTarget,
1008
1495
  args
1009
1496
  ),
1010
- makeEnhanceOptions(runtime)
1497
+ makeEnhanceOptions(runner)
1011
1498
  );
1012
1499
  cache.set(prop, wrappedMethod);
1013
1500
  return wrappedMethod;
@@ -1016,7 +1503,7 @@ function wrapContractNode(contract, target, runtime) {
1016
1503
  const child = wrapContractNode(
1017
1504
  contract[prop],
1018
1505
  Reflect.get(currentTarget, prop, receiver),
1019
- runtime
1506
+ runner
1020
1507
  );
1021
1508
  cache.set(prop, child);
1022
1509
  return child;
@@ -1040,11 +1527,11 @@ function wrapContractNode(contract, target, runtime) {
1040
1527
  }
1041
1528
  });
1042
1529
  }
1043
- function implementEffect(contract, runtime) {
1530
+ function implementEffect(contract, source) {
1044
1531
  return wrapContractNode(
1045
1532
  contract,
1046
1533
  implement(contract),
1047
- runtime
1534
+ makeEffectRuntimeRunner(source)
1048
1535
  );
1049
1536
  }
1050
1537
  export {
@@ -1056,6 +1543,7 @@ export {
1056
1543
  createEffectErrorConstructorMap,
1057
1544
  effectErrorMapToErrorMap,
1058
1545
  eoc,
1546
+ eos,
1059
1547
  implementEffect,
1060
1548
  isORPCTaggedError,
1061
1549
  isORPCTaggedErrorClass,