effect-orpc 1.0.0-effect-v4.4 → 1.0.0-effect-v4.6

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,20 +1,15 @@
1
1
  import {
2
- getCurrentServices
3
- } from "./chunk-I5EWBI42.js";
2
+ getCurrentServices,
3
+ runWithServices
4
+ } from "./chunk-SXPXGZUW.js";
4
5
 
5
6
  // src/contract.ts
6
7
  import { isContractProcedure as isContractProcedure2 } from "@orpc/contract";
7
8
  import { implement } from "@orpc/server";
8
9
 
9
10
  // src/effect-builder.ts
10
- import { mergeMeta as mergeMeta2, mergePrefix as mergePrefix2, mergeRoute as mergeRoute2, mergeTags } from "@orpc/contract";
11
- import {
12
- addMiddleware as addMiddleware2,
13
- Builder,
14
- decorateMiddleware as decorateMiddleware2,
15
- fallbackConfig,
16
- lazy as lazy2
17
- } from "@orpc/server";
11
+ import { Builder, fallbackConfig, lazy as lazy2 } from "@orpc/server";
12
+ import { Layer as Layer3 } from "effect";
18
13
 
19
14
  // src/effect-enhance-router.ts
20
15
  import {
@@ -34,12 +29,17 @@ import {
34
29
  // src/effect-procedure.ts
35
30
  import { mergeMeta, mergeRoute } from "@orpc/contract";
36
31
  import {
32
+ Procedure,
37
33
  addMiddleware,
38
34
  createActionableClient,
39
35
  createProcedureClient,
40
- decorateMiddleware,
41
- Procedure
36
+ decorateMiddleware
42
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, Result } from "effect";
43
43
 
44
44
  // src/tagged-error.ts
45
45
  import {
@@ -174,155 +174,7 @@ function effectErrorMapToErrorMap(errorMap) {
174
174
  return result;
175
175
  }
176
176
 
177
- // src/effect-procedure.ts
178
- var EffectProcedure = class extends Procedure {
179
- constructor(def) {
180
- super(def);
181
- this["~effect"] = def;
182
- }
183
- };
184
- var EffectDecoratedProcedure = class _EffectDecoratedProcedure extends EffectProcedure {
185
- constructor(def) {
186
- super(def);
187
- this["~effect"] = def;
188
- }
189
- /**
190
- * Adds type-safe custom errors.
191
- * Supports both traditional oRPC error definitions and ORPCTaggedError classes.
192
- *
193
- * @see {@link https://orpc.dev/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
194
- */
195
- errors(errors) {
196
- const newEffectErrorMap = {
197
- ...this["~effect"].effectErrorMap,
198
- ...errors
199
- };
200
- return new _EffectDecoratedProcedure({
201
- ...this["~effect"],
202
- effectErrorMap: newEffectErrorMap,
203
- errorMap: effectErrorMapToErrorMap(newEffectErrorMap)
204
- });
205
- }
206
- /**
207
- * Sets or updates the metadata.
208
- * The provided metadata is spared-merged with any existing metadata.
209
- *
210
- * @see {@link https://orpc.dev/docs/metadata Metadata Docs}
211
- */
212
- meta(meta) {
213
- return new _EffectDecoratedProcedure({
214
- ...this["~effect"],
215
- meta: mergeMeta(this["~effect"].meta, meta)
216
- });
217
- }
218
- /**
219
- * Sets or updates the route definition.
220
- * The provided route is spared-merged with any existing route.
221
- * This option is typically relevant when integrating with OpenAPI.
222
- *
223
- * @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
224
- * @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
225
- */
226
- route(route) {
227
- return new _EffectDecoratedProcedure({
228
- ...this["~effect"],
229
- route: mergeRoute(this["~effect"].route, route)
230
- });
231
- }
232
- use(middleware, mapInput) {
233
- const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
234
- return new _EffectDecoratedProcedure({
235
- ...this["~effect"],
236
- middlewares: addMiddleware(this["~effect"].middlewares, mapped)
237
- });
238
- }
239
- /**
240
- * Make this procedure callable (works like a function while still being a procedure).
241
- *
242
- * @see {@link https://orpc.dev/docs/client/server-side Server-side Client Docs}
243
- */
244
- callable(...rest) {
245
- const client = createProcedureClient(this, ...rest);
246
- return new Proxy(client, {
247
- get: (target, key) => {
248
- return Reflect.has(this, key) ? Reflect.get(this, key) : Reflect.get(target, key);
249
- },
250
- has: (target, key) => {
251
- return Reflect.has(this, key) || Reflect.has(target, key);
252
- }
253
- });
254
- }
255
- /**
256
- * Make this procedure compatible with server action.
257
- *
258
- * @see {@link https://orpc.dev/docs/server-action Server Action Docs}
259
- */
260
- actionable(...rest) {
261
- const action = createActionableClient(createProcedureClient(this, ...rest));
262
- return new Proxy(action, {
263
- get: (target, key) => {
264
- return Reflect.has(this, key) ? Reflect.get(this, key) : Reflect.get(target, key);
265
- },
266
- has: (target, key) => {
267
- return Reflect.has(this, key) || Reflect.has(target, key);
268
- }
269
- });
270
- }
271
- };
272
-
273
- // src/effect-enhance-router.ts
274
- function enhanceEffectRouter(router, options) {
275
- if (isLazy(router)) {
276
- const laziedMeta = getLazyMeta(router);
277
- const enhancedPrefix = laziedMeta?.prefix ? mergePrefix(options.prefix, laziedMeta?.prefix) : options.prefix;
278
- const enhanced2 = lazy(
279
- async () => {
280
- const { default: unlaziedRouter } = await unlazy(router);
281
- const enhanced3 = enhanceEffectRouter(unlaziedRouter, options);
282
- return unlazy(enhanced3);
283
- },
284
- {
285
- ...laziedMeta,
286
- prefix: enhancedPrefix
287
- }
288
- );
289
- const accessible = createAccessibleLazyRouter(enhanced2);
290
- return accessible;
291
- }
292
- if (isProcedure(router)) {
293
- const newMiddlewares = mergeMiddlewares(
294
- options.middlewares,
295
- router["~orpc"].middlewares,
296
- { dedupeLeading: options.dedupeLeadingMiddlewares }
297
- );
298
- const newMiddlewareAdded = newMiddlewares.length - router["~orpc"].middlewares.length;
299
- const effectErrorMap = {
300
- ...options.errorMap,
301
- ...router["~orpc"].errorMap
302
- };
303
- const errorMap = effectErrorMapToErrorMap(effectErrorMap);
304
- const enhanced2 = new EffectProcedure({
305
- ...router["~orpc"],
306
- route: enhanceRoute(router["~orpc"].route, options),
307
- effectErrorMap,
308
- errorMap,
309
- middlewares: newMiddlewares,
310
- inputValidationIndex: router["~orpc"].inputValidationIndex + newMiddlewareAdded,
311
- outputValidationIndex: router["~orpc"].outputValidationIndex + newMiddlewareAdded,
312
- runtime: options.runtime
313
- });
314
- return enhanced2;
315
- }
316
- const enhanced = {};
317
- for (const key in router) {
318
- enhanced[key] = enhanceEffectRouter(router[key], options);
319
- }
320
- return enhanced;
321
- }
322
-
323
177
  // src/effect-runtime.ts
324
- import { ORPCError as ORPCError2 } from "@orpc/contract";
325
- import { Cause as Cause2, Effect, Exit, Result, Context } from "effect";
326
178
  function toORPCErrorFromCause(cause) {
327
179
  if (Cause2.hasFails(cause)) {
328
180
  const reason = Cause2.findFail(cause);
@@ -366,9 +218,10 @@ function toORPCErrorFromCause(cause) {
366
218
  }
367
219
  function createEffectProcedureHandler(options) {
368
220
  const {
369
- runtime,
221
+ runner,
370
222
  effectErrorMap,
371
223
  effectFn,
224
+ effectSteps = [],
372
225
  spanConfig,
373
226
  defaultCaptureStackTrace
374
227
  } = options;
@@ -385,371 +238,1073 @@ function createEffectProcedureHandler(options) {
385
238
  const spanName = spanConfig?.name ?? opts.path.join(".");
386
239
  const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
387
240
  const resolver = Effect.fnUntraced(effectFn);
388
- const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
389
- captureStackTrace
390
- });
391
- const parentServices = getCurrentServices();
392
- const exit = parentServices ? await Effect.runPromiseExitWith(
393
- Context.merge(await runtime.context(), parentServices)
394
- )(tracedEffect, {
395
- signal: opts.signal
396
- }) : await runtime.runPromiseExit(tracedEffect, {
241
+ const handlerEffect = resolver(effectOpts);
242
+ const tracedEffect = Effect.withSpan(
243
+ runEffectPipeline({
244
+ baseOptions: effectOpts,
245
+ effectErrorMap,
246
+ final: (context) => Effect.map(
247
+ context === effectOpts.context ? handlerEffect : resolver({ ...effectOpts, context }),
248
+ (output) => ({ output, context: {} })
249
+ ),
250
+ input: opts.input,
251
+ steps: effectSteps
252
+ }),
253
+ spanName,
254
+ { captureStackTrace }
255
+ );
256
+ const exit = await runner.runPromiseExit(tracedEffect, {
397
257
  signal: opts.signal
398
258
  });
399
259
  if (Exit.isFailure(exit)) {
400
260
  throw toORPCErrorFromCause(exit.cause);
401
261
  }
402
- return exit.value;
262
+ return exit.value.output;
403
263
  };
404
264
  }
405
-
406
- // src/effect-builder.ts
407
- function addSpanStackTrace() {
408
- const ErrorConstructor = Error;
409
- const limit = ErrorConstructor.stackTraceLimit;
410
- ErrorConstructor.stackTraceLimit = 3;
411
- const traceError = new Error();
412
- ErrorConstructor.stackTraceLimit = limit;
413
- let cache = false;
414
- return () => {
415
- if (cache !== false) {
416
- return cache;
417
- }
418
- if (traceError.stack !== void 0) {
419
- const stack = traceError.stack.split("\n");
420
- if (stack[3] !== void 0) {
421
- cache = stack[3].trim();
422
- return cache;
423
- }
424
- }
265
+ function createEffectPipelineMiddleware(options) {
266
+ const { runner, effectErrorMap, steps } = options;
267
+ return async (opts, input) => {
268
+ const baseOptions = makeEffectOptions(opts, input, effectErrorMap);
269
+ const effect = runEffectPipeline({
270
+ baseOptions,
271
+ effectErrorMap,
272
+ final: (context) => withCurrentServiceContext(
273
+ () => opts.next(
274
+ context === opts.context ? void 0 : { context }
275
+ )
276
+ ),
277
+ input,
278
+ steps
279
+ });
280
+ const exit = await runner.runPromiseExit(effect, {
281
+ signal: opts.signal
282
+ });
283
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
284
+ return exit.value;
425
285
  };
426
286
  }
427
- var EffectBuilder = class _EffectBuilder {
428
- constructor(def) {
429
- const { runtime, spanConfig, effectErrorMap, ...orpcDef } = def;
430
- this["~orpc"] = orpcDef;
431
- this["~effect"] = { runtime, spanConfig, effectErrorMap, ...orpcDef };
432
- }
433
- /**
434
- * Sets or overrides the config.
435
- *
436
- * @see {@link https://orpc.dev/docs/client/server-side#middlewares-order Middlewares Order Docs}
437
- * @see {@link https://orpc.dev/docs/best-practices/dedupe-middleware#configuration Dedupe Middleware Docs}
438
- */
439
- $config(config) {
440
- const inputValidationCount = this["~effect"].inputValidationIndex - fallbackConfig(
441
- "initialInputValidationIndex",
442
- this["~effect"].config.initialInputValidationIndex
287
+ function createEffectProviderMiddleware(options) {
288
+ const { runner, effectErrorMap, tag, provider } = options;
289
+ return async (opts, input) => {
290
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
291
+ const effect = Effect.flatMap(
292
+ provider(effectOpts),
293
+ (service) => Effect.provideService(
294
+ withCurrentServiceContext(() => opts.next()),
295
+ tag,
296
+ service
297
+ )
443
298
  );
444
- const outputValidationCount = this["~effect"].outputValidationIndex - fallbackConfig(
445
- "initialOutputValidationIndex",
446
- this["~effect"].config.initialOutputValidationIndex
299
+ const exit = await runner.runPromiseExit(effect, {
300
+ signal: opts.signal
301
+ });
302
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
303
+ return exit.value;
304
+ };
305
+ }
306
+ function createEffectOptionalProviderMiddleware(options) {
307
+ const { runner, effectErrorMap, tag, provider } = options;
308
+ return async (opts, input) => {
309
+ const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
310
+ const effect = Effect.flatMap(
311
+ provider(effectOpts),
312
+ (service) => Option.match(service, {
313
+ onNone: () => withCurrentServiceContext(() => opts.next()),
314
+ onSome: (value) => Effect.provideService(
315
+ withCurrentServiceContext(() => opts.next()),
316
+ tag,
317
+ value
318
+ )
319
+ })
447
320
  );
448
- return new _EffectBuilder({
449
- ...this["~effect"],
450
- config,
451
- dedupeLeadingMiddlewares: fallbackConfig(
452
- "dedupeLeadingMiddlewares",
453
- config.dedupeLeadingMiddlewares
454
- ),
455
- inputValidationIndex: fallbackConfig(
456
- "initialInputValidationIndex",
457
- config.initialInputValidationIndex
458
- ) + inputValidationCount,
459
- outputValidationIndex: fallbackConfig(
460
- "initialOutputValidationIndex",
461
- config.initialOutputValidationIndex
462
- ) + outputValidationCount
321
+ const exit = await runner.runPromiseExit(effect, {
322
+ signal: opts.signal
463
323
  });
464
- }
465
- /**
466
- * Set or override the initial context.
467
- *
468
- * @see {@link https://orpc.dev/docs/context Context Docs}
469
- */
470
- $context() {
471
- return new _EffectBuilder({
472
- ...this["~effect"],
473
- middlewares: [],
474
- inputValidationIndex: fallbackConfig(
475
- "initialInputValidationIndex",
476
- this["~effect"].config.initialInputValidationIndex
477
- ),
478
- outputValidationIndex: fallbackConfig(
479
- "initialOutputValidationIndex",
480
- this["~effect"].config.initialOutputValidationIndex
324
+ if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
325
+ return exit.value;
326
+ };
327
+ }
328
+ function isEffectMiddleware(value) {
329
+ return typeof value === "function" && value.constructor?.name === "GeneratorFunction";
330
+ }
331
+ function makeEffectOptions(opts, input, effectErrorMap) {
332
+ return {
333
+ context: opts.context,
334
+ input,
335
+ path: opts.path,
336
+ procedure: opts.procedure,
337
+ signal: opts.signal,
338
+ lastEventId: opts.lastEventId,
339
+ errors: createEffectErrorConstructorMap(effectErrorMap)
340
+ };
341
+ }
342
+ function runEffectPipeline(options) {
343
+ const run = (index, context) => {
344
+ const step = options.steps[index];
345
+ if (!step) return options.final(context);
346
+ const stepOptions = { ...options.baseOptions, context };
347
+ if (step._tag === "provide") {
348
+ return Effect.flatMap(
349
+ step.provider(stepOptions),
350
+ (service) => Effect.provideService(run(index + 1, context), step.tag, service)
351
+ );
352
+ }
353
+ if (step._tag === "provideOptional") {
354
+ return Effect.flatMap(
355
+ step.provider(stepOptions),
356
+ (service) => Option.match(service, {
357
+ onNone: () => run(index + 1, context),
358
+ onSome: (value) => Effect.provideService(run(index + 1, context), step.tag, value)
359
+ })
360
+ );
361
+ }
362
+ if (step._tag === "provideLayer") {
363
+ return Effect.provide(run(index + 1, context), step.layer);
364
+ }
365
+ const nextTracker = createMiddlewareNextTracker();
366
+ const effectOptions = {
367
+ context,
368
+ path: stepOptions.path,
369
+ procedure: stepOptions.procedure,
370
+ signal: stepOptions.signal,
371
+ lastEventId: stepOptions.lastEventId,
372
+ errors: createEffectErrorConstructorMap(options.effectErrorMap),
373
+ next: nextTracker.wrapNext(
374
+ (...rest) => {
375
+ const nextContext = rest[0]?.context ?? {};
376
+ return Effect.map(
377
+ run(index + 1, { ...context, ...nextContext }),
378
+ (result) => ({
379
+ output: result.output,
380
+ context: nextContext
381
+ })
382
+ );
383
+ }
481
384
  )
482
- });
385
+ };
386
+ const effectOutput = makeEffectMiddlewareOutput((output) => ({ output, context: {} }));
387
+ const middlewareEffect = Effect.fnUntraced(step.middleware)(
388
+ effectOptions,
389
+ options.input,
390
+ effectOutput
391
+ );
392
+ return Effect.flatMap(
393
+ middlewareEffect,
394
+ (result) => resolveEffectMiddlewareContinuation({
395
+ autoNext: () => effectOptions.next(),
396
+ nextInvoked: nextTracker.nextInvoked,
397
+ nextResult: nextTracker.nextResult,
398
+ result
399
+ })
400
+ );
401
+ };
402
+ return run(0, options.baseOptions.context);
403
+ }
404
+ function createMiddlewareNextTracker() {
405
+ let nextInvoked = false;
406
+ let nextResult;
407
+ return {
408
+ get nextInvoked() {
409
+ return nextInvoked;
410
+ },
411
+ get nextResult() {
412
+ return nextResult;
413
+ },
414
+ wrapNext(nextFn) {
415
+ return ((...args) => {
416
+ nextInvoked = true;
417
+ return Effect.map(nextFn(...args), (result) => {
418
+ nextResult = result;
419
+ return result;
420
+ });
421
+ });
422
+ }
423
+ };
424
+ }
425
+ function resolveEffectMiddlewareContinuation(options) {
426
+ const { result, nextInvoked, nextResult, autoNext } = options;
427
+ if (result !== void 0) {
428
+ return Effect.succeed(result);
483
429
  }
484
- /**
485
- * Sets or overrides the initial meta.
486
- *
487
- * @see {@link https://orpc.dev/docs/metadata Metadata Docs}
488
- */
489
- $meta(initialMeta) {
490
- return new _EffectBuilder({
491
- ...this["~effect"],
492
- meta: initialMeta
493
- });
430
+ if (nextInvoked) {
431
+ if (nextResult === void 0) {
432
+ return Effect.die(
433
+ new Error(
434
+ "Effect middleware invoked next() but did not return its result"
435
+ )
436
+ );
437
+ }
438
+ return Effect.succeed(nextResult);
494
439
  }
495
- /**
496
- * Sets or overrides the initial route.
497
- * This option is typically relevant when integrating with OpenAPI.
498
- *
499
- * @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
500
- * @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
501
- */
502
- $route(initialRoute) {
503
- return new _EffectBuilder({
504
- ...this["~effect"],
505
- route: initialRoute
506
- });
440
+ return autoNext();
441
+ }
442
+ function makeEffectMiddlewareOutput(output) {
443
+ return (value) => withCurrentServiceContext(() => output(value));
444
+ }
445
+ function withCurrentServiceContext(fn) {
446
+ return Effect.flatMap(
447
+ Effect.context(),
448
+ (services) => Effect.promise(
449
+ () => runWithServices(services, () => Promise.resolve(fn()))
450
+ )
451
+ );
452
+ }
453
+
454
+ // src/extension/compose-surfaces.ts
455
+ function composeSurfaceProxy(surface, target) {
456
+ return new Proxy(target, {
457
+ get(currentTarget, prop, receiver) {
458
+ return Reflect.has(surface, prop) ? Reflect.get(surface, prop, surface) : Reflect.get(currentTarget, prop, receiver);
459
+ },
460
+ has(currentTarget, prop) {
461
+ return Reflect.has(surface, prop) || Reflect.has(currentTarget, prop);
462
+ }
463
+ });
464
+ }
465
+
466
+ // src/extension/state.ts
467
+ var effectInternalsSymbol = /* @__PURE__ */ Symbol("effect-orpc/internals");
468
+ function attachEffectState(target, upstream, state) {
469
+ Object.defineProperties(target, {
470
+ [effectInternalsSymbol]: {
471
+ configurable: true,
472
+ value: {
473
+ methodCache: /* @__PURE__ */ new Map(),
474
+ state,
475
+ upstream
476
+ }
477
+ }
478
+ });
479
+ }
480
+ function getEffectInternals(target) {
481
+ return target[effectInternalsSymbol];
482
+ }
483
+ function getEffectUpstream(target) {
484
+ return getEffectInternals(target).upstream;
485
+ }
486
+ function hasEffectState(value) {
487
+ return typeof value === "object" && value !== null && effectInternalsSymbol in value;
488
+ }
489
+ function assertEffectState(value) {
490
+ if (!hasEffectState(value)) {
491
+ throw new Error("Expected effect state to be attached");
507
492
  }
508
- /**
509
- * Sets or overrides the initial input schema.
510
- *
511
- * @see {@link https://orpc.dev/docs/procedure#initial-configuration Initial Procedure Configuration Docs}
512
- */
513
- $input(initialInputSchema) {
514
- return new _EffectBuilder({
515
- ...this["~effect"],
516
- inputSchema: initialInputSchema
517
- });
493
+ }
494
+ function getEffectErrorMap(value) {
495
+ return value["~effect"]?.effectErrorMap ?? value["~orpc"].errorMap;
496
+ }
497
+ function unwrapEffectUpstream(value) {
498
+ return hasEffectState(value) ? getEffectUpstream(value) : value;
499
+ }
500
+
501
+ // src/extension/create-node-proxy.ts
502
+ var unhandledProperty = /* @__PURE__ */ Symbol("effect-orpc/unhandledProperty");
503
+ function createNodeProxyContext(target) {
504
+ const internals = getEffectInternals(target);
505
+ return {
506
+ methodCache: internals.methodCache,
507
+ state: internals.state,
508
+ target,
509
+ upstream: internals.upstream
510
+ };
511
+ }
512
+ function createBoundMethod(context, prop, value, config, receiver) {
513
+ const cache = context.methodCache;
514
+ if (cache.has(prop)) {
515
+ return cache.get(prop);
518
516
  }
519
- /**
520
- * Creates a middleware.
521
- *
522
- * @see {@link https://orpc.dev/docs/middleware Middleware Docs}
523
- */
524
- middleware(middleware) {
525
- return decorateMiddleware2(middleware);
517
+ const wrapped = (...args) => {
518
+ const nextArgs = config.wrapArgs?.(context, prop, args, receiver) ?? args;
519
+ const result = Reflect.apply(value, context.upstream, nextArgs);
520
+ return config.wrapResult?.(context, prop, result, receiver) ?? result;
521
+ };
522
+ cache.set(prop, wrapped);
523
+ return wrapped;
524
+ }
525
+ function createNodeProxy(target, config) {
526
+ const privateKeys = /* @__PURE__ */ new Set([effectInternalsSymbol]);
527
+ const virtualKeys = new Set(config.virtualKeys ?? []);
528
+ return new Proxy(target, {
529
+ get(currentTarget, prop, receiver) {
530
+ if (privateKeys.has(prop)) {
531
+ return Reflect.get(currentTarget, prop, receiver);
532
+ }
533
+ const context = createNodeProxyContext(
534
+ currentTarget
535
+ );
536
+ const virtualValue = config.getVirtual?.(context, prop, receiver);
537
+ if (virtualValue !== void 0 && virtualValue !== unhandledProperty) {
538
+ return virtualValue;
539
+ }
540
+ const propertyValue = config.getProperty?.(context, prop, receiver);
541
+ if (propertyValue !== void 0 && propertyValue !== unhandledProperty) {
542
+ return propertyValue;
543
+ }
544
+ const sourceValue = Reflect.get(context.upstream, prop, context.upstream);
545
+ if (Reflect.has(context.upstream, prop)) {
546
+ if (typeof sourceValue === "function") {
547
+ return createBoundMethod(
548
+ context,
549
+ prop,
550
+ sourceValue,
551
+ config,
552
+ receiver
553
+ );
554
+ }
555
+ return sourceValue;
556
+ }
557
+ return Reflect.get(currentTarget, prop, receiver);
558
+ },
559
+ has(currentTarget, prop) {
560
+ if (virtualKeys.has(prop)) {
561
+ return true;
562
+ }
563
+ const context = createNodeProxyContext(currentTarget);
564
+ return Reflect.has(context.upstream, prop) || Reflect.has(currentTarget, prop);
565
+ },
566
+ ownKeys(currentTarget) {
567
+ const keys = /* @__PURE__ */ new Set();
568
+ for (const key of Reflect.ownKeys(currentTarget)) {
569
+ if (!privateKeys.has(key)) {
570
+ keys.add(key);
571
+ }
572
+ }
573
+ const context = createNodeProxyContext(
574
+ currentTarget
575
+ );
576
+ for (const key of Reflect.ownKeys(context.upstream)) {
577
+ keys.add(key);
578
+ }
579
+ for (const key of virtualKeys) {
580
+ keys.add(key);
581
+ }
582
+ return [...keys];
583
+ },
584
+ getOwnPropertyDescriptor(currentTarget, prop) {
585
+ const context = createNodeProxyContext(
586
+ currentTarget
587
+ );
588
+ if (virtualKeys.has(prop)) {
589
+ const value = config.getVirtual?.(context, prop, currentTarget);
590
+ if (value !== void 0 && value !== unhandledProperty) {
591
+ return {
592
+ configurable: true,
593
+ enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
594
+ value,
595
+ writable: false
596
+ };
597
+ }
598
+ }
599
+ const descriptor = Reflect.getOwnPropertyDescriptor(
600
+ context.upstream,
601
+ prop
602
+ );
603
+ if (descriptor === void 0) {
604
+ return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
605
+ }
606
+ if ("value" in descriptor && typeof descriptor.value === "function") {
607
+ return {
608
+ ...descriptor,
609
+ value: createBoundMethod(
610
+ context,
611
+ prop,
612
+ descriptor.value,
613
+ config,
614
+ currentTarget
615
+ )
616
+ };
617
+ }
618
+ return descriptor;
619
+ }
620
+ });
621
+ }
622
+ function unhandled() {
623
+ return unhandledProperty;
624
+ }
625
+
626
+ // src/effect-procedure.ts
627
+ var procedureVirtualDescriptors = {
628
+ "~effect": { enumerable: true },
629
+ actionable: { enumerable: false },
630
+ callable: { enumerable: false },
631
+ errors: { enumerable: false },
632
+ meta: { enumerable: false },
633
+ provide: { enumerable: false },
634
+ provideOptional: { enumerable: false },
635
+ route: { enumerable: false },
636
+ use: { enumerable: false }
637
+ };
638
+ var baseProcedureVirtualKeys = ["~effect"];
639
+ var decoratedProcedureVirtualKeys = [
640
+ ...baseProcedureVirtualKeys,
641
+ "errors",
642
+ "meta",
643
+ "provide",
644
+ "provideOptional",
645
+ "route",
646
+ "use",
647
+ "callable",
648
+ "actionable"
649
+ ];
650
+ function getOrCreateVirtualMethod(context, prop, factory) {
651
+ const cache = context.methodCache;
652
+ if (cache.has(prop)) {
653
+ return cache.get(prop);
526
654
  }
527
- /**
528
- * Adds type-safe custom errors.
529
- * Supports both traditional oRPC error definitions and ORPCTaggedError classes.
530
- *
531
- * @example
532
- * ```ts
533
- * // Traditional format
534
- * builder.errors({ BAD_REQUEST: { status: 400, message: 'Bad request' } })
535
- *
536
- * // Tagged error class
537
- * builder.errors({ USER_NOT_FOUND: UserNotFoundError })
538
- *
539
- * // Mixed
540
- * builder.errors({
541
- * BAD_REQUEST: { status: 400 },
542
- * USER_NOT_FOUND: UserNotFoundError,
543
- * })
544
- * ```
545
- *
546
- * @see {@link https://orpc.dev/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
547
- */
548
- errors(errors) {
549
- const newEffectErrorMap = {
550
- ...this["~effect"].effectErrorMap,
551
- ...errors
552
- };
553
- return new _EffectBuilder({
554
- ...this["~effect"],
555
- errorMap: effectErrorMapToErrorMap(newEffectErrorMap),
556
- effectErrorMap: newEffectErrorMap
557
- });
655
+ const value = factory();
656
+ cache.set(prop, value);
657
+ return value;
658
+ }
659
+ function getEffectProcedureDef(context) {
660
+ return {
661
+ ...context.upstream["~orpc"],
662
+ effectSteps: context.state.effectSteps,
663
+ effectHandler: context.state.effectHandler,
664
+ effectErrorMap: context.state.effectErrorMap,
665
+ runner: context.state.runner
666
+ };
667
+ }
668
+ function makeEffectProcedureHandler(def) {
669
+ if (!def.effectHandler) {
670
+ return def.handler;
558
671
  }
559
- use(middleware, mapInput) {
560
- const mapped = mapInput ? decorateMiddleware2(middleware).mapInput(mapInput) : middleware;
561
- return new _EffectBuilder({
562
- ...this["~effect"],
563
- middlewares: addMiddleware2(this["~effect"].middlewares, mapped)
564
- });
672
+ return createEffectProcedureHandler({
673
+ defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
674
+ effectErrorMap: def.effectErrorMap,
675
+ effectFn: def.effectHandler.effectFn,
676
+ effectSteps: def.effectSteps,
677
+ runner: def.runner,
678
+ spanConfig: def.effectHandler.spanConfig
679
+ });
680
+ }
681
+ function withRebuiltEffectHandler(def) {
682
+ return {
683
+ ...def,
684
+ handler: makeEffectProcedureHandler(def)
685
+ };
686
+ }
687
+ function appendEffectStep(def, step) {
688
+ return withRebuiltEffectHandler({
689
+ ...def,
690
+ effectSteps: [...def.effectSteps ?? [], step]
691
+ });
692
+ }
693
+ function flushEffectSteps(def) {
694
+ if (!def.effectSteps?.length) {
695
+ return def;
565
696
  }
566
- /**
567
- * Sets or updates the metadata.
568
- * The provided metadata is spared-merged with any existing metadata.
569
- *
570
- * @see {@link https://orpc.dev/docs/metadata Metadata Docs}
571
- */
572
- meta(meta) {
573
- return new _EffectBuilder({
574
- ...this["~effect"],
575
- meta: mergeMeta2(this["~effect"].meta, meta)
697
+ const middleware = createEffectPipelineMiddleware({
698
+ effectErrorMap: def.effectErrorMap,
699
+ runner: def.runner,
700
+ steps: def.effectSteps
701
+ });
702
+ return withRebuiltEffectHandler({
703
+ ...def,
704
+ effectSteps: void 0,
705
+ middlewares: addMiddleware(def.middlewares, middleware)
706
+ });
707
+ }
708
+ function createEffectProcedureProxy(target, decorated) {
709
+ return createNodeProxy(target, {
710
+ getVirtual(context, prop, receiver) {
711
+ if (prop === "~effect") {
712
+ return getEffectProcedureDef(context);
713
+ }
714
+ if (!decorated) {
715
+ return unhandled();
716
+ }
717
+ const state = context.state;
718
+ switch (prop) {
719
+ case "errors":
720
+ return getOrCreateVirtualMethod(context, prop, () => {
721
+ return (errors) => {
722
+ const nextEffectErrorMap = {
723
+ ...state.effectErrorMap,
724
+ ...errors
725
+ };
726
+ return new EffectDecoratedProcedure({
727
+ ...getEffectProcedureDef(context),
728
+ effectErrorMap: nextEffectErrorMap,
729
+ errorMap: effectErrorMapToErrorMap(nextEffectErrorMap)
730
+ });
731
+ };
732
+ });
733
+ case "meta":
734
+ return getOrCreateVirtualMethod(context, prop, () => {
735
+ return (meta) => new EffectDecoratedProcedure({
736
+ ...getEffectProcedureDef(context),
737
+ meta: mergeMeta(getEffectProcedureDef(context).meta, meta)
738
+ });
739
+ });
740
+ case "route":
741
+ return getOrCreateVirtualMethod(context, prop, () => {
742
+ return (route) => new EffectDecoratedProcedure({
743
+ ...getEffectProcedureDef(context),
744
+ route: mergeRoute(getEffectProcedureDef(context).route, route)
745
+ });
746
+ });
747
+ case "provide":
748
+ return getOrCreateVirtualMethod(context, prop, () => {
749
+ return (tagOrLayer, provider) => {
750
+ const def = getEffectProcedureDef(context);
751
+ if (Layer.isLayer(tagOrLayer)) {
752
+ const step = {
753
+ _tag: "provideLayer",
754
+ layer: tagOrLayer
755
+ };
756
+ if (def.effectHandler) {
757
+ return new EffectDecoratedProcedure(
758
+ appendEffectStep(def, step)
759
+ );
760
+ }
761
+ return new EffectDecoratedProcedure({
762
+ ...def,
763
+ middlewares: addMiddleware(
764
+ def.middlewares,
765
+ createEffectPipelineMiddleware({
766
+ effectErrorMap: state.effectErrorMap,
767
+ runner: state.runner,
768
+ steps: [step]
769
+ })
770
+ )
771
+ });
772
+ }
773
+ if (def.effectHandler) {
774
+ return new EffectDecoratedProcedure(
775
+ appendEffectStep(def, {
776
+ _tag: "provide",
777
+ provider,
778
+ tag: tagOrLayer
779
+ })
780
+ );
781
+ }
782
+ return new EffectDecoratedProcedure({
783
+ ...def,
784
+ middlewares: addMiddleware(
785
+ def.middlewares,
786
+ createEffectProviderMiddleware({
787
+ effectErrorMap: state.effectErrorMap,
788
+ provider,
789
+ runner: state.runner,
790
+ tag: tagOrLayer
791
+ })
792
+ )
793
+ });
794
+ };
795
+ });
796
+ case "provideOptional":
797
+ return getOrCreateVirtualMethod(context, prop, () => {
798
+ return (tag, provider) => {
799
+ const def = getEffectProcedureDef(context);
800
+ if (def.effectHandler) {
801
+ return new EffectDecoratedProcedure(
802
+ appendEffectStep(def, {
803
+ _tag: "provideOptional",
804
+ provider,
805
+ tag
806
+ })
807
+ );
808
+ }
809
+ return new EffectDecoratedProcedure({
810
+ ...def,
811
+ middlewares: addMiddleware(
812
+ def.middlewares,
813
+ createEffectOptionalProviderMiddleware({
814
+ effectErrorMap: state.effectErrorMap,
815
+ provider,
816
+ runner: state.runner,
817
+ tag
818
+ })
819
+ )
820
+ });
821
+ };
822
+ });
823
+ case "use":
824
+ return getOrCreateVirtualMethod(context, prop, () => {
825
+ return (middleware, mapInput) => {
826
+ const def = getEffectProcedureDef(context);
827
+ if (!mapInput && isEffectMiddleware(middleware)) {
828
+ return new EffectDecoratedProcedure(
829
+ appendEffectStep(def, {
830
+ _tag: "middleware",
831
+ middleware
832
+ })
833
+ );
834
+ }
835
+ const flushedDef = flushEffectSteps(def);
836
+ const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
837
+ return new EffectDecoratedProcedure({
838
+ ...flushedDef,
839
+ middlewares: addMiddleware(flushedDef.middlewares, mapped)
840
+ });
841
+ };
842
+ });
843
+ case "callable":
844
+ return (...rest) => {
845
+ const client = createProcedureClient(
846
+ receiver,
847
+ ...rest
848
+ );
849
+ return composeSurfaceProxy(
850
+ receiver,
851
+ client
852
+ );
853
+ };
854
+ case "actionable":
855
+ return (...rest) => {
856
+ const client = createProcedureClient(
857
+ receiver,
858
+ ...rest
859
+ );
860
+ const action = createActionableClient(client);
861
+ return composeSurfaceProxy(
862
+ receiver,
863
+ action
864
+ );
865
+ };
866
+ default:
867
+ return unhandled();
868
+ }
869
+ },
870
+ virtualDescriptors: procedureVirtualDescriptors,
871
+ virtualKeys: decorated ? decoratedProcedureVirtualKeys : baseProcedureVirtualKeys
872
+ });
873
+ }
874
+ var EffectProcedure = class _EffectProcedure extends Procedure {
875
+ constructor(def, procedure) {
876
+ const { effectSteps, effectHandler, ...procedureDef } = def;
877
+ super(procedureDef);
878
+ attachEffectState(this, procedure ?? new Procedure(procedureDef), {
879
+ effectSteps,
880
+ effectHandler,
881
+ effectErrorMap: def.effectErrorMap,
882
+ runner: def.runner
576
883
  });
884
+ if (new.target === _EffectProcedure) {
885
+ return createEffectProcedureProxy(this, false);
886
+ }
577
887
  }
578
- /**
579
- * Sets or updates the route definition.
580
- * The provided route is spared-merged with any existing route.
581
- * This option is typically relevant when integrating with OpenAPI.
582
- *
583
- * @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
584
- * @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
585
- */
586
- route(route) {
587
- return new _EffectBuilder({
588
- ...this["~effect"],
589
- route: mergeRoute2(this["~effect"].route, route)
590
- });
888
+ };
889
+ var EffectDecoratedProcedure = class extends EffectProcedure {
890
+ constructor(def, procedure) {
891
+ super(def, procedure);
892
+ assertEffectState(this);
893
+ return createEffectProcedureProxy(this, true);
591
894
  }
592
- /**
593
- * Defines the input validation schema.
594
- *
595
- * @see {@link https://orpc.dev/docs/procedure#input-output-validation Input Validation Docs}
596
- */
597
- input(schema) {
598
- return new _EffectBuilder({
599
- ...this["~effect"],
600
- inputSchema: schema,
601
- inputValidationIndex: fallbackConfig(
602
- "initialInputValidationIndex",
603
- this["~effect"].config.initialInputValidationIndex
604
- ) + this["~effect"].middlewares.length
605
- // we cast to any because EffectProcedureBuilderWithInput is expecting
606
- // use() input type to be defined, and EffectBuilder types its use() input
607
- // to unknown to allow any middleware to be passed
608
- // ---
609
- // note: the original implentation of the builder also uses any for the same reason
610
- });
895
+ };
896
+
897
+ // src/effect-enhance-router.ts
898
+ function enhanceEffectRouter(router, options) {
899
+ if (isLazy(router)) {
900
+ const laziedMeta = getLazyMeta(router);
901
+ const enhancedPrefix = laziedMeta?.prefix ? mergePrefix(options.prefix, laziedMeta.prefix) : options.prefix;
902
+ const enhanced2 = lazy(
903
+ async () => {
904
+ const { default: unlaziedRouter } = await unlazy(router);
905
+ const wrappedRouter = enhanceEffectRouter(unlaziedRouter, options);
906
+ return unlazy(wrappedRouter);
907
+ },
908
+ {
909
+ ...laziedMeta,
910
+ prefix: enhancedPrefix
911
+ }
912
+ );
913
+ return createAccessibleLazyRouter(enhanced2);
611
914
  }
612
- /**
613
- * Defines the output validation schema.
614
- *
615
- * @see {@link https://orpc.dev/docs/procedure#input-output-validation Output Validation Docs}
616
- */
617
- output(schema) {
618
- return new _EffectBuilder({
619
- ...this["~effect"],
620
- outputSchema: schema,
621
- outputValidationIndex: fallbackConfig(
622
- "initialOutputValidationIndex",
623
- this["~effect"].config.initialOutputValidationIndex
624
- ) + this["~effect"].middlewares.length
915
+ if (isProcedure(router)) {
916
+ const source = unwrapEffectUpstream(router);
917
+ const sourceEffectErrorMap = getEffectErrorMap(router);
918
+ const middlewares = mergeMiddlewares(
919
+ options.middlewares,
920
+ source["~orpc"].middlewares,
921
+ { dedupeLeading: options.dedupeLeadingMiddlewares }
922
+ );
923
+ const newMiddlewareAdded = middlewares.length - source["~orpc"].middlewares.length;
924
+ const effectErrorMap = {
925
+ ...options.errorMap,
926
+ ...sourceEffectErrorMap
927
+ };
928
+ const errorMap = effectErrorMapToErrorMap(effectErrorMap);
929
+ return new EffectProcedure({
930
+ ...source["~orpc"],
931
+ route: enhanceRoute(source["~orpc"].route, options),
932
+ effectErrorMap,
933
+ errorMap,
934
+ middlewares,
935
+ inputValidationIndex: source["~orpc"].inputValidationIndex + newMiddlewareAdded,
936
+ outputValidationIndex: source["~orpc"].outputValidationIndex + newMiddlewareAdded,
937
+ runner: options.runner
625
938
  });
626
939
  }
627
- /**
628
- * Adds a traceable span to the procedure for telemetry.
629
- * The span name is used for Effect tracing via `Effect.withSpan`.
630
- * Stack trace is captured at the call site for better error reporting.
631
- *
632
- * @param spanName - The name of the span for telemetry (e.g., 'users.getUser')
633
- * @returns An EffectBuilder with span tracing configured
634
- *
635
- * @example
636
- * ```ts
637
- * const getUser = effectOs
638
- * .input(z.object({ id: z.string() }))
639
- * .traced('users.getUser')
640
- * .effect(function* ({ input }) {
641
- * const userService = yield* UserService
642
- * return yield* userService.findById(input.id)
643
- * })
644
- * ```
645
- */
646
- traced(spanName) {
647
- return new _EffectBuilder({
648
- ...this["~effect"],
649
- spanConfig: {
650
- name: spanName,
651
- captureStackTrace: addSpanStackTrace()
652
- }
653
- });
940
+ const enhanced = {};
941
+ for (const key in router) {
942
+ enhanced[key] = enhanceEffectRouter(router[key], options);
654
943
  }
655
- handler(handler) {
656
- return new EffectDecoratedProcedure({
657
- ...this["~effect"],
658
- handler
659
- });
944
+ return enhanced;
945
+ }
946
+
947
+ // src/runtime-source.ts
948
+ import { Context, Effect as Effect2, Layer as Layer2, ManagedRuntime } from "effect";
949
+ function makeEffectRuntimeRunner(source) {
950
+ if (source === void 0) {
951
+ return {
952
+ runPromiseExit: (effect, options) => runPromiseExitWithCurrentServices(effect, options)
953
+ };
660
954
  }
661
- /**
662
- * Defines the handler of the procedure using an Effect.
663
- * The Effect is executed using the ManagedRuntime provided during builder creation.
664
- * The effect is automatically wrapped with `Effect.withSpan`.
665
- *
666
- * @see {@link https://orpc.dev/docs/procedure Procedure Docs}
667
- */
668
- effect(effectFn) {
669
- const { runtime, spanConfig } = this["~effect"];
670
- const defaultCaptureStackTrace = addSpanStackTrace();
671
- return new EffectDecoratedProcedure({
672
- ...this["~effect"],
673
- handler: async (opts) => {
674
- return createEffectProcedureHandler({
675
- runtime,
676
- effectErrorMap: this["~effect"].effectErrorMap,
677
- effectFn,
678
- spanConfig,
679
- defaultCaptureStackTrace
680
- })(opts);
681
- }
682
- });
955
+ if (ManagedRuntime.isManagedRuntime(source)) {
956
+ const runtime = source;
957
+ return {
958
+ runtime,
959
+ runPromiseExit: (effect, options) => runManagedRuntimePromiseExit(runtime, effect, options)
960
+ };
683
961
  }
684
- /**
685
- * Prefixes all procedures in the router.
686
- * The provided prefix is post-appended to any existing router prefix.
687
- *
688
- * @note This option does not affect procedures that do not define a path in their route definition.
689
- *
690
- * @see {@link https://orpc.dev/docs/openapi/routing#route-prefixes OpenAPI Route Prefixes Docs}
691
- */
692
- prefix(prefix) {
693
- return new _EffectBuilder({
694
- ...this["~effect"],
695
- prefix: mergePrefix2(this["~effect"].prefix, prefix)
696
- });
962
+ const layer = source;
963
+ return {
964
+ runPromiseExit: (effect, options) => Effect2.runPromiseExit(
965
+ provideLayerWithCurrentServices(effect, layer),
966
+ { signal: options?.signal }
967
+ )
968
+ };
969
+ }
970
+ function runPromiseExitWithCurrentServices(effect, options) {
971
+ const parentServices = getCurrentServices();
972
+ return parentServices ? Effect2.runPromiseExitWith(parentServices)(effect, {
973
+ signal: options?.signal
974
+ }) : Effect2.runPromiseExit(effect, {
975
+ signal: options?.signal
976
+ });
977
+ }
978
+ async function runManagedRuntimePromiseExit(runtime, effect, options) {
979
+ const parentServices = getCurrentServices();
980
+ return parentServices ? Effect2.runPromiseExitWith(
981
+ Context.merge(await runtime.context(), parentServices)
982
+ )(effect, { signal: options?.signal }) : runtime.runPromiseExit(effect, { signal: options?.signal });
983
+ }
984
+ function provideLayerWithCurrentServices(effect, layer) {
985
+ const parentServices = getCurrentServices();
986
+ if (!parentServices) {
987
+ return Effect2.provide(effect, layer);
697
988
  }
698
- /**
699
- * Adds tags to all procedures in the router.
700
- * This helpful when you want to group procedures together in the OpenAPI specification.
701
- *
702
- * @see {@link https://orpc.dev/docs/openapi/openapi-specification#operation-metadata OpenAPI Operation Metadata Docs}
703
- */
704
- tag(...tags) {
705
- return new _EffectBuilder({
706
- ...this["~effect"],
707
- tags: mergeTags(this["~effect"].tags, tags)
708
- });
989
+ return Effect2.scoped(
990
+ Effect2.flatMap(
991
+ Layer2.build(layer),
992
+ (layerContext) => Effect2.provide(
993
+ effect,
994
+ Context.merge(layerContext, parentServices)
995
+ )
996
+ )
997
+ );
998
+ }
999
+
1000
+ // src/effect-builder.ts
1001
+ var builderVirtualDescriptors = {
1002
+ "~effect": { enumerable: true },
1003
+ effect: { enumerable: false },
1004
+ errors: { enumerable: false },
1005
+ handler: { enumerable: false },
1006
+ lazy: { enumerable: false },
1007
+ middleware: { enumerable: false },
1008
+ provide: { enumerable: false },
1009
+ provideOptional: { enumerable: false },
1010
+ router: { enumerable: false },
1011
+ traced: { enumerable: false }
1012
+ };
1013
+ var builderVirtualKeys = [
1014
+ "~effect",
1015
+ "errors",
1016
+ "effect",
1017
+ "middleware",
1018
+ "provide",
1019
+ "provideOptional",
1020
+ "traced",
1021
+ "handler",
1022
+ "router",
1023
+ "lazy"
1024
+ ];
1025
+ function isBuilderLike(value) {
1026
+ return typeof value === "object" && value !== null && "~orpc" in value;
1027
+ }
1028
+ function getOrCreateVirtualMethod2(context, prop, factory) {
1029
+ const cache = context.methodCache;
1030
+ if (cache.has(prop)) {
1031
+ return cache.get(prop);
709
1032
  }
710
- /**
711
- * Applies all of the previously defined options to the specified router.
712
- *
713
- * @see {@link https://orpc.dev/docs/router#extending-router Extending Router Docs}
714
- */
715
- router(router) {
716
- return enhanceEffectRouter(router, {
717
- ...this["~effect"]
718
- });
1033
+ const value = factory();
1034
+ cache.set(prop, value);
1035
+ return value;
1036
+ }
1037
+ function getEffectBuilderDef(context) {
1038
+ return {
1039
+ ...context.upstream["~orpc"],
1040
+ effectErrorMap: context.state.effectErrorMap,
1041
+ runner: context.state.runner,
1042
+ spanConfig: context.state.spanConfig,
1043
+ effectSteps: context.state.effectSteps,
1044
+ effectHandler: context.state.effectHandler
1045
+ };
1046
+ }
1047
+ function wrapBuilderLike(builder, state) {
1048
+ return new EffectBuilder(
1049
+ {
1050
+ ...builder["~orpc"],
1051
+ effectErrorMap: state.effectErrorMap,
1052
+ runner: state.runner,
1053
+ spanConfig: state.spanConfig,
1054
+ effectSteps: state.effectSteps,
1055
+ effectHandler: state.effectHandler
1056
+ },
1057
+ unwrapEffectUpstream(builder)
1058
+ );
1059
+ }
1060
+ function appendEffectStep2(state, step) {
1061
+ return {
1062
+ ...state,
1063
+ effectSteps: [...state.effectSteps ?? [], step]
1064
+ };
1065
+ }
1066
+ function flushEffectSteps2(builder, state) {
1067
+ if (!state.effectSteps?.length) {
1068
+ return { builder, state };
719
1069
  }
720
- /**
721
- * Create a lazy router
722
- * And applies all of the previously defined options to the specified router.
723
- *
724
- * @see {@link https://orpc.dev/docs/router#extending-router Extending Router Docs}
725
- */
726
- lazy(loader) {
727
- return enhanceEffectRouter(lazy2(loader), {
728
- ...this["~effect"]
1070
+ const middleware = createEffectPipelineMiddleware({
1071
+ effectErrorMap: state.effectErrorMap,
1072
+ runner: state.runner,
1073
+ steps: state.effectSteps
1074
+ });
1075
+ return {
1076
+ builder: Reflect.apply(Reflect.get(builder, "use", builder), builder, [
1077
+ middleware
1078
+ ]),
1079
+ state: {
1080
+ ...state,
1081
+ effectSteps: void 0
1082
+ }
1083
+ };
1084
+ }
1085
+ function createEffectBuilderProxy(target) {
1086
+ return createNodeProxy(target, {
1087
+ getVirtual(context, prop) {
1088
+ const effectDef = getEffectBuilderDef(context);
1089
+ if (prop === "~effect") {
1090
+ return getEffectBuilderDef(context);
1091
+ }
1092
+ const { upstream: source, state } = context;
1093
+ switch (prop) {
1094
+ case "errors":
1095
+ return getOrCreateVirtualMethod2(context, prop, () => {
1096
+ return (errors) => {
1097
+ const nextEffectErrorMap = {
1098
+ ...state.effectErrorMap,
1099
+ ...errors
1100
+ };
1101
+ const nextBuilder = Reflect.apply(
1102
+ Reflect.get(source, "errors", source),
1103
+ source,
1104
+ [effectErrorMapToErrorMap(errors)]
1105
+ );
1106
+ return wrapBuilderLike(nextBuilder, {
1107
+ ...state,
1108
+ effectErrorMap: nextEffectErrorMap
1109
+ });
1110
+ };
1111
+ });
1112
+ case "effect":
1113
+ return getOrCreateVirtualMethod2(context, prop, () => {
1114
+ return (effectFn) => {
1115
+ const defaultCaptureStackTrace = addSpanStackTrace();
1116
+ const effectHandler = {
1117
+ defaultCaptureStackTrace,
1118
+ effectFn,
1119
+ spanConfig: state.spanConfig
1120
+ };
1121
+ return new EffectDecoratedProcedure({
1122
+ ...effectDef,
1123
+ effectHandler,
1124
+ handler: async (opts) => {
1125
+ return createEffectProcedureHandler({
1126
+ defaultCaptureStackTrace,
1127
+ effectErrorMap: state.effectErrorMap,
1128
+ effectFn,
1129
+ effectSteps: state.effectSteps,
1130
+ runner: state.runner,
1131
+ spanConfig: state.spanConfig
1132
+ })(opts);
1133
+ }
1134
+ });
1135
+ };
1136
+ });
1137
+ case "middleware":
1138
+ return getOrCreateVirtualMethod2(context, prop, () => {
1139
+ return (middleware) => {
1140
+ if (isEffectMiddleware(middleware)) {
1141
+ const effectMiddleware = createEffectPipelineMiddleware({
1142
+ effectErrorMap: state.effectErrorMap,
1143
+ runner: state.runner,
1144
+ steps: [
1145
+ ...state.effectSteps ?? [],
1146
+ { _tag: "middleware", middleware }
1147
+ ]
1148
+ });
1149
+ return Reflect.apply(
1150
+ Reflect.get(source, "middleware", source),
1151
+ source,
1152
+ [effectMiddleware]
1153
+ );
1154
+ }
1155
+ return Reflect.apply(
1156
+ Reflect.get(source, "middleware", source),
1157
+ source,
1158
+ [middleware]
1159
+ );
1160
+ };
1161
+ });
1162
+ case "provide":
1163
+ return getOrCreateVirtualMethod2(context, prop, () => {
1164
+ return (tagOrLayer, provider) => {
1165
+ return wrapBuilderLike(
1166
+ source,
1167
+ appendEffectStep2(
1168
+ state,
1169
+ Layer3.isLayer(tagOrLayer) ? { _tag: "provideLayer", layer: tagOrLayer } : { _tag: "provide", provider, tag: tagOrLayer }
1170
+ )
1171
+ );
1172
+ };
1173
+ });
1174
+ case "provideOptional":
1175
+ return getOrCreateVirtualMethod2(context, prop, () => {
1176
+ return (tag, provider) => {
1177
+ return wrapBuilderLike(
1178
+ source,
1179
+ appendEffectStep2(state, {
1180
+ _tag: "provideOptional",
1181
+ provider,
1182
+ tag
1183
+ })
1184
+ );
1185
+ };
1186
+ });
1187
+ case "use":
1188
+ return getOrCreateVirtualMethod2(context, prop, () => {
1189
+ return (middleware, ...rest) => {
1190
+ if (isEffectMiddleware(middleware) && rest.length === 0) {
1191
+ return wrapBuilderLike(
1192
+ source,
1193
+ appendEffectStep2(state, {
1194
+ _tag: "middleware",
1195
+ middleware
1196
+ })
1197
+ );
1198
+ }
1199
+ const flushed = flushEffectSteps2(source, state);
1200
+ const nextBuilder = Reflect.apply(
1201
+ Reflect.get(flushed.builder, "use", flushed.builder),
1202
+ flushed.builder,
1203
+ [middleware, ...rest]
1204
+ );
1205
+ return wrapBuilderLike(nextBuilder, flushed.state);
1206
+ };
1207
+ });
1208
+ case "traced":
1209
+ return getOrCreateVirtualMethod2(context, prop, () => {
1210
+ return (spanName) => wrapBuilderLike(source, {
1211
+ ...state,
1212
+ spanConfig: {
1213
+ captureStackTrace: addSpanStackTrace(),
1214
+ name: spanName
1215
+ }
1216
+ });
1217
+ });
1218
+ case "handler":
1219
+ return getOrCreateVirtualMethod2(context, prop, () => {
1220
+ return (handler) => new EffectDecoratedProcedure({
1221
+ ...effectDef,
1222
+ handler
1223
+ });
1224
+ });
1225
+ case "router":
1226
+ return getOrCreateVirtualMethod2(context, prop, () => {
1227
+ return (router) => enhanceEffectRouter(router, effectDef);
1228
+ });
1229
+ case "lazy":
1230
+ return getOrCreateVirtualMethod2(context, prop, () => {
1231
+ return (loader) => enhanceEffectRouter(lazy2(loader), effectDef);
1232
+ });
1233
+ default:
1234
+ return unhandled();
1235
+ }
1236
+ },
1237
+ virtualDescriptors: builderVirtualDescriptors,
1238
+ virtualKeys: builderVirtualKeys,
1239
+ wrapResult(context, _prop, result) {
1240
+ if (!isBuilderLike(result)) {
1241
+ return result;
1242
+ }
1243
+ return wrapBuilderLike(result, context.state);
1244
+ }
1245
+ });
1246
+ }
1247
+ function addSpanStackTrace() {
1248
+ const ErrorConstructor = Error;
1249
+ const limit = ErrorConstructor.stackTraceLimit;
1250
+ ErrorConstructor.stackTraceLimit = 3;
1251
+ const traceError = new Error();
1252
+ ErrorConstructor.stackTraceLimit = limit;
1253
+ let cache = false;
1254
+ return () => {
1255
+ if (cache !== false) {
1256
+ return cache;
1257
+ }
1258
+ if (traceError.stack !== void 0) {
1259
+ const stack = traceError.stack.split("\n");
1260
+ if (stack[3] !== void 0) {
1261
+ cache = stack[3].trim();
1262
+ return cache;
1263
+ }
1264
+ }
1265
+ };
1266
+ }
1267
+ var EffectBuilder = class {
1268
+ constructor(def, builder) {
1269
+ const { runner, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
1270
+ attachEffectState(this, builder ?? new Builder(orpcDef), {
1271
+ effectSteps,
1272
+ effectHandler: def.effectHandler,
1273
+ effectErrorMap,
1274
+ runner,
1275
+ spanConfig
729
1276
  });
1277
+ return createEffectBuilderProxy(this);
730
1278
  }
731
1279
  };
732
- function makeEffectORPC(runtime, builder) {
733
- const resolvedBuilder = builder ?? emptyBuilder();
734
- return new EffectBuilder({
735
- ...resolvedBuilder["~orpc"],
736
- errorMap: effectErrorMapToErrorMap(resolvedBuilder["~orpc"].errorMap),
737
- effectErrorMap: resolvedBuilder["~orpc"].errorMap,
738
- runtime
739
- });
1280
+ function makeEffectORPC(source, builder) {
1281
+ const sourceIsBuilder = source !== void 0 && isBuilderLike(source);
1282
+ const resolvedBuilder = sourceIsBuilder ? source : builder ?? emptyBuilder();
1283
+ const effectErrorMap = getEffectErrorMap(resolvedBuilder);
1284
+ const runner = sourceIsBuilder || source === void 0 ? makeEffectRuntimeRunner() : makeEffectRuntimeRunner(source);
1285
+ return new EffectBuilder(
1286
+ {
1287
+ ...resolvedBuilder["~orpc"],
1288
+ effectErrorMap,
1289
+ errorMap: effectErrorMapToErrorMap(effectErrorMap),
1290
+ runner
1291
+ },
1292
+ unwrapEffectUpstream(resolvedBuilder)
1293
+ );
740
1294
  }
741
1295
  function emptyBuilder() {
742
1296
  return new Builder({
743
1297
  config: {},
744
- route: {},
745
- meta: {},
1298
+ dedupeLeadingMiddlewares: true,
746
1299
  errorMap: {},
747
1300
  inputValidationIndex: fallbackConfig("initialInputValidationIndex"),
748
- outputValidationIndex: fallbackConfig("initialOutputValidationIndex"),
1301
+ meta: {},
749
1302
  middlewares: [],
750
- dedupeLeadingMiddlewares: true
1303
+ outputValidationIndex: fallbackConfig("initialOutputValidationIndex"),
1304
+ route: {}
751
1305
  });
752
1306
  }
1307
+ var eos = makeEffectORPC();
753
1308
 
754
1309
  // src/eoc.ts
755
1310
  import { isContractProcedure, oc } from "@orpc/contract";
@@ -888,15 +1443,15 @@ var CONTRACT_HIDDEN_METHODS = /* @__PURE__ */ new Set([
888
1443
  "router",
889
1444
  "tag"
890
1445
  ]);
891
- function makeEnhanceOptions(runtime) {
1446
+ function makeEnhanceOptions(runner) {
892
1447
  return {
893
1448
  middlewares: [],
894
1449
  errorMap: {},
895
1450
  dedupeLeadingMiddlewares: true,
896
- runtime
1451
+ runner
897
1452
  };
898
1453
  }
899
- function wrapContractNode(contract, target, runtime) {
1454
+ function wrapContractNode(contract, target, runner) {
900
1455
  const cache = /* @__PURE__ */ new Map();
901
1456
  return new Proxy(target, {
902
1457
  get(currentTarget, prop, receiver) {
@@ -911,9 +1466,9 @@ function wrapContractNode(contract, target, runtime) {
911
1466
  ...currentTarget["~orpc"],
912
1467
  errorMap: effectErrorMapToErrorMap(effectErrorMap),
913
1468
  effectErrorMap,
914
- runtime,
1469
+ runner,
915
1470
  handler: createEffectProcedureHandler({
916
- runtime,
1471
+ runner,
917
1472
  effectErrorMap,
918
1473
  effectFn,
919
1474
  defaultCaptureStackTrace: addSpanStackTrace()
@@ -931,7 +1486,7 @@ function wrapContractNode(contract, target, runtime) {
931
1486
  currentTarget,
932
1487
  args
933
1488
  ),
934
- runtime
1489
+ runner
935
1490
  );
936
1491
  cache.set(prop, use);
937
1492
  return use;
@@ -948,7 +1503,7 @@ function wrapContractNode(contract, target, runtime) {
948
1503
  currentTarget,
949
1504
  args
950
1505
  ),
951
- runtime
1506
+ runner
952
1507
  );
953
1508
  cache.set(prop, wrappedMethod);
954
1509
  return wrappedMethod;
@@ -960,7 +1515,7 @@ function wrapContractNode(contract, target, runtime) {
960
1515
  currentTarget,
961
1516
  args
962
1517
  ),
963
- makeEnhanceOptions(runtime)
1518
+ makeEnhanceOptions(runner)
964
1519
  );
965
1520
  cache.set(prop, wrappedMethod);
966
1521
  return wrappedMethod;
@@ -969,7 +1524,7 @@ function wrapContractNode(contract, target, runtime) {
969
1524
  const child = wrapContractNode(
970
1525
  contract[prop],
971
1526
  Reflect.get(currentTarget, prop, receiver),
972
- runtime
1527
+ runner
973
1528
  );
974
1529
  cache.set(prop, child);
975
1530
  return child;
@@ -993,11 +1548,11 @@ function wrapContractNode(contract, target, runtime) {
993
1548
  }
994
1549
  });
995
1550
  }
996
- function implementEffect(contract, runtime) {
1551
+ function implementEffect(contract, source) {
997
1552
  return wrapContractNode(
998
1553
  contract,
999
1554
  implement(contract),
1000
- runtime
1555
+ makeEffectRuntimeRunner(source)
1001
1556
  );
1002
1557
  }
1003
1558
  export {
@@ -1009,6 +1564,7 @@ export {
1009
1564
  createEffectErrorConstructorMap,
1010
1565
  effectErrorMapToErrorMap,
1011
1566
  eoc,
1567
+ eos,
1012
1568
  implementEffect,
1013
1569
  isORPCTaggedError,
1014
1570
  isORPCTaggedErrorClass,