effect-orpc 0.2.1 → 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.
@@ -9,14 +9,22 @@ import type {
9
9
  ProcedureDef,
10
10
  } from "@orpc/server";
11
11
  import {
12
+ Procedure,
12
13
  addMiddleware,
13
14
  createActionableClient,
14
15
  createProcedureClient,
15
16
  decorateMiddleware,
16
- Procedure,
17
17
  } from "@orpc/server";
18
18
  import type { MaybeOptionalOptions } from "@orpc/shared";
19
+ import { Layer } from "effect";
19
20
 
21
+ import {
22
+ createEffectOptionalProviderMiddleware,
23
+ createEffectPipelineMiddleware,
24
+ createEffectProcedureHandler,
25
+ createEffectProviderMiddleware,
26
+ isEffectMiddleware,
27
+ } from "./effect-runtime";
20
28
  import { composeSurfaceProxy } from "./extension/compose-surfaces";
21
29
  import {
22
30
  createNodeProxy,
@@ -30,7 +38,11 @@ import {
30
38
  } from "./extension/state";
31
39
  import type { EffectErrorMap, MergedEffectErrorMap } from "./tagged-error";
32
40
  import { effectErrorMapToErrorMap } from "./tagged-error";
33
- import type { EffectErrorMapToErrorMap, EffectProcedureDef } from "./types";
41
+ import type {
42
+ EffectErrorMapToErrorMap,
43
+ EffectPipelineStep,
44
+ EffectProcedureDef,
45
+ } from "./types";
34
46
  import type { EffectDecoratedProcedureSurface } from "./types/effect-procedure-surface";
35
47
 
36
48
  type AnyProcedureLike = Procedure<any, any, any, any, any, any>;
@@ -66,6 +78,8 @@ const procedureVirtualDescriptors = {
66
78
  callable: { enumerable: false },
67
79
  errors: { enumerable: false },
68
80
  meta: { enumerable: false },
81
+ provide: { enumerable: false },
82
+ provideOptional: { enumerable: false },
69
83
  route: { enumerable: false },
70
84
  use: { enumerable: false },
71
85
  } as const;
@@ -75,6 +89,8 @@ const decoratedProcedureVirtualKeys = [
75
89
  ...baseProcedureVirtualKeys,
76
90
  "errors",
77
91
  "meta",
92
+ "provide",
93
+ "provideOptional",
78
94
  "route",
79
95
  "use",
80
96
  "callable",
@@ -101,11 +117,69 @@ function getEffectProcedureDef(
101
117
  ): EffectProcedureDef<any, any, any, any, any, any, any, any> {
102
118
  return {
103
119
  ...context.upstream["~orpc"],
120
+ effectSteps: context.state.effectSteps,
121
+ effectHandler: context.state.effectHandler,
104
122
  effectErrorMap: context.state.effectErrorMap,
105
123
  runtime: context.state.runtime,
106
124
  };
107
125
  }
108
126
 
127
+ function makeEffectProcedureHandler(
128
+ def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
129
+ ) {
130
+ if (!def.effectHandler) {
131
+ return def.handler;
132
+ }
133
+
134
+ return createEffectProcedureHandler({
135
+ defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
136
+ effectErrorMap: def.effectErrorMap,
137
+ effectFn: def.effectHandler.effectFn,
138
+ effectSteps: def.effectSteps,
139
+ runtime: def.runtime,
140
+ spanConfig: def.effectHandler.spanConfig,
141
+ });
142
+ }
143
+
144
+ function withRebuiltEffectHandler(
145
+ def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
146
+ ): EffectProcedureDef<any, any, any, any, any, any, any, any> {
147
+ return {
148
+ ...def,
149
+ handler: makeEffectProcedureHandler(def),
150
+ };
151
+ }
152
+
153
+ function appendEffectStep(
154
+ def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
155
+ step: EffectPipelineStep,
156
+ ): EffectProcedureDef<any, any, any, any, any, any, any, any> {
157
+ return withRebuiltEffectHandler({
158
+ ...def,
159
+ effectSteps: [...(def.effectSteps ?? []), step],
160
+ });
161
+ }
162
+
163
+ function flushEffectSteps(
164
+ def: EffectProcedureDef<any, any, any, any, any, any, any, any>,
165
+ ): EffectProcedureDef<any, any, any, any, any, any, any, any> {
166
+ if (!def.effectSteps?.length) {
167
+ return def;
168
+ }
169
+
170
+ const middleware = createEffectPipelineMiddleware({
171
+ effectErrorMap: def.effectErrorMap,
172
+ runtime: def.runtime,
173
+ steps: def.effectSteps,
174
+ });
175
+
176
+ return withRebuiltEffectHandler({
177
+ ...def,
178
+ effectSteps: undefined,
179
+ middlewares: addMiddleware(def.middlewares, middleware),
180
+ });
181
+ }
182
+
109
183
  function createEffectProcedureProxy<
110
184
  T extends AnyEffectProcedure | AnyEffectDecoratedProcedure,
111
185
  >(
@@ -158,22 +232,113 @@ function createEffectProcedureProxy<
158
232
  route: mergeRoute(getEffectProcedureDef(context).route, route),
159
233
  });
160
234
  });
