effect-orpc 0.2.2 → 0.3.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,433 @@ 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, FiberRefs, 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
+ runtime,
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 runtime.runPromiseExit(
250
+ withParentFiberRefs(tracedEffect),
251
+ { signal: opts.signal }
252
+ );
253
+ if (Exit.isFailure(exit)) {
254
+ throw toORPCErrorFromCause(exit.cause);
255
+ }
256
+ return exit.value.output;
257
+ };
258
+ }
259
+ function createEffectPipelineMiddleware(options) {
260
+ const { runtime, effectErrorMap, steps } = options;
261
+ return async (opts, input) => {
262
+ const baseOptions = makeEffectOptions(opts, input, effectErrorMap);
263
+ const effect = runEffectPipeline({
264
+ baseOptions,
265
+ effectErrorMap,
266
+ final: (context) => withCurrentFiberContext(
267
+ () => opts.next(
268
+ context === opts.context ? void 0 : { context }
269
+ )
270
+ ),
271
+ input,
272
+ steps
273
+ });
274
+ const exit = await runtime.runPromiseExit(
275
+ withParentFiberRefs(effect),
276
+ { signal: opts.signal }
277
+ );
278
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
279
+ return exit.value;
280
+ };
281
+ }
282
+ function createEffectProviderMiddleware(options) {
283
+ const { runtime, effectErrorMap, tag, provider } = options;
284
+ return async (opts, input) => {
285
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
286
+ const effect = Effect.flatMap(
287
+ provider(effectOpts),
288
+ (service) => Effect.provideService(
289
+ withCurrentFiberContext(() => opts.next()),
290
+ tag,
291
+ service
292
+ )
293
+ );
294
+ const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
295
+ signal: opts.signal
296
+ });
297
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
298
+ return exit.value;
299
+ };
300
+ }
301
+ function createEffectOptionalProviderMiddleware(options) {
302
+ const { runtime, effectErrorMap, tag, provider } = options;
303
+ return async (opts, input) => {
304
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
305
+ const effect = Effect.flatMap(
306
+ provider(effectOpts),
307
+ (service) => Option.match(service, {
308
+ onNone: () => withCurrentFiberContext(() => opts.next()),
309
+ onSome: (value) => Effect.provideService(
310
+ withCurrentFiberContext(() => opts.next()),
311
+ tag,
312
+ value
313
+ )
314
+ })
315
+ );
316
+ const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
317
+ signal: opts.signal
318
+ });
319
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
320
+ return exit.value;
321
+ };
322
+ }
323
+ function isEffectMiddleware(value) {
324
+ return typeof value === "function" && value.constructor?.name === "GeneratorFunction";
325
+ }
326
+ function makeEffectOptions(opts, input, effectErrorMap) {
327
+ return {
328
+ context: opts.context,
329
+ input,
330
+ path: opts.path,
331
+ procedure: opts.procedure,
332
+ signal: opts.signal,
333
+ lastEventId: opts.lastEventId,
334
+ errors: createEffectErrorConstructorMap(effectErrorMap)
335
+ };
336
+ }
337
+ function runEffectPipeline(options) {
338
+ const run = (index, context) => {
339
+ const step = options.steps[index];
340
+ if (!step) return options.final(context);
341
+ const stepOptions = { ...options.baseOptions, context };
342
+ if (step._tag === "provide") {
343
+ return Effect.flatMap(
344
+ step.provider(stepOptions),
345
+ (service) => Effect.provideService(run(index + 1, context), step.tag, service)
346
+ );
347
+ }
348
+ if (step._tag === "provideOptional") {
349
+ return Effect.flatMap(
350
+ step.provider(stepOptions),
351
+ (service) => Option.match(service, {
352
+ onNone: () => run(index + 1, context),
353
+ onSome: (value) => Effect.provideService(run(index + 1, context), step.tag, value)
354
+ })
355
+ );
356
+ }
357
+ if (step._tag === "provideLayer") {
358
+ return Effect.provide(run(index + 1, context), step.layer);
359
+ }
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
+ );
396
+ };
397
+ return run(0, options.baseOptions.context);
398
+ }
399
+ function createMiddlewareNextTracker() {
400
+ let nextInvoked = false;
401
+ let nextResult;
402
+ return {
403
+ get nextInvoked() {
404
+ return nextInvoked;
405
+ },
406
+ get nextResult() {
407
+ return nextResult;
408
+ },
409
+ wrapNext(nextFn) {
410
+ return ((...args) => {
411
+ nextInvoked = true;
412
+ return Effect.map(nextFn(...args), (result) => {
413
+ nextResult = result;
414
+ return result;
415
+ });
416
+ });
417
+ }
418
+ };
419
+ }
420
+ function resolveEffectMiddlewareContinuation(options) {
421
+ const { result, nextInvoked, nextResult, autoNext } = options;
422
+ if (result !== void 0) {
423
+ return Effect.succeed(result);
424
+ }
425
+ if (nextInvoked) {
426
+ if (nextResult === void 0) {
427
+ return Effect.die(
428
+ new Error(
429
+ "Effect middleware invoked next() but did not return its result"
430
+ )
431
+ );
432
+ }
433
+ return Effect.succeed(nextResult);
434
+ }
435
+ return autoNext();
436
+ }
437
+ function makeEffectMiddlewareOutput(output) {
438
+ return (value) => withCurrentFiberContext(() => output(value));
439
+ }
440
+ function withCurrentFiberContext(fn) {
441
+ return Effect.flatMap(
442
+ Effect.getFiberRefs,
443
+ (fiberRefs) => Effect.promise(
444
+ () => runWithFiberRefs(fiberRefs, () => Promise.resolve(fn()))
445
+ )
446
+ );
447
+ }
448
+ function withParentFiberRefs(effect) {
449
+ const parentFiberRefs = getCurrentFiberRefs();
450
+ return parentFiberRefs ? Effect.fiberIdWith(
451
+ (fiberId) => Effect.flatMap(
452
+ Effect.getFiberRefs,
453
+ (fiberRefs) => Effect.setFiberRefs(
454
+ FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
455
+ ).pipe(Effect.andThen(effect))
456
+ )
457
+ ) : effect;
458
+ }
36
459
 
