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.
@@ -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
  });
@@ -302,8 +467,11 @@ export class EffectProcedure<
302
467
  >,
303
468
  procedure?: AnyProcedureLike,
304
469
  ) {
305
- super(def);
306
- 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,
307
475
  effectErrorMap: def.effectErrorMap,
308
476
  runtime: def.runtime,
309
477
  });
@@ -402,6 +570,32 @@ export class EffectDecoratedProcedure<
402
570
  TRequirementsProvided,
403
571
  TRuntimeError
404
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"];
405
599
  /**
406
600
  * Uses a middleware to modify the context or improve the pipeline.
407
601
  *