235
+ case "provide":
236
+ return getOrCreateVirtualMethod(context, prop, () => {
237
+ return (tagOrLayer: any, provider?: any) => {
238
+ const def = getEffectProcedureDef(context);
239
+
240
+ if (Layer.isLayer(tagOrLayer)) {
241
+ const step = {
242
+ _tag: "provideLayer" as const,
243
+ layer: tagOrLayer,
244
+ };
245
+
246
+ if (def.effectHandler) {
247
+ return new EffectDecoratedProcedure(
248
+ appendEffectStep(def, step),
249
+ );
250
+ }
251
+
252
+ return new EffectDecoratedProcedure({
253
+ ...def,
254
+ middlewares: addMiddleware(
255
+ def.middlewares,
256
+ createEffectPipelineMiddleware({
257
+ effectErrorMap: state.effectErrorMap,
258
+ runtime: state.runtime,
259
+ steps: [step],
260
+ }),
261
+ ),
262
+ });
263
+ }
264
+
265
+ if (def.effectHandler) {
266
+ return new EffectDecoratedProcedure(
267
+ appendEffectStep(def, {
268
+ _tag: "provide",
269
+ provider,
270
+ tag: tagOrLayer,
271
+ }),
272
+ );
273
+ }
274
+
275
+ return new EffectDecoratedProcedure({
276
+ ...def,
277
+ middlewares: addMiddleware(
278
+ def.middlewares,
279
+ createEffectProviderMiddleware({
280
+ effectErrorMap: state.effectErrorMap,
281
+ provider,
282
+ runtime: state.runtime,
283
+ tag: tagOrLayer,
284
+ }),
285
+ ),
286
+ });
287
+ };
288
+ });
289
+ case "provideOptional":
290
+ return getOrCreateVirtualMethod(context, prop, () => {
291
+ return (tag: any, provider: any) => {
292
+ const def = getEffectProcedureDef(context);
293
+
294
+ if (def.effectHandler) {
295
+ return new EffectDecoratedProcedure(
296
+ appendEffectStep(def, {
297
+ _tag: "provideOptional",
298
+ provider,
299
+ tag,
300
+ }),
301
+ );
302
+ }
303
+
304
+ return new EffectDecoratedProcedure({
305
+ ...def,
306
+ middlewares: addMiddleware(
307
+ def.middlewares,
308
+ createEffectOptionalProviderMiddleware({
309
+ effectErrorMap: state.effectErrorMap,
310
+ provider,
311
+ runtime: state.runtime,
312
+ tag,
313
+ }),
314
+ ),
315
+ });
316
+ };
317
+ });
161
318
  case "use":
162
319
  return getOrCreateVirtualMethod(context, prop, () => {
163
320
  return (
164
321
  middleware: AnyMiddleware,
165
322
  mapInput?: MapInputMiddleware<any, any>,
166
323
  ) => {
324
+ const def = getEffectProcedureDef(context);
325
+ if (!mapInput && isEffectMiddleware(middleware)) {
326
+ return new EffectDecoratedProcedure(
327
+ appendEffectStep(def, {
328
+ _tag: "middleware",
329
+ middleware,
330
+ }),
331
+ );
332
+ }
333
+
334
+ const flushedDef = flushEffectSteps(def);
167
335
  const mapped = mapInput
168
336
  ? decorateMiddleware(middleware).mapInput(mapInput)
169
337
  : middleware;
170
338
 
171
339
  return new EffectDecoratedProcedure({
172
- ...getEffectProcedureDef(context),
173
- middlewares: addMiddleware(
174
- getEffectProcedureDef(context).middlewares,
175
- mapped,
176
- ),
340
+ ...flushedDef,
341
+ middlewares: addMiddleware(flushedDef.middlewares, mapped),
177
342
  });
178
343
  };
179
344
  });
@@ -264,6 +429,9 @@ export class EffectProcedure<
264
429
  EffectErrorMapToErrorMap<TEffectErrorMap>,
265
430
  TMeta
