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.
- package/README.md +198 -77
- package/dist/{chunk-VOWRLWZZ.js → chunk-IJP6L2XR.js} +6 -2
- package/dist/chunk-IJP6L2XR.js.map +1 -0
- package/dist/index.js +736 -266
- package/dist/index.js.map +1 -1
- package/dist/node.js +4 -3
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
- package/src/contract.ts +34 -2
- package/src/effect-builder.ts +452 -18
- package/src/effect-procedure.ts +247 -9
- package/src/effect-runtime.ts +453 -21
- package/src/extension/create-node-proxy.ts +17 -1
- package/src/extension/state.ts +13 -15
- package/src/fiber-context-bridge.ts +13 -0
- package/src/node.ts +2 -1
- package/src/runtime-source.ts +18 -0
- package/src/tagged-error.ts +0 -9
- package/src/tests/contract.test.ts +24 -0
- package/src/tests/effect-builder.test.ts +506 -3
- package/src/tests/node-side-effect.test.ts +80 -0
- package/src/tests/parity.effect-builder.test.ts +10 -3
- package/src/tests/parity.effect-procedure.test.ts +24 -8
- package/src/tests/shared.ts +1 -25
- package/src/types/effect-builder-surface.ts +116 -0
- package/src/types/effect-procedure-surface.ts +98 -1
- package/src/types/index.ts +292 -1
- package/src/types/variants.ts +346 -13
- package/dist/chunk-VOWRLWZZ.js.map +0 -1
package/src/effect-procedure.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
...
|
|
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
|
-
|
|
300
|
-
|
|
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,
|