effect-orpc 0.1.3 → 0.2.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.
@@ -0,0 +1,134 @@
1
+ import { ORPCError } from "@orpc/contract";
2
+ import type {
3
+ Context,
4
+ ProcedureHandler,
5
+ ProcedureHandlerOptions,
6
+ } from "@orpc/server";
7
+ import type { ManagedRuntime } from "effect";
8
+ import { Cause, Effect, Exit, FiberRefs } from "effect";
9
+
10
+ import { getCurrentFiberRefs } from "./fiber-context-bridge";
11
+ import type { EffectErrorConstructorMap, EffectErrorMap } from "./tagged-error";
12
+ import {
13
+ createEffectErrorConstructorMap,
14
+ isORPCTaggedError,
15
+ } from "./tagged-error";
16
+ import type { EffectProcedureHandler, EffectSpanConfig } from "./types";
17
+
18
+ export function toORPCErrorFromCause(
19
+ cause: Cause.Cause<unknown>,
20
+ ): ORPCError<string, unknown> {
21
+ return Cause.match(cause, {
22
+ onDie(defect) {
23
+ return new ORPCError("INTERNAL_SERVER_ERROR", {
24
+ cause: defect,
25
+ });
26
+ },
27
+ onFail(error) {
28
+ if (isORPCTaggedError(error)) {
29
+ return error.toORPCError();
30
+ }
31
+ if (error instanceof ORPCError) {
32
+ return error;
33
+ }
34
+ return new ORPCError("INTERNAL_SERVER_ERROR", {
35
+ cause: error,
36
+ });
37
+ },
38
+ onInterrupt(fiberId) {
39
+ return new ORPCError("INTERNAL_SERVER_ERROR", {
40
+ cause: new Error(`${fiberId} Interrupted`),
41
+ });
42
+ },
43
+ onSequential(left) {
44
+ return left;
45
+ },
46
+ onEmpty: new ORPCError("INTERNAL_SERVER_ERROR", {
47
+ cause: new Error("Unknown error"),
48
+ }),
49
+ onParallel(left) {
50
+ return left;
51
+ },
52
+ });
53
+ }
54
+
55
+ export function createEffectProcedureHandler<
56
+ TCurrentContext extends Context,
57
+ TInput,
58
+ TOutput,
59
+ TEffectErrorMap extends EffectErrorMap,
60
+ TRequirementsProvided,
61
+ TRuntimeError,
62
+ TMeta,
63
+ >(options: {
64
+ runtime: ManagedRuntime.ManagedRuntime<TRequirementsProvided, TRuntimeError>;
65
+ effectErrorMap: TEffectErrorMap;
66
+ effectFn: EffectProcedureHandler<
67
+ TCurrentContext,
68
+ TInput,
69
+ TOutput,
70
+ TEffectErrorMap,
71
+ TRequirementsProvided,
72
+ any
73
+ >;
74
+ spanConfig?: EffectSpanConfig;
75
+ defaultCaptureStackTrace: () => string | undefined;
76
+ }): ProcedureHandler<
77
+ TCurrentContext,
78
+ TInput,
79
+ TOutput,
80
+ any,
81
+ TMeta & Record<never, never>
82
+ > {
83
+ const {
84
+ runtime,
85
+ effectErrorMap,
86
+ effectFn,
87
+ spanConfig,
88
+ defaultCaptureStackTrace,
89
+ } = options;
90
+
91
+ return async (opts) => {
92
+ const effectOpts: ProcedureHandlerOptions<
93
+ TCurrentContext,
94
+ TInput,
95
+ EffectErrorConstructorMap<TEffectErrorMap>,
96
+ TMeta & Record<never, never>
97
+ > = {
98
+ context: opts.context,
99
+ input: opts.input,
100
+ path: opts.path,
101
+ procedure: opts.procedure,
102
+ signal: opts.signal,
103
+ lastEventId: opts.lastEventId,
104
+ errors: createEffectErrorConstructorMap(effectErrorMap),
105
+ };
106
+
107
+ const spanName = spanConfig?.name ?? opts.path.join(".");
108
+ const captureStackTrace =
109
+ spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
110
+ const resolver = Effect.fnUntraced(effectFn as any);
111
+ const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
112
+ captureStackTrace,
113
+ });
114
+ const parentFiberRefs = getCurrentFiberRefs();
115
+ const effectWithRefs = parentFiberRefs
116
+ ? Effect.fiberIdWith((fiberId) =>
117
+ Effect.flatMap(Effect.getFiberRefs, (fiberRefs) =>
118
+ Effect.setFiberRefs(
119
+ FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs),
120
+ ).pipe(Effect.andThen(tracedEffect)),
121
+ ),
122
+ )
123
+ : tracedEffect;
124
+ const exit = await runtime.runPromiseExit(effectWithRefs, {
125
+ signal: opts.signal,
126
+ });
127
+
128
+ if (Exit.isFailure(exit)) {
129
+ throw toORPCErrorFromCause(exit.cause);
130
+ }
131
+
132
+ return exit.value as TOutput;
133
+ };
134
+ }
package/src/eoc.ts ADDED
@@ -0,0 +1,499 @@
1
+ import type {
2
+ AnySchema,
3
+ ContractProcedure,
4
+ ContractRouter,
5
+ ErrorMap,
6
+ HTTPPath,
7
+ Meta,
8
+ Route,
9
+ Schema,
10
+ } from "@orpc/contract";
11
+ import { isContractProcedure, oc } from "@orpc/contract";
12
+
13
+ import type { EffectErrorMap, MergedEffectErrorMap } from "./tagged-error";
14
+ import { effectErrorMapToErrorMap } from "./tagged-error";
15
+ import type { EffectErrorMapToErrorMap } from "./types";
16
+
17
+ export const effectContractSymbol: unique symbol = Symbol.for(
18
+ "@orpc/effect/contract",
19
+ );
20
+
21
+ interface EffectContractMetadata<TEffectErrorMap extends EffectErrorMap> {
22
+ readonly [effectContractSymbol]: {
23
+ readonly errorMap: TEffectErrorMap;
24
+ };
25
+ }
26
+
27
+ type LocalEffectErrorMap<T> =
28
+ T extends EffectContractMetadata<infer TEffectErrorMap extends EffectErrorMap>
29
+ ? TEffectErrorMap
30
+ : Record<never, never>;
31
+
32
+ type ContractWithEffectErrorMap<T, TEffectErrorMap extends EffectErrorMap> =
33
+ T extends ContractProcedure<
34
+ infer TInputSchema,
35
+ infer TOutputSchema,
36
+ infer TErrorMap extends ErrorMap,
37
+ infer TMeta extends Meta
38
+ >
39
+ ? ContractProcedure<TInputSchema, TOutputSchema, TErrorMap, TMeta> &
40
+ EffectContractMetadata<
41
+ MergedEffectErrorMap<TEffectErrorMap, LocalEffectErrorMap<T>>
42
+ >
43
+ : T extends ContractRouter<Meta>
44
+ ? {
45
+ [K in keyof T]: ContractWithEffectErrorMap<T[K], TEffectErrorMap>;
46
+ }
47
+ : never;
48
+
49
+ export interface EffectContractProcedureBuilder<
50
+ TInputSchema extends AnySchema,
51
+ TOutputSchema extends AnySchema,
52
+ TEffectErrorMap extends EffectErrorMap,
53
+ TMeta extends Meta,
54
+ >
55
+ extends
56
+ ContractProcedure<
57
+ TInputSchema,
58
+ TOutputSchema,
59
+ EffectErrorMapToErrorMap<TEffectErrorMap>,
60
+ TMeta
61
+ >,
62
+ EffectContractMetadata<TEffectErrorMap> {
63
+ errors<U extends EffectErrorMap>(
64
+ errors: U,
65
+ ): EffectContractProcedureBuilder<
66
+ TInputSchema,
67
+ TOutputSchema,
68
+ MergedEffectErrorMap<TEffectErrorMap, U>,
69
+ TMeta
70
+ >;
71
+ meta(
72
+ meta: TMeta,
73
+ ): EffectContractProcedureBuilder<
74
+ TInputSchema,
75
+ TOutputSchema,
76
+ TEffectErrorMap,
77
+ TMeta
78
+ >;
79
+ route(
80
+ route: Route,
81
+ ): EffectContractProcedureBuilder<
82
+ TInputSchema,
83
+ TOutputSchema,
84
+ TEffectErrorMap,
85
+ TMeta
86
+ >;
87
+ input<U extends AnySchema>(
88
+ schema: U,
89
+ ): EffectContractProcedureBuilderWithInput<
90
+ U,
91
+ TOutputSchema,
92
+ TEffectErrorMap,
93
+ TMeta
94
+ >;
95
+ output<U extends AnySchema>(
96
+ schema: U,
97
+ ): EffectContractProcedureBuilderWithOutput<
98
+ TInputSchema,
99
+ U,
100
+ TEffectErrorMap,
101
+ TMeta
102
+ >;
103
+ }
104
+
105
+ export interface EffectContractProcedureBuilderWithInput<
106
+ TInputSchema extends AnySchema,
107
+ TOutputSchema extends AnySchema,
108
+ TEffectErrorMap extends EffectErrorMap,
109
+ TMeta extends Meta,
110
+ >
111
+ extends
112
+ ContractProcedure<
113
+ TInputSchema,
114
+ TOutputSchema,
115
+ EffectErrorMapToErrorMap<TEffectErrorMap>,
116
+ TMeta
117
+ >,
118
+ EffectContractMetadata<TEffectErrorMap> {
119
+ errors<U extends EffectErrorMap>(
120
+ errors: U,
121
+ ): EffectContractProcedureBuilderWithInput<
122
+ TInputSchema,
123
+ TOutputSchema,
124
+ MergedEffectErrorMap<TEffectErrorMap, U>,
125
+ TMeta
126
+ >;
127
+ meta(
128
+ meta: TMeta,
129
+ ): EffectContractProcedureBuilderWithInput<
130
+ TInputSchema,
131
+ TOutputSchema,
132
+ TEffectErrorMap,
133
+ TMeta
134
+ >;
135
+ route(
136
+ route: Route,
137
+ ): EffectContractProcedureBuilderWithInput<
138
+ TInputSchema,
139
+ TOutputSchema,
140
+ TEffectErrorMap,
141
+ TMeta
142
+ >;
143
+ output<U extends AnySchema>(
144
+ schema: U,
145
+ ): EffectContractProcedureBuilderWithInputOutput<
146
+ TInputSchema,
147
+ U,
148
+ TEffectErrorMap,
149
+ TMeta
150
+ >;
151
+ }
152
+
153
+ export interface EffectContractProcedureBuilderWithOutput<
154
+ TInputSchema extends AnySchema,
155
+ TOutputSchema extends AnySchema,
156
+ TEffectErrorMap extends EffectErrorMap,
157
+ TMeta extends Meta,
158
+ >
159
+ extends
160
+ ContractProcedure<
161
+ TInputSchema,
162
+ TOutputSchema,
163
+ EffectErrorMapToErrorMap<TEffectErrorMap>,
164
+ TMeta
165
+ >,
166
+ EffectContractMetadata<TEffectErrorMap> {
167
+ errors<U extends EffectErrorMap>(
168
+ errors: U,
169
+ ): EffectContractProcedureBuilderWithOutput<
170
+ TInputSchema,
171
+ TOutputSchema,
172
+ MergedEffectErrorMap<TEffectErrorMap, U>,
173
+ TMeta
174
+ >;
175
+ meta(
176
+ meta: TMeta,
177
+ ): EffectContractProcedureBuilderWithOutput<
178
+ TInputSchema,
179
+ TOutputSchema,
180
+ TEffectErrorMap,
181
+ TMeta
182
+ >;
183
+ route(
184
+ route: Route,
185
+ ): EffectContractProcedureBuilderWithOutput<
186
+ TInputSchema,
187
+ TOutputSchema,
188
+ TEffectErrorMap,
189
+ TMeta
190
+ >;
191
+ input<U extends AnySchema>(
192
+ schema: U,
193
+ ): EffectContractProcedureBuilderWithInputOutput<
194
+ U,
195
+ TOutputSchema,
196
+ TEffectErrorMap,
197
+ TMeta
198
+ >;
199
+ }
200
+
201
+ export interface EffectContractProcedureBuilderWithInputOutput<
202
+ TInputSchema extends AnySchema,
203
+ TOutputSchema extends AnySchema,
204
+ TEffectErrorMap extends EffectErrorMap,
205
+ TMeta extends Meta,
206
+ >
207
+ extends
208
+ ContractProcedure<
209
+ TInputSchema,
210
+ TOutputSchema,
211
+ EffectErrorMapToErrorMap<TEffectErrorMap>,
212
+ TMeta
213
+ >,
214
+ EffectContractMetadata<TEffectErrorMap> {
215
+ errors<U extends EffectErrorMap>(
216
+ errors: U,
217
+ ): EffectContractProcedureBuilderWithInputOutput<
218
+ TInputSchema,
219
+ TOutputSchema,
220
+ MergedEffectErrorMap<TEffectErrorMap, U>,
221
+ TMeta
222
+ >;
223
+ meta(
224
+ meta: TMeta,
225
+ ): EffectContractProcedureBuilderWithInputOutput<
226
+ TInputSchema,
227
+ TOutputSchema,
228
+ TEffectErrorMap,
229
+ TMeta
230
+ >;
231
+ route(
232
+ route: Route,
233
+ ): EffectContractProcedureBuilderWithInputOutput<
234
+ TInputSchema,
235
+ TOutputSchema,
236
+ TEffectErrorMap,
237
+ TMeta
238
+ >;
239
+ }
240
+
241
+ export interface EffectContractRouterBuilder<
242
+ TEffectErrorMap extends EffectErrorMap,
243
+ TMeta extends Meta,
244
+ > extends EffectContractMetadata<TEffectErrorMap> {
245
+ errors<U extends EffectErrorMap>(
246
+ errors: U,
247
+ ): EffectContractRouterBuilder<
248
+ MergedEffectErrorMap<TEffectErrorMap, U>,
249
+ TMeta
250
+ >;
251
+ prefix(prefix: HTTPPath): EffectContractRouterBuilder<TEffectErrorMap, TMeta>;
252
+ tag(...tags: string[]): EffectContractRouterBuilder<TEffectErrorMap, TMeta>;
253
+ router<T extends ContractRouter<TMeta>>(
254
+ router: T,
255
+ ): ContractWithEffectErrorMap<T, TEffectErrorMap>;
256
+ }
257
+
258
+ export interface EffectContractBuilder<
259
+ TInputSchema extends AnySchema,
260
+ TOutputSchema extends AnySchema,
261
+ TEffectErrorMap extends EffectErrorMap,
262
+ TMeta extends Meta,
263
+ >
264
+ extends
265
+ ContractProcedure<
266
+ TInputSchema,
267
+ TOutputSchema,
268
+ EffectErrorMapToErrorMap<TEffectErrorMap>,
269
+ TMeta
270
+ >,
271
+ EffectContractMetadata<TEffectErrorMap> {
272
+ $meta<U extends Meta>(
273
+ initialMeta: U,
274
+ ): EffectContractBuilder<TInputSchema, TOutputSchema, TEffectErrorMap, U>;
275
+ $route(
276
+ initialRoute: Route,
277
+ ): EffectContractBuilder<TInputSchema, TOutputSchema, TEffectErrorMap, TMeta>;
278
+ $input<U extends AnySchema>(
279
+ initialInputSchema?: U,
280
+ ): EffectContractBuilder<U, TOutputSchema, TEffectErrorMap, TMeta>;
281
+ errors<U extends EffectErrorMap>(
282
+ errors: U,
283
+ ): EffectContractBuilder<
284
+ TInputSchema,
285
+ TOutputSchema,
286
+ MergedEffectErrorMap<TEffectErrorMap, U>,
287
+ TMeta
288
+ >;
289
+ meta(
290
+ meta: TMeta,
291
+ ): EffectContractProcedureBuilder<
292
+ TInputSchema,
293
+ TOutputSchema,
294
+ TEffectErrorMap,
295
+ TMeta
296
+ >;
297
+ route(
298
+ route: Route,
299
+ ): EffectContractProcedureBuilder<
300
+ TInputSchema,
301
+ TOutputSchema,
302
+ TEffectErrorMap,
303
+ TMeta
304
+ >;
305
+ input<U extends AnySchema>(
306
+ schema: U,
307
+ ): EffectContractProcedureBuilderWithInput<
308
+ U,
309
+ TOutputSchema,
310
+ TEffectErrorMap,
311
+ TMeta
312
+ >;
313
+ output<U extends AnySchema>(
314
+ schema: U,
315
+ ): EffectContractProcedureBuilderWithOutput<
316
+ TInputSchema,
317
+ U,
318
+ TEffectErrorMap,
319
+ TMeta
320
+ >;
321
+ prefix(prefix: HTTPPath): EffectContractRouterBuilder<TEffectErrorMap, TMeta>;
322
+ tag(...tags: string[]): EffectContractRouterBuilder<TEffectErrorMap, TMeta>;
323
+ router<T extends ContractRouter<TMeta>>(
324
+ router: T,
325
+ ): ContractWithEffectErrorMap<T, TEffectErrorMap>;
326
+ }
327
+
328
+ function isWrappableContractBuilder(value: unknown): value is {
329
+ "~orpc": { errorMap: ErrorMap };
330
+ } {
331
+ return typeof value === "object" && value !== null && "~orpc" in value;
332
+ }
333
+
334
+ function mergeEffectErrorMaps(
335
+ left: EffectErrorMap | undefined,
336
+ right: EffectErrorMap | undefined,
337
+ ): EffectErrorMap | undefined {
338
+ if (!left) {
339
+ return right;
340
+ }
341
+
342
+ if (!right) {
343
+ return left;
344
+ }
345
+
346
+ return {
347
+ ...left,
348
+ ...right,
349
+ };
350
+ }
351
+
352
+ function setEffectContractErrorMap(
353
+ value: object,
354
+ effectErrorMap: EffectErrorMap | undefined,
355
+ ): void {
356
+ if (!effectErrorMap) {
357
+ return;
358
+ }
359
+
360
+ Object.defineProperty(value, effectContractSymbol, {
361
+ value: { errorMap: effectErrorMap },
362
+ enumerable: false,
363
+ configurable: true,
364
+ });
365
+ }
366
+
367
+ export function getEffectContractErrorMap(
368
+ value: unknown,
369
+ ): EffectErrorMap | undefined {
370
+ if (typeof value !== "object" || value === null) {
371
+ return undefined;
372
+ }
373
+
374
+ return (value as Partial<EffectContractMetadata<EffectErrorMap>>)[
375
+ effectContractSymbol
376
+ ]?.errorMap;
377
+ }
378
+
379
+ function applyEffectContractErrorMapToRouter(
380
+ router: ContractRouter<Meta>,
381
+ source: ContractRouter<Meta> | undefined,
382
+ inheritedEffectErrorMap: EffectErrorMap | undefined,
383
+ ): void {
384
+ const routerRecord = router as Record<string, ContractRouter<Meta>>;
385
+ const sourceRecord = source as
386
+ | Record<string, ContractRouter<Meta>>
387
+ | undefined;
388
+
389
+ for (const key of Object.keys(routerRecord)) {
390
+ const routerValue = routerRecord[key];
391
+ const sourceValue =
392
+ sourceRecord && typeof sourceRecord === "object"
393
+ ? sourceRecord[key]
394
+ : undefined;
395
+
396
+ if (!routerValue) {
397
+ continue;
398
+ }
399
+
400
+ if (isContractProcedure(routerValue)) {
401
+ const sourceEffectErrorMap = getEffectContractErrorMap(sourceValue);
402
+ setEffectContractErrorMap(
403
+ routerValue,
404
+ mergeEffectErrorMaps(inheritedEffectErrorMap, sourceEffectErrorMap),
405
+ );
406
+ continue;
407
+ }
408
+
409
+ if (typeof routerValue === "object") {
410
+ applyEffectContractErrorMapToRouter(
411
+ routerValue,
412
+ sourceValue as ContractRouter<Meta> | undefined,
413
+ inheritedEffectErrorMap,
414
+ );
415
+ }
416
+ }
417
+ }
418
+
419
+ function wrapEffectContractBuilder<T>(
420
+ builder: T,
421
+ inheritedEffectErrorMap?: EffectErrorMap,
422
+ ): T {
423
+ const currentEffectErrorMap =
424
+ inheritedEffectErrorMap ?? getEffectContractErrorMap(builder);
425
+
426
+ if (typeof builder === "object" && builder !== null) {
427
+ setEffectContractErrorMap(builder as object, currentEffectErrorMap);
428
+ }
429
+
430
+ const proxy = new Proxy(builder as object, {
431
+ get(target, prop, receiver) {
432
+ if (prop === effectContractSymbol) {
433
+ return currentEffectErrorMap
434
+ ? { errorMap: currentEffectErrorMap }
435
+ : undefined;
436
+ }
437
+
438
+ if (prop === "errors") {
439
+ return (errors: EffectErrorMap) => {
440
+ const nextEffectErrorMap = mergeEffectErrorMaps(
441
+ currentEffectErrorMap,
442
+ errors,
443
+ );
444
+
445
+ return wrapEffectContractBuilder(
446
+ Reflect.apply(Reflect.get(target, prop, receiver), target, [
447
+ effectErrorMapToErrorMap(errors),
448
+ ]),
449
+ nextEffectErrorMap,
450
+ );
451
+ };
452
+ }
453
+
454
+ if (prop === "router") {
455
+ return (router: ContractRouter<Meta>) => {
456
+ const result = Reflect.apply(
457
+ Reflect.get(target, prop, receiver),
458
+ target,
459
+ [router],
460
+ ) as ContractRouter<Meta>;
461
+
462
+ applyEffectContractErrorMapToRouter(
463
+ result,
464
+ router,
465
+ currentEffectErrorMap,
466
+ );
467
+
468
+ return result;
469
+ };
470
+ }
471
+
472
+ const value = Reflect.get(target, prop, receiver);
473
+ if (typeof value !== "function") {
474
+ return value;
475
+ }
476
+
477
+ return (...args: unknown[]) => {
478
+ const result = Reflect.apply(value, target, args);
479
+ return isWrappableContractBuilder(result)
480
+ ? wrapEffectContractBuilder(result, currentEffectErrorMap)
481
+ : result;
482
+ };
483
+ },
484
+ }) as T;
485
+
486
+ setEffectContractErrorMap(proxy as object, currentEffectErrorMap);
487
+
488
+ return proxy;
489
+ }
490
+
491
+ export const eoc = wrapEffectContractBuilder(
492
+ oc,
493
+ {},
494
+ ) as unknown as EffectContractBuilder<
495
+ Schema<unknown, unknown>,
496
+ Schema<unknown, unknown>,
497
+ Record<never, never>,
498
+ Record<never, never>
499
+ >;
package/src/index.ts CHANGED
@@ -1,3 +1,18 @@
1
+ export { implementEffect } from "./contract";
2
+ export type {
3
+ EffectImplementer,
4
+ EffectImplementerInternal,
5
+ EffectProcedureImplementer,
6
+ } from "./contract";
7
+ export { eoc } from "./eoc";
8
+ export type {
9
+ EffectContractBuilder,
10
+ EffectContractProcedureBuilder,
11
+ EffectContractProcedureBuilderWithInput,
12
+ EffectContractProcedureBuilderWithInputOutput,
13
+ EffectContractProcedureBuilderWithOutput,
14
+ EffectContractRouterBuilder,
15
+ } from "./eoc";
1
16
  export {
2
17
  addSpanStackTrace,
3
18
  EffectBuilder,
@@ -40,10 +55,10 @@ export type {
40
55
  EffectProcedureHandler,
41
56
  EffectRouterBuilder,
42
57
  EffectSpanConfig,
43
- InferBuilderInitialContext,
44
58
  InferBuilderCurrentContext,
45
- InferBuilderInputSchema,
46
- InferBuilderOutputSchema,
47
59
  InferBuilderErrorMap,
60
+ InferBuilderInitialContext,
61
+ InferBuilderInputSchema,
48
62
  InferBuilderMeta,
63
+ InferBuilderOutputSchema,
49
64
  } from "./types";
@@ -15,7 +15,6 @@ import type {
15
15
  ErrorMapItem,
16
16
  InferSchemaOutput,
17
17
  } from "@orpc/contract";
18
- import type { ORPCErrorConstructorMap } from "@orpc/server";
19
18
  import type { MaybeOptionalOptions } from "@orpc/shared";
20
19
  import { resolveMaybeOptionalOptions } from "@orpc/shared";
21
20
  import type { Pipeable } from "effect";
@@ -433,8 +432,29 @@ export type EffectErrorMapToUnion<T extends EffectErrorMap> = {
433
432
  /**
434
433
  * Constructor map for EffectErrorMap - provides typed error constructors for handlers.
435
434
  */
436
- export type EffectErrorConstructorMap<T extends EffectErrorMap> =
437
- ORPCErrorConstructorMap<EffectErrorMapToErrorMap<T>>;
435
+ type EffectErrorConstructor<
436
+ TCode extends ORPCErrorCode,
437
+ TItem,
438
+ > = TItem extends AnyORPCTaggedErrorClass
439
+ ? (...args: ConstructorParameters<TItem>) => InstanceType<TItem>
440
+ : TItem extends { data?: infer TSchema extends AnySchema }
441
+ ? (
442
+ ...rest: MaybeOptionalOptions<
443
+ Omit<
444
+ ORPCErrorOptions<InferSchemaOutput<TSchema>>,
445
+ "defined" | "status"
446
+ >
447
+ >
448
+ ) => ORPCError<TCode, InferSchemaOutput<TSchema>>
449
+ : (
450
+ ...rest: MaybeOptionalOptions<
451
+ Omit<ORPCErrorOptions<unknown>, "defined" | "status">
452
+ >
453
+ ) => ORPCError<TCode, unknown>;
454
+
455
+ export type EffectErrorConstructorMap<T extends EffectErrorMap> = {
456
+ [K in Extract<keyof T, ORPCErrorCode>]: EffectErrorConstructor<K, T[K]>;
457
+ };
438
458
 
439
459
  /**
440
460
  * Creates an error constructor map from an EffectErrorMap.
@@ -478,7 +498,7 @@ export function createEffectErrorConstructorMap<T extends EffectErrorMap>(
478
498
  },
479
499
  });
480
500
 
481
- return proxy as EffectErrorConstructorMap<T>;
501
+ return proxy as unknown as EffectErrorConstructorMap<T>;
482
502
  }
483
503
 
484
504
  /**