266
431
  > {
432
+ /**
433
+ * This property holds the defined options and the effect-specific properties.
434
+ */
267
435
  declare "~effect": EffectProcedureDef<
268
436
  TInitialContext,
269
437
  TCurrentContext,
@@ -274,6 +442,9 @@ export class EffectProcedure<
274
442
  TRequirementsProvided,
275
443
  TRuntimeError
276
444
  >;
445
+ /**
446
+ * This property holds the defined options.
447
+ */
277
448
  declare "~orpc": ProcedureDef<
278
449
  TInitialContext,
279
450
  TCurrentContext,
@@ -296,8 +467,11 @@ export class EffectProcedure<
296
467
  >,
297
468
  procedure?: AnyProcedureLike,
298
469
  ) {
299
- super(def);
300
- attachEffectState(this, procedure ?? new Procedure(def), {
470
+ const { effectSteps, effectHandler, ...procedureDef } = def;
471
+ super(procedureDef);
472
+ attachEffectState(this, procedure ?? new Procedure(procedureDef), {
473
+ effectSteps,
474
+ effectHandler,
301
475
  effectErrorMap: def.effectErrorMap,
302
476
  runtime: def.runtime,
303
477
  });
@@ -346,6 +520,12 @@ export class EffectDecoratedProcedure<
346
520
  TRuntimeError
347
521
  >
348
522
  {
523
+ /**
524
+ * Adds type-safe custom errors.
525
+ * Supports both traditional oRPC error definitions and ORPCTaggedError classes.
526
+ *
527
+ * @see {@link https://orpc.dev/docs/error-handling#type%E2%80%90safe-error-handling Type-Safe Error Handling Docs}
528
+ */
349
529
  declare errors: EffectDecoratedProcedureSurface<
350
530
  TInitialContext,
351
531
  TCurrentContext,
@@ -356,6 +536,12 @@ export class EffectDecoratedProcedure<
356
536
  TRequirementsProvided,
357
537
  TRuntimeError
358
538
  >["errors"];
539
+ /**
540
+ * Sets or updates the metadata.
541
+ * The provided metadata is spared-merged with any existing metadata.
542
+ *
543
+ * @see {@link https://orpc.dev/docs/metadata Metadata Docs}
544
+ */
359
545
  declare meta: EffectDecoratedProcedureSurface<
360
546
  TInitialContext,
361
547
  TCurrentContext,
@@ -366,6 +552,14 @@ export class EffectDecoratedProcedure<
366
552
  TRequirementsProvided,
367
553
  TRuntimeError
368
554
  >["meta"];
555
+ /**
556
+ * Sets or updates the route definition.
557
+ * The provided route is spared-merged with any existing route.
558
+ * This option is typically relevant when integrating with OpenAPI.
559
+ *
560
+ * @see {@link https://orpc.dev/docs/openapi/routing OpenAPI Routing Docs}
561
+ * @see {@link https://orpc.dev/docs/openapi/input-output-structure OpenAPI Input/Output Structure Docs}
562
+ */
369
563
  declare route: EffectDecoratedProcedureSurface<
370
564
  TInitialContext,
371
565
  TCurrentContext,
@@ -376,6 +570,40 @@ export class EffectDecoratedProcedure<
376
570
  TRequirementsProvided,
377
571
  TRuntimeError
378
572
  >["route"];
573
+ /**
574
+ * Provides a request-scoped Effect service to downstream procedures.
575
+ */
576
+ declare provide: EffectDecoratedProcedureSurface<
577
+ TInitialContext,
578
+ TCurrentContext,
579
+ TInputSchema,
580
+ TOutputSchema,
581
+ TEffectErrorMap,
582
+ TMeta,
583
+ TRequirementsProvided,
584
+ TRuntimeError
585
+ >["provide"];
586
+ /**
587
+ * Optionally provides a request-scoped Effect service to downstream procedures.
588
+ */
589
+ declare provideOptional: EffectDecoratedProcedureSurface<
590
+ TInitialContext,
591
+ TCurrentContext,
592
+ TInputSchema,
593
+ TOutputSchema,
594
+ TEffectErrorMap,
595
+ TMeta,
596
+ TRequirementsProvided,
597
+ TRuntimeError
598
+ >["provideOptional"];
599
+ /**
600
+ * Uses a middleware to modify the context or improve the pipeline.
601
+ *
602
+ * @info Supports both normal middleware and inline middleware implementations.
603
+ * @info Pass second argument to map the input.
604
+ * @note The current context must be satisfy middleware dependent-context
605
+ * @see {@link https://orpc.dev/docs/middleware Middleware Docs}
606
+ */
379
607
  declare use: EffectDecoratedProcedureSurface<
380
608
  TInitialContext,
381
609
  TCurrentContext,
@@ -386,6 +614,11 @@ export class EffectDecoratedProcedure<
386
614
  TRequirementsProvided,
387
615
  TRuntimeError
388
616
  >["use"];
617
+ /**
618
+ * Make this procedure callable (works like a function while still being a procedure).
619
+ *
620
+ * @see {@link https://orpc.dev/docs/client/server-side Server-side Client Docs}
621
+ */
389
622
  declare callable: EffectDecoratedProcedureSurface<
390
623
  TInitialContext,
391
624
  TCurrentContext,
@@ -396,6 +629,11 @@ export class EffectDecoratedProcedure<
396
629
  TRequirementsProvided,
397
630
  TRuntimeError
398
631
  >["callable"];
632
+ /**
633
+ * Make this procedure compatible with server action.
634
+ *
635
+ * @see {@link https://orpc.dev/docs/server-action Server Action Docs}
636
+ */
399
637
  declare actionable: EffectDecoratedProcedureSurface<
400
638
  TInitialContext,
401
639
  TCurrentContext,