37
460
  // src/extension/compose-surfaces.ts
38
461
  function composeSurfaceProxy(surface, target) {
@@ -98,7 +521,8 @@ function createBoundMethod(context, prop, value, config, receiver) {
98
521
  return cache.get(prop);
99
522
  }
100
523
  const wrapped = (...args) => {
101
- const result = Reflect.apply(value, context.upstream, args);
524
+ const nextArgs = config.wrapArgs?.(context, prop, args, receiver) ?? args;
525
+ const result = Reflect.apply(value, context.upstream, nextArgs);
102
526
  return config.wrapResult?.(context, prop, result, receiver) ?? result;
103
527
  };
104
528
  cache.set(prop, wrapped);
@@ -159,183 +583,50 @@ function createNodeProxy(target, config) {
159
583
  keys.add(key);
160
584
  }
161
585
  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
586
+ keys.add(key);
587
+ }
588
+ return [...keys];
589
+ },
590
+ getOwnPropertyDescriptor(currentTarget, prop) {
591
+ const context = createNodeProxyContext(
592
+ currentTarget
254
593
  );
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
594
+ if (virtualKeys.has(prop)) {
595
+ const value = config.getVirtual?.(context, prop, currentTarget);
596
+ if (value !== void 0 && value !== unhandledProperty) {
597
+ return {
598
+ configurable: true,
599
+ enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
600
+ value,
601
+ writable: false
602
+ };
264
603
  }
604
+ }
605
+ const descriptor = Reflect.getOwnPropertyDescriptor(
606
+ context.upstream,
607
+ prop
265
608
  );
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);
609
+ if (descriptor === void 0) {
610
+ return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
299
611
  }
300
- const config = target[code];
301
- if (isORPCTaggedErrorClass(config)) {
302
- return (...opts) => new config(...opts);
612
+ if ("value" in descriptor && typeof descriptor.value === "function") {
613
+ return {
614
+ ...descriptor,
615
+ value: createBoundMethod(
616
+ context,
617
+ prop,
618
+ descriptor.value,
619
+ config,
620
+ currentTarget
621
+ )
622
+ };
303
623
  }
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
- };
624
+ return descriptor;
314
625
  }
315
626
  });
316
- return proxy;
317
627
  }
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;
628
+ function unhandled() {
629
+ return unhandledProperty;
339
630
  }
340
631
 
341
632
  // src/effect-procedure.ts
@@ -345,6 +636,8 @@ var procedureVirtualDescriptors = {
345
636
  callable: { enumerable: false },
346
637
  errors: { enumerable: false },
347
638
  meta: { enumerable: false },
639
+ provide: { enumerable: false },
640
+ provideOptional: { enumerable: false },
348
641
  route: { enumerable: false },
349
642
  use: { enumerable: false }
350
643
  };
@@ -353,6 +646,8 @@ var decoratedProcedureVirtualKeys = [
353
646
  ...baseProcedureVirtualKeys,
354
647
  "errors",
355
648
  "meta",
649
+ "provide",
650
+ "provideOptional",
356
651
  "route",
357
652
  "use",
358
653
  "callable",
@@ -370,10 +665,52 @@ function getOrCreateVirtualMethod(context, prop, factory) {
370
665
  function getEffectProcedureDef(context) {
371
666
  return {
372
667
  ...context.upstream["~orpc"],
668
+ effectSteps: context.state.effectSteps,
669
+ effectHandler: context.state.effectHandler,
373
670
  effectErrorMap: context.state.effectErrorMap,
374
671
  runtime: context.state.runtime
375
672
  };
376
673
  }
674
+ function makeEffectProcedureHandler(def) {
675
+ if (!def.effectHandler) {
676
+ return def.handler;
677
+ }
678
+ return createEffectProcedureHandler({
679
+ defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
680
+ effectErrorMap: def.effectErrorMap,
681
+ effectFn: def.effectHandler.effectFn,
682
+ effectSteps: def.effectSteps,
683
+ runtime: def.runtime,
684
+ spanConfig: def.effectHandler.spanConfig
685
+ });
686
+ }
687
+ function withRebuiltEffectHandler(def) {
688
+ return {
689
+ ...def,
690
+ handler: makeEffectProcedureHandler(def)
691
+ };
692
+ }
693
+ function appendEffectStep(def, step) {
694
+ return withRebuiltEffectHandler({
695
+ ...def,
696
+ effectSteps: [...def.effectSteps ?? [], step]
697
+ });
698
+ }
699
+ function flushEffectSteps(def) {
700
+ if (!def.effectSteps?.length) {
701
+ return def;
702
+ }
703
+ const middleware = createEffectPipelineMiddleware({
704
+ effectErrorMap: def.effectErrorMap,
705
+ runtime: def.runtime,
706
+ steps: def.effectSteps
707
+ });
708
+ return withRebuiltEffectHandler({
709
+ ...def,
710
+ effectSteps: void 0,
711
+ middlewares: addMiddleware(def.middlewares, middleware)
712
+ });
713
+ }
377
714
  function createEffectProcedureProxy(target, decorated) {
378
715
  return createNodeProxy(target, {
379
716
  getVirtual(context, prop, receiver) {
@@ -413,16 +750,99 @@ function createEffectProcedureProxy(target, decorated) {
413
750
  route: mergeRoute(getEffectProcedureDef(context).route, route)
414
751
  });
415
752
  });
753
+ case "provide":
754
+ return getOrCreateVirtualMethod(context, prop, () => {
755
+ return (tagOrLayer, provider) => {
756
+ const def = getEffectProcedureDef(context);
757
+ if (Layer.isLayer(tagOrLayer)) {
758
+ const step = {
759
+ _tag: "provideLayer",
760
+ layer: tagOrLayer
761
+ };
762
+ if (def.effectHandler) {
763
+ return new EffectDecoratedProcedure(
764
+ appendEffectStep(def, step)
765
+ );
766
+ }
767
+ return new EffectDecoratedProcedure({
768
+ ...def,
769
+ middlewares: addMiddleware(
770
+ def.middlewares,
771
+ createEffectPipelineMiddleware({
772
+ effectErrorMap: state.effectErrorMap,
773
+ runtime: state.runtime,
774
+ steps: [step]
775
+ })
776
+ )
777
+ });
778
+ }
779
+ if (def.effectHandler) {
780
+ return new EffectDecoratedProcedure(
781
+ appendEffectStep(def, {
782
+ _tag: "provide",
783
+ provider,
784
+ tag: tagOrLayer
785
+ })
786
+ );
787
+ }
788
+ return new EffectDecoratedProcedure({
789
+ ...def,
790
+ middlewares: addMiddleware(
791
+ def.middlewares,
792
+ createEffectProviderMiddleware({
793
+ effectErrorMap: state.effectErrorMap,
794
+ provider,
795
+ runtime: state.runtime,
796
+ tag: tagOrLayer
797
+ })
798
+ )
799
+ });
800
+ };
801
+ });
802
+ case "provideOptional":
803
+ return getOrCreateVirtualMethod(context, prop, () => {
804
+ return (tag, provider) => {
805
+ const def = getEffectProcedureDef(context);
806
+ if (def.effectHandler) {
807
+ return new EffectDecoratedProcedure(
808
+ appendEffectStep(def, {
809
+ _tag: "provideOptional",
810
+ provider,
811
+ tag
812
+ })
813
+ );
814
+ }
815
+ return new EffectDecoratedProcedure({
816
+ ...def,
817
+ middlewares: addMiddleware(
818
+ def.middlewares,
819
+ createEffectOptionalProviderMiddleware({
820
+ effectErrorMap: state.effectErrorMap,
821
+ provider,
822
+ runtime: state.runtime,
823
+ tag
824
+ })
825
+ )
826
+ });
827
+ };
828
+ });
416
829
  case "use":
417
830
  return getOrCreateVirtualMethod(context, prop, () => {
418
831
  return (middleware, mapInput) => {
832
+ const def = getEffectProcedureDef(context);
833
+ if (!mapInput && isEffectMiddleware(middleware)) {
834
+ return new EffectDecoratedProcedure(
835
+ appendEffectStep(def, {
836
+ _tag: "middleware",
837
+ middleware
838
+ })
839
+ );
840
+ }
841
+ const flushedDef = flushEffectSteps(def);
419
842
  const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
420
843
  return new EffectDecoratedProcedure({
421
- ...getEffectProcedureDef(context),
422
- middlewares: addMiddleware(
423
- getEffectProcedureDef(context).middlewares,
424
- mapped
425
- )
844
+ ...flushedDef,
845
+ middlewares: addMiddleware(flushedDef.middlewares, mapped)
426
846
  });
427
847
  };
428
848
  });
@@ -459,8 +879,11 @@ function createEffectProcedureProxy(target, decorated) {
459
879
  }
460
880
  var EffectProcedure = class _EffectProcedure extends Procedure {
461
881
  constructor(def, procedure) {
462
- super(def);
463
- attachEffectState(this, procedure ?? new Procedure(def), {
882
+ const { effectSteps, effectHandler, ...procedureDef } = def;
883
+ super(procedureDef);
884
+ attachEffectState(this, procedure ?? new Procedure(procedureDef), {
885
+ effectSteps,
886
+ effectHandler,
464
887
  effectErrorMap: def.effectErrorMap,
465
888
  runtime: def.runtime
466
889
  });
@@ -527,84 +950,12 @@ function enhanceEffectRouter(router, options) {
527
950
  return enhanced;
528
951
  }
529
952
 
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)
584
- };
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;
607
- };
953
+ // src/runtime-source.ts
954
+ import { ManagedRuntime } from "effect";
955
+ function toManagedRuntime(source) {
956
+ return ManagedRuntime.isManagedRuntime(source) ? source : ManagedRuntime.make(
957
+ source
958
+ );
608
959
  }
609
960
 
610
961
  // src/effect-builder.ts
@@ -614,6 +965,9 @@ var builderVirtualDescriptors = {
614
965
  errors: { enumerable: false },
615
966
  handler: { enumerable: false },
616
967
  lazy: { enumerable: false },
968
+ middleware: { enumerable: false },
969
+ provide: { enumerable: false },
970
+ provideOptional: { enumerable: false },
617
971
  router: { enumerable: false },
618
972
  traced: { enumerable: false }
619
973
  };
@@ -621,6 +975,9 @@ var builderVirtualKeys = [
621
975
  "~effect",
622
976
  "errors",
623
977
  "effect",
978
+ "middleware",
979
+ "provide",
980
+ "provideOptional",
624
981
  "traced",
625
982
  "handler",
626
983
  "router",
@@ -643,7 +1000,9 @@ function getEffectBuilderDef(context) {
643
1000
  ...context.upstream["~orpc"],
644
1001
  effectErrorMap: context.state.effectErrorMap,
645
1002
  runtime: context.state.runtime,
646
- spanConfig: context.state.spanConfig
1003
+ spanConfig: context.state.spanConfig,
1004
+ effectSteps: context.state.effectSteps,
1005
+ effectHandler: context.state.effectHandler
647
1006
  };
648
1007
  }
649
1008
  function wrapBuilderLike(builder, state) {
@@ -652,11 +1011,38 @@ function wrapBuilderLike(builder, state) {
652
1011
  ...builder["~orpc"],
653
1012
  effectErrorMap: state.effectErrorMap,
654
1013
  runtime: state.runtime,
655
- spanConfig: state.spanConfig
1014
+ spanConfig: state.spanConfig,
1015
+ effectSteps: state.effectSteps,
1016
+ effectHandler: state.effectHandler
656
1017
  },
657
1018
  unwrapEffectUpstream(builder)
658
1019
  );
659
1020
  }
1021
+ function appendEffectStep2(state, step) {
1022
+ return {
1023
+ ...state,
1024
+ effectSteps: [...state.effectSteps ?? [], step]
1025
+ };
1026
+ }
1027
+ function flushEffectSteps2(builder, state) {
1028
+ if (!state.effectSteps?.length) {
1029
+ return { builder, state };
1030
+ }
1031
+ const middleware = createEffectPipelineMiddleware({
1032
+ effectErrorMap: state.effectErrorMap,
1033
+ runtime: state.runtime,
1034
+ steps: state.effectSteps
1035
+ });
1036
+ return {
1037
+ builder: Reflect.apply(Reflect.get(builder, "use", builder), builder, [
1038
+ middleware
1039
+ ]),
1040
+ state: {
1041
+ ...state,
1042
+ effectSteps: void 0
1043
+ }
1044
+ };
1045
+ }
660
1046
  function createEffectBuilderProxy(target) {
661
1047
  return createNodeProxy(target, {
662
1048
  getVirtual(context, prop) {
@@ -688,13 +1074,20 @@ function createEffectBuilderProxy(target) {
688
1074
  return getOrCreateVirtualMethod2(context, prop, () => {
689
1075
  return (effectFn) => {
690
1076
  const defaultCaptureStackTrace = addSpanStackTrace();
1077
+ const effectHandler = {
1078
+ defaultCaptureStackTrace,
1079
+ effectFn,
1080
+ spanConfig: state.spanConfig
1081
+ };
691
1082
  return new EffectDecoratedProcedure({
692
1083
  ...effectDef,
1084
+ effectHandler,
693
1085
  handler: async (opts) => {
694
1086
  return createEffectProcedureHandler({
695
1087
  defaultCaptureStackTrace,
696
1088
  effectErrorMap: state.effectErrorMap,
697
1089
  effectFn,
1090
+ effectSteps: state.effectSteps,
698
1091
  runtime: state.runtime,
699
1092
  spanConfig: state.spanConfig
700
1093
  })(opts);
@@ -702,6 +1095,77 @@ function createEffectBuilderProxy(target) {
702
1095
  });
703
1096
  };
704
1097
  });
1098
+ case "middleware":
1099
+ return getOrCreateVirtualMethod2(context, prop, () => {
1100
+ 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
+ }
1116
+ return Reflect.apply(
1117
+ Reflect.get(source, "middleware", source),
1118
+ source,
1119
+ [middleware]
1120
+ );
1121
+ };
1122
+ });
1123
+ case "provide":
1124
+ return getOrCreateVirtualMethod2(context, prop, () => {
1125
+ return (tagOrLayer, provider) => {
1126
+ return wrapBuilderLike(
1127
+ source,
1128
+ appendEffectStep2(
1129
+ state,
1130
+ Layer3.isLayer(tagOrLayer) ? { _tag: "provideLayer", layer: tagOrLayer } : { _tag: "provide", provider, tag: tagOrLayer }
1131
+ )
1132
+ );
1133
+ };
1134
+ });
1135
+ case "provideOptional":
1136
+ return getOrCreateVirtualMethod2(context, prop, () => {
1137
+ return (tag, provider) => {
1138
+ return wrapBuilderLike(
1139
+ source,
1140
+ appendEffectStep2(state, {
1141
+ _tag: "provideOptional",
1142
+ provider,
1143
+ tag
1144
+ })
1145
+ );
1146
+ };
1147
+ });
1148
+ case "use":
1149
+ return getOrCreateVirtualMethod2(context, prop, () => {
1150
+ return (middleware, ...rest) => {
1151
+ if (isEffectMiddleware(middleware) && rest.length === 0) {
1152
+ return wrapBuilderLike(
1153
+ source,
1154
+ appendEffectStep2(state, {
1155
+ _tag: "middleware",
1156
+ middleware
1157
+ })
1158
+ );
1159
+ }
1160
+ const flushed = flushEffectSteps2(source, state);
1161
+ const nextBuilder = Reflect.apply(
1162
+ Reflect.get(flushed.builder, "use", flushed.builder),
1163
+ flushed.builder,
1164
+ [middleware, ...rest]
1165
+ );
1166
+ return wrapBuilderLike(nextBuilder, flushed.state);
1167
+ };
1168
+ });
705
1169
  case "traced":
706
1170
  return getOrCreateVirtualMethod2(context, prop, () => {
707
1171
  return (spanName) => wrapBuilderLike(source, {
@@ -763,8 +1227,10 @@ function addSpanStackTrace() {
763
1227
  }
764
1228
  var EffectBuilder = class {
765
1229
  constructor(def, builder) {
766
- const { runtime, spanConfig, effectErrorMap, ...orpcDef } = def;
1230
+ const { runtime, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
767
1231
  attachEffectState(this, builder ?? new Builder(orpcDef), {
1232
+ effectSteps,
1233
+ effectHandler: def.effectHandler,
768
1234
  effectErrorMap,
769
1235
  runtime,
770
1236
  spanConfig
@@ -772,9 +1238,13 @@ var EffectBuilder = class {
772
1238
  return createEffectBuilderProxy(this);
773
1239
  }
774
1240
  };
775
- function makeEffectORPC(runtime, builder) {
776
- const resolvedBuilder = builder ?? emptyBuilder();
1241
+ function makeEffectORPC(source, builder) {
1242
+ const sourceIsBuilder = source !== void 0 && isBuilderLike(source);
1243
+ const resolvedBuilder = sourceIsBuilder ? source : builder ?? emptyBuilder();
777
1244
  const effectErrorMap = getEffectErrorMap(resolvedBuilder);
1245
+ const runtime = toManagedRuntime(
1246
+ sourceIsBuilder || source === void 0 ? Layer3.empty : source
1247
+ );
778
1248
  return new EffectBuilder(
779
1249
  {
780
1250
  ...resolvedBuilder["~orpc"],
@@ -1040,11 +1510,11 @@ function wrapContractNode(contract, target, runtime) {
1040
1510
  }
1041
1511
  });
1042
1512
  }
1043
- function implementEffect(contract, runtime) {
1513
+ function implementEffect(contract, source) {
1044
1514
  return wrapContractNode(
1045
1515
  contract,
1046
1516
  implement(contract),
1047
- runtime
1517
+ toManagedRuntime(source)
1048
1518
  );
1049
1519
  }
1050
1520
  export {