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.
- 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 +277 -24
- package/src/effect-procedure.ts +203 -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/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
getCurrentFiberRefs
|
|
3
|
-
|
|
2
|
+
getCurrentFiberRefs,
|
|
3
|
+
runWithFiberRefs
|
|
4
|
+
} from "./chunk-IJP6L2XR.js";
|
|
4
5
|
|
|
5
6
|
// src/contract.ts
|
|
6
7
|
import { isContractProcedure as isContractProcedure2 } from "@orpc/contract";
|
|
@@ -8,6 +9,7 @@ import { implement } from "@orpc/server";
|
|
|
8
9
|
|
|
9
10
|
// src/effect-builder.ts
|
|
10
11
|
import { Builder, fallbackConfig, lazy as lazy2 } from "@orpc/server";
|
|
12
|
+
import { Layer as Layer3 } from "effect";
|
|
11
13
|
|
|
12
14
|
// src/effect-enhance-router.ts
|
|
13
15
|
import {
|
|
@@ -27,12 +29,433 @@ import {
|
|
|
27
29
|
// src/effect-procedure.ts
|
|
28
30
|
import { mergeMeta, mergeRoute } from "@orpc/contract";
|
|
29
31
|
import {
|
|
32
|
+
Procedure,
|
|
30
33
|
addMiddleware,
|
|
31
34
|
createActionableClient,
|
|
32
35
|
createProcedureClient,
|
|
33
|
-
decorateMiddleware
|
|
34
|
-
Procedure
|
|
36
|
+
decorateMiddleware
|
|
35
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, FiberRefs, Option } from "effect";
|
|
43
|
+
|
|
44
|
+
// src/tagged-error.ts
|
|
45
|
+
import {
|
|
46
|
+
fallbackORPCErrorMessage,
|
|
47
|
+
fallbackORPCErrorStatus,
|
|
48
|
+
isORPCErrorStatus,
|
|
49
|
+
ORPCError
|
|
50
|
+
} from "@orpc/client";
|
|
51
|
+
import { resolveMaybeOptionalOptions } from "@orpc/shared";
|
|
52
|
+
import "effect/Cause";
|
|
53
|
+
import * as Data from "effect/Data";
|
|
54
|
+
var ORPCErrorSymbol = /* @__PURE__ */ Symbol.for(
|
|
55
|
+
"@orpc/effect/ORPCTaggedError"
|
|
56
|
+
);
|
|
57
|
+
function isORPCTaggedErrorClass(value) {
|
|
58
|
+
return typeof value === "function" && "_tag" in value && "code" in value && typeof value._tag === "string" && typeof value.code === "string";
|
|
59
|
+
}
|
|
60
|
+
function isORPCTaggedError(value) {
|
|
61
|
+
return typeof value === "object" && value !== null && ORPCErrorSymbol in value;
|
|
62
|
+
}
|
|
63
|
+
function toConstantCase(str) {
|
|
64
|
+
return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toUpperCase();
|
|
65
|
+
}
|
|
66
|
+
function ORPCTaggedError(tag, props) {
|
|
67
|
+
const code = props?.code ?? toConstantCase(tag);
|
|
68
|
+
class ORPCTaggedErrorBase extends Data.TaggedError(tag) {
|
|
69
|
+
status;
|
|
70
|
+
defined;
|
|
71
|
+
data;
|
|
72
|
+
code = code;
|
|
73
|
+
schema = props?.schema;
|
|
74
|
+
[ORPCErrorSymbol];
|
|
75
|
+
constructor(...rest) {
|
|
76
|
+
super();
|
|
77
|
+
const opts = resolveMaybeOptionalOptions(rest);
|
|
78
|
+
const status = opts.status ?? props?.status;
|
|
79
|
+
if (status !== void 0 && !isORPCErrorStatus(status)) {
|
|
80
|
+
throw new globalThis.Error(
|
|
81
|
+
"[ORPCTaggedError] Invalid error status code."
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
this.status = fallbackORPCErrorStatus(code, status);
|
|
85
|
+
this.defined = opts.defined ?? true;
|
|
86
|
+
this.data = opts.data;
|
|
87
|
+
this.message = fallbackORPCErrorMessage(
|
|
88
|
+
this.code,
|
|
89
|
+
opts.message ?? props?.message
|
|
90
|
+
);
|
|
91
|
+
this.cause = opts.cause;
|
|
92
|
+
this[ORPCErrorSymbol] = new ORPCError(
|
|
93
|
+
this.code,
|
|
94
|
+
{
|
|
95
|
+
status: this.status,
|
|
96
|
+
message: this.message,
|
|
97
|
+
data: this.data,
|
|
98
|
+
defined: this.defined,
|
|
99
|
+
cause: this.cause
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Converts this error to a plain ORPCError.
|
|
105
|
+
* Useful when you need to return from an oRPC handler.
|
|
106
|
+
*/
|
|
107
|
+
toORPCError() {
|
|
108
|
+
return this[ORPCErrorSymbol];
|
|
109
|
+
}
|
|
110
|
+
toJSON() {
|
|
111
|
+
return {
|
|
112
|
+
_tag: this._tag,
|
|
113
|
+
defined: this[ORPCErrorSymbol].defined,
|
|
114
|
+
code: this[ORPCErrorSymbol].code,
|
|
115
|
+
status: this[ORPCErrorSymbol].status,
|
|
116
|
+
message: this[ORPCErrorSymbol].message,
|
|
117
|
+
data: this[ORPCErrorSymbol].data
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return Object.assign(ORPCTaggedErrorBase, {
|
|
122
|
+
_tag: tag,
|
|
123
|
+
code
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function toORPCError(error) {
|
|
127
|
+
return error[ORPCErrorSymbol];
|
|
128
|
+
}
|
|
129
|
+
function createEffectErrorConstructorMap(errors) {
|
|
130
|
+
const target = errors ?? {};
|
|
131
|
+
const proxy = new Proxy(target, {
|
|
132
|
+
get(proxyTarget, code) {
|
|
133
|
+
if (typeof code !== "string") {
|
|
134
|
+
return Reflect.get(proxyTarget, code);
|
|
135
|
+
}
|
|
136
|
+
const config = target[code];
|
|
137
|
+
if (isORPCTaggedErrorClass(config)) {
|
|
138
|
+
return (...opts) => new config(...opts);
|
|
139
|
+
}
|
|
140
|
+
return (...rest) => {
|
|
141
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
142
|
+
return new ORPCError(code, {
|
|
143
|
+
defined: Boolean(config),
|
|
144
|
+
status: config?.status,
|
|
145
|
+
message: options.message ?? config?.message,
|
|
146
|
+
data: options.data,
|
|
147
|
+
cause: options.cause
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
return proxy;
|
|
153
|
+
}
|
|
154
|
+
function effectErrorMapToErrorMap(errorMap) {
|
|
155
|
+
const result = {};
|
|
156
|
+
if (!errorMap) {
|
|
157
|
+
return result;
|
|
158
|
+
}
|
|
159
|
+
for (const [code, ClassOrErrorItem] of Object.entries(errorMap)) {
|
|
160
|
+
if (!ClassOrErrorItem) {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (isORPCTaggedErrorClass(ClassOrErrorItem)) {
|
|
164
|
+
const classInstance = new ClassOrErrorItem();
|
|
165
|
+
result[classInstance.code] = {
|
|
166
|
+
status: classInstance.status,
|
|
167
|
+
message: classInstance.message,
|
|
168
|
+
data: classInstance.schema
|
|
169
|
+
};
|
|
170
|
+
} else {
|
|
171
|
+
result[code] = ClassOrErrorItem;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/effect-runtime.ts
|
|
178
|
+
function toORPCErrorFromCause(cause) {
|
|
179
|
+
return Cause2.match(cause, {
|
|
180
|
+
onDie(defect) {
|
|
181
|
+
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
182
|
+
cause: defect
|
|
183
|
+
});
|
|
184
|
+
},
|
|
185
|
+
onFail(error) {
|
|
186
|
+
if (isORPCTaggedError(error)) {
|
|
187
|
+
return error.toORPCError();
|
|
188
|
+
}
|
|
189
|
+
if (error instanceof ORPCError2) {
|
|
190
|
+
return error;
|
|
191
|
+
}
|
|
192
|
+
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
193
|
+
cause: error
|
|
194
|
+
});
|
|
195
|
+
},
|
|
196
|
+
onInterrupt(fiberId) {
|
|
197
|
+
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
198
|
+
cause: new Error(`${fiberId} Interrupted`)
|
|
199
|
+
});
|
|
200
|
+
},
|
|
201
|
+
onSequential(left) {
|
|
202
|
+
return left;
|
|
203
|
+
},
|
|
204
|
+
onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
205
|
+
cause: new Error("Unknown error")
|
|
206
|
+
}),
|
|
207
|
+
onParallel(left) {
|
|
208
|
+
return left;
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
function createEffectProcedureHandler(options) {
|
|
213
|
+
const {
|
|
214
|
+
runtime,
|
|
215
|
+
effectErrorMap,
|
|
216
|
+
effectFn,
|
|
217
|
+
effectSteps = [],
|
|
218
|
+
spanConfig,
|
|
219
|
+
defaultCaptureStackTrace
|
|
220
|
+
} = options;
|
|
221
|
+
return async (opts) => {
|
|
222
|
+
const effectOpts = {
|
|
223
|
+
context: opts.context,
|
|
224
|
+
input: opts.input,
|
|
225
|
+
path: opts.path,
|
|
226
|
+
procedure: opts.procedure,
|
|
227
|
+
signal: opts.signal,
|
|
228
|
+
lastEventId: opts.lastEventId,
|
|
229
|
+
errors: createEffectErrorConstructorMap(effectErrorMap)
|
|
230
|
+
};
|
|
231
|
+
const spanName = spanConfig?.name ?? opts.path.join(".");
|
|
232
|
+
const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
|
|
233
|
+
const resolver = Effect.fnUntraced(effectFn);
|
|
234
|
+
const handlerEffect = resolver(effectOpts);
|
|
235
|
+
const tracedEffect = Effect.withSpan(
|
|
236
|
+
runEffectPipeline({
|
|
237
|
+
baseOptions: effectOpts,
|
|
238
|
+
effectErrorMap,
|
|
239
|
+
final: (context) => Effect.map(
|
|
240
|
+
context === effectOpts.context ? handlerEffect : resolver({ ...effectOpts, context }),
|
|
241
|
+
(output) => ({ output, context: {} })
|
|
242
|
+
),
|
|
243
|
+
input: opts.input,
|
|
244
|
+
steps: effectSteps
|
|
245
|
+
}),
|
|
246
|
+
spanName,
|
|
247
|
+
{ captureStackTrace }
|
|
248
|
+
);
|
|
249
|
+
const exit = await runtime.runPromiseExit(
|
|
250
|
+
withParentFiberRefs(tracedEffect),
|
|
251
|
+
{ signal: opts.signal }
|
|
252
|
+
);
|
|
253
|
+
if (Exit.isFailure(exit)) {
|
|
254
|
+
throw toORPCErrorFromCause(exit.cause);
|
|
255
|
+
}
|
|
256
|
+
return exit.value.output;
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function createEffectPipelineMiddleware(options) {
|
|
260
|
+
const { runtime, effectErrorMap, steps } = options;
|
|
261
|
+
return async (opts, input) => {
|
|
262
|
+
const baseOptions = makeEffectOptions(opts, input, effectErrorMap);
|
|
263
|
+
const effect = runEffectPipeline({
|
|
264
|
+
baseOptions,
|
|
265
|
+
effectErrorMap,
|
|
266
|
+
final: (context) => withCurrentFiberContext(
|
|
267
|
+
() => opts.next(
|
|
268
|
+
context === opts.context ? void 0 : { context }
|
|
269
|
+
)
|
|
270
|
+
),
|
|
271
|
+
input,
|
|
272
|
+
steps
|
|
273
|
+
});
|
|
274
|
+
const exit = await runtime.runPromiseExit(
|
|
275
|
+
withParentFiberRefs(effect),
|
|
276
|
+
{ signal: opts.signal }
|
|
277
|
+
);
|
|
278
|
+
if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
|
|
279
|
+
return exit.value;
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
function createEffectProviderMiddleware(options) {
|
|
283
|
+
const { runtime, effectErrorMap, tag, provider } = options;
|
|
284
|
+
return async (opts, input) => {
|
|
285
|
+
const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
|
|
286
|
+
const effect = Effect.flatMap(
|
|
287
|
+
provider(effectOpts),
|
|
288
|
+
(service) => Effect.provideService(
|
|
289
|
+
withCurrentFiberContext(() => opts.next()),
|
|
290
|
+
tag,
|
|
291
|
+
service
|
|
292
|
+
)
|
|
293
|
+
);
|
|
294
|
+
const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
|
|
295
|
+
signal: opts.signal
|
|
296
|
+
});
|
|
297
|
+
if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
|
|
298
|
+
return exit.value;
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function createEffectOptionalProviderMiddleware(options) {
|
|
302
|
+
const { runtime, effectErrorMap, tag, provider } = options;
|
|
303
|
+
return async (opts, input) => {
|
|
304
|
+
const effectOpts = makeEffectOptions(opts, input, effectErrorMap);
|
|
305
|
+
const effect = Effect.flatMap(
|
|
306
|
+
provider(effectOpts),
|
|
307
|
+
(service) => Option.match(service, {
|
|
308
|
+
onNone: () => withCurrentFiberContext(() => opts.next()),
|
|
309
|
+
onSome: (value) => Effect.provideService(
|
|
310
|
+
withCurrentFiberContext(() => opts.next()),
|
|
311
|
+
tag,
|
|
312
|
+
value
|
|
313
|
+
)
|
|
314
|
+
})
|
|
315
|
+
);
|
|
316
|
+
const exit = await runtime.runPromiseExit(withParentFiberRefs(effect), {
|
|
317
|
+
signal: opts.signal
|
|
318
|
+
});
|
|
319
|
+
if (Exit.isFailure(exit)) throw toORPCErrorFromCause(exit.cause);
|
|
320
|
+
return exit.value;
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function isEffectMiddleware(value) {
|
|
324
|
+
return typeof value === "function" && value.constructor?.name === "GeneratorFunction";
|
|
325
|
+
}
|
|
326
|
+
function makeEffectOptions(opts, input, effectErrorMap) {
|
|
327
|
+
return {
|
|
328
|
+
context: opts.context,
|
|
329
|
+
input,
|
|
330
|
+
path: opts.path,
|
|
331
|
+
procedure: opts.procedure,
|
|
332
|
+
signal: opts.signal,
|
|
333
|
+
lastEventId: opts.lastEventId,
|
|
334
|
+
errors: createEffectErrorConstructorMap(effectErrorMap)
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function runEffectPipeline(options) {
|
|
338
|
+
const run = (index, context) => {
|
|
339
|
+
const step = options.steps[index];
|
|
340
|
+
if (!step) return options.final(context);
|
|
341
|
+
const stepOptions = { ...options.baseOptions, context };
|
|
342
|
+
if (step._tag === "provide") {
|
|
343
|
+
return Effect.flatMap(
|
|
344
|
+
step.provider(stepOptions),
|
|
345
|
+
(service) => Effect.provideService(run(index + 1, context), step.tag, service)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (step._tag === "provideOptional") {
|
|
349
|
+
return Effect.flatMap(
|
|
350
|
+
step.provider(stepOptions),
|
|
351
|
+
(service) => Option.match(service, {
|
|
352
|
+
onNone: () => run(index + 1, context),
|
|
353
|
+
onSome: (value) => Effect.provideService(run(index + 1, context), step.tag, value)
|
|
354
|
+
})
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
if (step._tag === "provideLayer") {
|
|
358
|
+
return Effect.provide(run(index + 1, context), step.layer);
|
|
359
|
+
}
|
|
360
|
+
const nextTracker = createMiddlewareNextTracker();
|
|
361
|
+
const effectOptions = {
|
|
362
|
+
context,
|
|
363
|
+
path: stepOptions.path,
|
|
364
|
+
procedure: stepOptions.procedure,
|
|
365
|
+
signal: stepOptions.signal,
|
|
366
|
+
lastEventId: stepOptions.lastEventId,
|
|
367
|
+
errors: createEffectErrorConstructorMap(options.effectErrorMap),
|
|
368
|
+
next: nextTracker.wrapNext(
|
|
369
|
+
(...rest) => {
|
|
370
|
+
const nextContext = rest[0]?.context ?? {};
|
|
371
|
+
return Effect.map(
|
|
372
|
+
run(index + 1, { ...context, ...nextContext }),
|
|
373
|
+
(result) => ({
|
|
374
|
+
output: result.output,
|
|
375
|
+
context: nextContext
|
|
376
|
+
})
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
)
|
|
380
|
+
};
|
|
381
|
+
const effectOutput = makeEffectMiddlewareOutput((output) => ({ output, context: {} }));
|
|
382
|
+
const middlewareEffect = Effect.fnUntraced(step.middleware)(
|
|
383
|
+
effectOptions,
|
|
384
|
+
options.input,
|
|
385
|
+
effectOutput
|
|
386
|
+
);
|
|
387
|
+
return Effect.flatMap(
|
|
388
|
+
middlewareEffect,
|
|
389
|
+
(result) => resolveEffectMiddlewareContinuation({
|
|
390
|
+
autoNext: () => effectOptions.next(),
|
|
391
|
+
nextInvoked: nextTracker.nextInvoked,
|
|
392
|
+
nextResult: nextTracker.nextResult,
|
|
393
|
+
result
|
|
394
|
+
})
|
|
395
|
+
);
|
|
396
|
+
};
|
|
397
|
+
return run(0, options.baseOptions.context);
|
|
398
|
+
}
|
|
399
|
+
function createMiddlewareNextTracker() {
|
|
400
|
+
let nextInvoked = false;
|
|
401
|
+
let nextResult;
|
|
402
|
+
return {
|
|
403
|
+
get nextInvoked() {
|
|
404
|
+
return nextInvoked;
|
|
405
|
+
},
|
|
406
|
+
get nextResult() {
|
|
407
|
+
return nextResult;
|
|
408
|
+
},
|
|
409
|
+
wrapNext(nextFn) {
|
|
410
|
+
return ((...args) => {
|
|
411
|
+
nextInvoked = true;
|
|
412
|
+
return Effect.map(nextFn(...args), (result) => {
|
|
413
|
+
nextResult = result;
|
|
414
|
+
return result;
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
function resolveEffectMiddlewareContinuation(options) {
|
|
421
|
+
const { result, nextInvoked, nextResult, autoNext } = options;
|
|
422
|
+
if (result !== void 0) {
|
|
423
|
+
return Effect.succeed(result);
|
|
424
|
+
}
|
|
425
|
+
if (nextInvoked) {
|
|
426
|
+
if (nextResult === void 0) {
|
|
427
|
+
return Effect.die(
|
|
428
|
+
new Error(
|
|
429
|
+
"Effect middleware invoked next() but did not return its result"
|
|
430
|
+
)
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return Effect.succeed(nextResult);
|
|
434
|
+
}
|
|
435
|
+
return autoNext();
|
|
436
|
+
}
|
|
437
|
+
function makeEffectMiddlewareOutput(output) {
|
|
438
|
+
return (value) => withCurrentFiberContext(() => output(value));
|
|
439
|
+
}
|
|
440
|
+
function withCurrentFiberContext(fn) {
|
|
441
|
+
return Effect.flatMap(
|
|
442
|
+
Effect.getFiberRefs,
|
|
443
|
+
(fiberRefs) => Effect.promise(
|
|
444
|
+
() => runWithFiberRefs(fiberRefs, () => Promise.resolve(fn()))
|
|
445
|
+
)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
function withParentFiberRefs(effect) {
|
|
449
|
+
const parentFiberRefs = getCurrentFiberRefs();
|
|
450
|
+
return parentFiberRefs ? Effect.fiberIdWith(
|
|
451
|
+
(fiberId) => Effect.flatMap(
|
|
452
|
+
Effect.getFiberRefs,
|
|
453
|
+
(fiberRefs) => Effect.setFiberRefs(
|
|
454
|
+
FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
|
|
455
|
+
).pipe(Effect.andThen(effect))
|
|
456
|
+
)
|
|
457
|
+
) : effect;
|
|
458
|
+
}
|
|
36
459
|
|
|
37
460
|
// src/extension/compose-surfaces.ts
|
|
38
461
|
function composeSurfaceProxy(surface, target) {
|
|
@@ -98,7 +521,8 @@ function createBoundMethod(context, prop, value, config, receiver) {
|
|
|
98
521
|
return cache.get(prop);
|
|
99
522
|
}
|
|
100
523
|
const wrapped = (...args) => {
|
|
101
|
-
const
|
|
524
|
+
const nextArgs = config.wrapArgs?.(context, prop, args, receiver) ?? args;
|
|
525
|
+
const result = Reflect.apply(value, context.upstream, nextArgs);
|
|
102
526
|
return config.wrapResult?.(context, prop, result, receiver) ?? result;
|
|
103
527
|
};
|
|
104
528
|
cache.set(prop, wrapped);
|
|
@@ -159,183 +583,50 @@ function createNodeProxy(target, config) {
|
|
|
159
583
|
keys.add(key);
|
|
160
584
|
}
|
|
161
585
|
for (const key of virtualKeys) {
|
|
162
|
-
keys.add(key);
|
|
163
|
-
}
|
|
164
|
-
return [...keys];
|
|
165
|
-
},
|
|
166
|
-
getOwnPropertyDescriptor(currentTarget, prop) {
|
|
167
|
-
const context = createNodeProxyContext(
|
|
168
|
-
currentTarget
|
|
169
|
-
);
|
|
170
|
-
if (virtualKeys.has(prop)) {
|
|
171
|
-
const value = config.getVirtual?.(context, prop, currentTarget);
|
|
172
|
-
if (value !== void 0 && value !== unhandledProperty) {
|
|
173
|
-
return {
|
|
174
|
-
configurable: true,
|
|
175
|
-
enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
|
|
176
|
-
value,
|
|
177
|
-
writable: false
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const descriptor = Reflect.getOwnPropertyDescriptor(
|
|
182
|
-
context.upstream,
|
|
183
|
-
prop
|
|
184
|
-
);
|
|
185
|
-
if (descriptor === void 0) {
|
|
186
|
-
return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
|
|
187
|
-
}
|
|
188
|
-
if ("value" in descriptor && typeof descriptor.value === "function") {
|
|
189
|
-
return {
|
|
190
|
-
...descriptor,
|
|
191
|
-
value: createBoundMethod(
|
|
192
|
-
context,
|
|
193
|
-
prop,
|
|
194
|
-
descriptor.value,
|
|
195
|
-
config,
|
|
196
|
-
currentTarget
|
|
197
|
-
)
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
return descriptor;
|
|
201
|
-
}
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
function unhandled() {
|
|
205
|
-
return unhandledProperty;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// src/tagged-error.ts
|
|
209
|
-
import {
|
|
210
|
-
fallbackORPCErrorMessage,
|
|
211
|
-
fallbackORPCErrorStatus,
|
|
212
|
-
isORPCErrorStatus,
|
|
213
|
-
ORPCError
|
|
214
|
-
} from "@orpc/client";
|
|
215
|
-
import { resolveMaybeOptionalOptions } from "@orpc/shared";
|
|
216
|
-
import "effect/Cause";
|
|
217
|
-
import * as Data from "effect/Data";
|
|
218
|
-
var ORPCErrorSymbol = /* @__PURE__ */ Symbol.for(
|
|
219
|
-
"@orpc/effect/ORPCTaggedError"
|
|
220
|
-
);
|
|
221
|
-
function isORPCTaggedErrorClass(value) {
|
|
222
|
-
return typeof value === "function" && "_tag" in value && "code" in value && typeof value._tag === "string" && typeof value.code === "string";
|
|
223
|
-
}
|
|
224
|
-
function isORPCTaggedError(value) {
|
|
225
|
-
return typeof value === "object" && value !== null && ORPCErrorSymbol in value;
|
|
226
|
-
}
|
|
227
|
-
function toConstantCase(str) {
|
|
228
|
-
return str.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/([A-Z])([A-Z][a-z])/g, "$1_$2").toUpperCase();
|
|
229
|
-
}
|
|
230
|
-
function ORPCTaggedError(tag, props) {
|
|
231
|
-
const code = props?.code ?? toConstantCase(tag);
|
|
232
|
-
class ORPCTaggedErrorBase extends Data.TaggedError(tag) {
|
|
233
|
-
status;
|
|
234
|
-
defined;
|
|
235
|
-
data;
|
|
236
|
-
code = code;
|
|
237
|
-
schema = props?.schema;
|
|
238
|
-
[ORPCErrorSymbol];
|
|
239
|
-
constructor(...rest) {
|
|
240
|
-
super();
|
|
241
|
-
const opts = resolveMaybeOptionalOptions(rest);
|
|
242
|
-
const status = opts.status ?? props?.status;
|
|
243
|
-
if (status !== void 0 && !isORPCErrorStatus(status)) {
|
|
244
|
-
throw new globalThis.Error(
|
|
245
|
-
"[ORPCTaggedError] Invalid error status code."
|
|
246
|
-
);
|
|
247
|
-
}
|
|
248
|
-
this.status = fallbackORPCErrorStatus(code, status);
|
|
249
|
-
this.defined = opts.defined ?? true;
|
|
250
|
-
this.data = opts.data;
|
|
251
|
-
this.message = fallbackORPCErrorMessage(
|
|
252
|
-
this.code,
|
|
253
|
-
opts.message ?? props?.message
|
|
586
|
+
keys.add(key);
|
|
587
|
+
}
|
|
588
|
+
return [...keys];
|
|
589
|
+
},
|
|
590
|
+
getOwnPropertyDescriptor(currentTarget, prop) {
|
|
591
|
+
const context = createNodeProxyContext(
|
|
592
|
+
currentTarget
|
|
254
593
|
);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
594
|
+
if (virtualKeys.has(prop)) {
|
|
595
|
+
const value = config.getVirtual?.(context, prop, currentTarget);
|
|
596
|
+
if (value !== void 0 && value !== unhandledProperty) {
|
|
597
|
+
return {
|
|
598
|
+
configurable: true,
|
|
599
|
+
enumerable: config.virtualDescriptors?.[prop]?.enumerable ?? false,
|
|
600
|
+
value,
|
|
601
|
+
writable: false
|
|
602
|
+
};
|
|
264
603
|
}
|
|
604
|
+
}
|
|
605
|
+
const descriptor = Reflect.getOwnPropertyDescriptor(
|
|
606
|
+
context.upstream,
|
|
607
|
+
prop
|
|
265
608
|
);
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
* Converts this error to a plain ORPCError.
|
|
269
|
-
* Useful when you need to return from an oRPC handler.
|
|
270
|
-
*/
|
|
271
|
-
toORPCError() {
|
|
272
|
-
return this[ORPCErrorSymbol];
|
|
273
|
-
}
|
|
274
|
-
toJSON() {
|
|
275
|
-
return {
|
|
276
|
-
_tag: this._tag,
|
|
277
|
-
defined: this[ORPCErrorSymbol].defined,
|
|
278
|
-
code: this[ORPCErrorSymbol].code,
|
|
279
|
-
status: this[ORPCErrorSymbol].status,
|
|
280
|
-
message: this[ORPCErrorSymbol].message,
|
|
281
|
-
data: this[ORPCErrorSymbol].data
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return Object.assign(ORPCTaggedErrorBase, {
|
|
286
|
-
_tag: tag,
|
|
287
|
-
code
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
function toORPCError(error) {
|
|
291
|
-
return error[ORPCErrorSymbol];
|
|
292
|
-
}
|
|
293
|
-
function createEffectErrorConstructorMap(errors) {
|
|
294
|
-
const target = errors ?? {};
|
|
295
|
-
const proxy = new Proxy(target, {
|
|
296
|
-
get(proxyTarget, code) {
|
|
297
|
-
if (typeof code !== "string") {
|
|
298
|
-
return Reflect.get(proxyTarget, code);
|
|
609
|
+
if (descriptor === void 0) {
|
|
610
|
+
return Reflect.getOwnPropertyDescriptor(currentTarget, prop);
|
|
299
611
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
612
|
+
if ("value" in descriptor && typeof descriptor.value === "function") {
|
|
613
|
+
return {
|
|
614
|
+
...descriptor,
|
|
615
|
+
value: createBoundMethod(
|
|
616
|
+
context,
|
|
617
|
+
prop,
|
|
618
|
+
descriptor.value,
|
|
619
|
+
config,
|
|
620
|
+
currentTarget
|
|
621
|
+
)
|
|
622
|
+
};
|
|
303
623
|
}
|
|
304
|
-
return
|
|
305
|
-
const options = resolveMaybeOptionalOptions(rest);
|
|
306
|
-
return new ORPCError(code, {
|
|
307
|
-
defined: Boolean(config),
|
|
308
|
-
status: config?.status,
|
|
309
|
-
message: options.message ?? config?.message,
|
|
310
|
-
data: options.data,
|
|
311
|
-
cause: options.cause
|
|
312
|
-
});
|
|
313
|
-
};
|
|
624
|
+
return descriptor;
|
|
314
625
|
}
|
|
315
626
|
});
|
|
316
|
-
return proxy;
|
|
317
627
|
}
|
|
318
|
-
function
|
|
319
|
-
|
|
320
|
-
if (!errorMap) {
|
|
321
|
-
return result;
|
|
322
|
-
}
|
|
323
|
-
for (const [code, ClassOrErrorItem] of Object.entries(errorMap)) {
|
|
324
|
-
if (!ClassOrErrorItem) {
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
if (isORPCTaggedErrorClass(ClassOrErrorItem)) {
|
|
328
|
-
const classInstance = new ClassOrErrorItem();
|
|
329
|
-
result[classInstance.code] = {
|
|
330
|
-
status: classInstance.status,
|
|
331
|
-
message: classInstance.message,
|
|
332
|
-
data: classInstance.schema
|
|
333
|
-
};
|
|
334
|
-
} else {
|
|
335
|
-
result[code] = ClassOrErrorItem;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return result;
|
|
628
|
+
function unhandled() {
|
|
629
|
+
return unhandledProperty;
|
|
339
630
|
}
|
|
340
631
|
|
|
341
632
|
// src/effect-procedure.ts
|
|
@@ -345,6 +636,8 @@ var procedureVirtualDescriptors = {
|
|
|
345
636
|
callable: { enumerable: false },
|
|
346
637
|
errors: { enumerable: false },
|
|
347
638
|
meta: { enumerable: false },
|
|
639
|
+
provide: { enumerable: false },
|
|
640
|
+
provideOptional: { enumerable: false },
|
|
348
641
|
route: { enumerable: false },
|
|
349
642
|
use: { enumerable: false }
|
|
350
643
|
};
|
|
@@ -353,6 +646,8 @@ var decoratedProcedureVirtualKeys = [
|
|
|
353
646
|
...baseProcedureVirtualKeys,
|
|
354
647
|
"errors",
|
|
355
648
|
"meta",
|
|
649
|
+
"provide",
|
|
650
|
+
"provideOptional",
|
|
356
651
|
"route",
|
|
357
652
|
"use",
|
|
358
653
|
"callable",
|
|
@@ -370,10 +665,52 @@ function getOrCreateVirtualMethod(context, prop, factory) {
|
|
|
370
665
|
function getEffectProcedureDef(context) {
|
|
371
666
|
return {
|
|
372
667
|
...context.upstream["~orpc"],
|
|
668
|
+
effectSteps: context.state.effectSteps,
|
|
669
|
+
effectHandler: context.state.effectHandler,
|
|
373
670
|
effectErrorMap: context.state.effectErrorMap,
|
|
374
671
|
runtime: context.state.runtime
|
|
375
672
|
};
|
|
376
673
|
}
|
|
674
|
+
function makeEffectProcedureHandler(def) {
|
|
675
|
+
if (!def.effectHandler) {
|
|
676
|
+
return def.handler;
|
|
677
|
+
}
|
|
678
|
+
return createEffectProcedureHandler({
|
|
679
|
+
defaultCaptureStackTrace: def.effectHandler.defaultCaptureStackTrace,
|
|
680
|
+
effectErrorMap: def.effectErrorMap,
|
|
681
|
+
effectFn: def.effectHandler.effectFn,
|
|
682
|
+
effectSteps: def.effectSteps,
|
|
683
|
+
runtime: def.runtime,
|
|
684
|
+
spanConfig: def.effectHandler.spanConfig
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
function withRebuiltEffectHandler(def) {
|
|
688
|
+
return {
|
|
689
|
+
...def,
|
|
690
|
+
handler: makeEffectProcedureHandler(def)
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function appendEffectStep(def, step) {
|
|
694
|
+
return withRebuiltEffectHandler({
|
|
695
|
+
...def,
|
|
696
|
+
effectSteps: [...def.effectSteps ?? [], step]
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
function flushEffectSteps(def) {
|
|
700
|
+
if (!def.effectSteps?.length) {
|
|
701
|
+
return def;
|
|
702
|
+
}
|
|
703
|
+
const middleware = createEffectPipelineMiddleware({
|
|
704
|
+
effectErrorMap: def.effectErrorMap,
|
|
705
|
+
runtime: def.runtime,
|
|
706
|
+
steps: def.effectSteps
|
|
707
|
+
});
|
|
708
|
+
return withRebuiltEffectHandler({
|
|
709
|
+
...def,
|
|
710
|
+
effectSteps: void 0,
|
|
711
|
+
middlewares: addMiddleware(def.middlewares, middleware)
|
|
712
|
+
});
|
|
713
|
+
}
|
|
377
714
|
function createEffectProcedureProxy(target, decorated) {
|
|
378
715
|
return createNodeProxy(target, {
|
|
379
716
|
getVirtual(context, prop, receiver) {
|
|
@@ -413,16 +750,99 @@ function createEffectProcedureProxy(target, decorated) {
|
|
|
413
750
|
route: mergeRoute(getEffectProcedureDef(context).route, route)
|
|
414
751
|
});
|
|
415
752
|
});
|
|
753
|
+
case "provide":
|
|
754
|
+
return getOrCreateVirtualMethod(context, prop, () => {
|
|
755
|
+
return (tagOrLayer, provider) => {
|
|
756
|
+
const def = getEffectProcedureDef(context);
|
|
757
|
+
if (Layer.isLayer(tagOrLayer)) {
|
|
758
|
+
const step = {
|
|
759
|
+
_tag: "provideLayer",
|
|
760
|
+
layer: tagOrLayer
|
|
761
|
+
};
|
|
762
|
+
if (def.effectHandler) {
|
|
763
|
+
return new EffectDecoratedProcedure(
|
|
764
|
+
appendEffectStep(def, step)
|
|
765
|
+
);
|
|
766
|
+
}
|
|
767
|
+
return new EffectDecoratedProcedure({
|
|
768
|
+
...def,
|
|
769
|
+
middlewares: addMiddleware(
|
|
770
|
+
def.middlewares,
|
|
771
|
+
createEffectPipelineMiddleware({
|
|
772
|
+
effectErrorMap: state.effectErrorMap,
|
|
773
|
+
runtime: state.runtime,
|
|
774
|
+
steps: [step]
|
|
775
|
+
})
|
|
776
|
+
)
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
if (def.effectHandler) {
|
|
780
|
+
return new EffectDecoratedProcedure(
|
|
781
|
+
appendEffectStep(def, {
|
|
782
|
+
_tag: "provide",
|
|
783
|
+
provider,
|
|
784
|
+
tag: tagOrLayer
|
|
785
|
+
})
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
return new EffectDecoratedProcedure({
|
|
789
|
+
...def,
|
|
790
|
+
middlewares: addMiddleware(
|
|
791
|
+
def.middlewares,
|
|
792
|
+
createEffectProviderMiddleware({
|
|
793
|
+
effectErrorMap: state.effectErrorMap,
|
|
794
|
+
provider,
|
|
795
|
+
runtime: state.runtime,
|
|
796
|
+
tag: tagOrLayer
|
|
797
|
+
})
|
|
798
|
+
)
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
});
|
|
802
|
+
case "provideOptional":
|
|
803
|
+
return getOrCreateVirtualMethod(context, prop, () => {
|
|
804
|
+
return (tag, provider) => {
|
|
805
|
+
const def = getEffectProcedureDef(context);
|
|
806
|
+
if (def.effectHandler) {
|
|
807
|
+
return new EffectDecoratedProcedure(
|
|
808
|
+
appendEffectStep(def, {
|
|
809
|
+
_tag: "provideOptional",
|
|
810
|
+
provider,
|
|
811
|
+
tag
|
|
812
|
+
})
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
return new EffectDecoratedProcedure({
|
|
816
|
+
...def,
|
|
817
|
+
middlewares: addMiddleware(
|
|
818
|
+
def.middlewares,
|
|
819
|
+
createEffectOptionalProviderMiddleware({
|
|
820
|
+
effectErrorMap: state.effectErrorMap,
|
|
821
|
+
provider,
|
|
822
|
+
runtime: state.runtime,
|
|
823
|
+
tag
|
|
824
|
+
})
|
|
825
|
+
)
|
|
826
|
+
});
|
|
827
|
+
};
|
|
828
|
+
});
|
|
416
829
|
case "use":
|
|
417
830
|
return getOrCreateVirtualMethod(context, prop, () => {
|
|
418
831
|
return (middleware, mapInput) => {
|
|
832
|
+
const def = getEffectProcedureDef(context);
|
|
833
|
+
if (!mapInput && isEffectMiddleware(middleware)) {
|
|
834
|
+
return new EffectDecoratedProcedure(
|
|
835
|
+
appendEffectStep(def, {
|
|
836
|
+
_tag: "middleware",
|
|
837
|
+
middleware
|
|
838
|
+
})
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
const flushedDef = flushEffectSteps(def);
|
|
419
842
|
const mapped = mapInput ? decorateMiddleware(middleware).mapInput(mapInput) : middleware;
|
|
420
843
|
return new EffectDecoratedProcedure({
|
|
421
|
-
...
|
|
422
|
-
middlewares: addMiddleware(
|
|
423
|
-
getEffectProcedureDef(context).middlewares,
|
|
424
|
-
mapped
|
|
425
|
-
)
|
|
844
|
+
...flushedDef,
|
|
845
|
+
middlewares: addMiddleware(flushedDef.middlewares, mapped)
|
|
426
846
|
});
|
|
427
847
|
};
|
|
428
848
|
});
|
|
@@ -459,8 +879,11 @@ function createEffectProcedureProxy(target, decorated) {
|
|
|
459
879
|
}
|
|
460
880
|
var EffectProcedure = class _EffectProcedure extends Procedure {
|
|
461
881
|
constructor(def, procedure) {
|
|
462
|
-
|
|
463
|
-
|
|
882
|
+
const { effectSteps, effectHandler, ...procedureDef } = def;
|
|
883
|
+
super(procedureDef);
|
|
884
|
+
attachEffectState(this, procedure ?? new Procedure(procedureDef), {
|
|
885
|
+
effectSteps,
|
|
886
|
+
effectHandler,
|
|
464
887
|
effectErrorMap: def.effectErrorMap,
|
|
465
888
|
runtime: def.runtime
|
|
466
889
|
});
|
|
@@ -527,84 +950,12 @@ function enhanceEffectRouter(router, options) {
|
|
|
527
950
|
return enhanced;
|
|
528
951
|
}
|
|
529
952
|
|
|
530
|
-
// src/
|
|
531
|
-
import {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
537
|
-
cause: defect
|
|
538
|
-
});
|
|
539
|
-
},
|
|
540
|
-
onFail(error) {
|
|
541
|
-
if (isORPCTaggedError(error)) {
|
|
542
|
-
return error.toORPCError();
|
|
543
|
-
}
|
|
544
|
-
if (error instanceof ORPCError2) {
|
|
545
|
-
return error;
|
|
546
|
-
}
|
|
547
|
-
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
548
|
-
cause: error
|
|
549
|
-
});
|
|
550
|
-
},
|
|
551
|
-
onInterrupt(fiberId) {
|
|
552
|
-
return new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
553
|
-
cause: new Error(`${fiberId} Interrupted`)
|
|
554
|
-
});
|
|
555
|
-
},
|
|
556
|
-
onSequential(left) {
|
|
557
|
-
return left;
|
|
558
|
-
},
|
|
559
|
-
onEmpty: new ORPCError2("INTERNAL_SERVER_ERROR", {
|
|
560
|
-
cause: new Error("Unknown error")
|
|
561
|
-
}),
|
|
562
|
-
onParallel(left) {
|
|
563
|
-
return left;
|
|
564
|
-
}
|
|
565
|
-
});
|
|
566
|
-
}
|
|
567
|
-
function createEffectProcedureHandler(options) {
|
|
568
|
-
const {
|
|
569
|
-
runtime,
|
|
570
|
-
effectErrorMap,
|
|
571
|
-
effectFn,
|
|
572
|
-
spanConfig,
|
|
573
|
-
defaultCaptureStackTrace
|
|
574
|
-
} = options;
|
|
575
|
-
return async (opts) => {
|
|
576
|
-
const effectOpts = {
|
|
577
|
-
context: opts.context,
|
|
578
|
-
input: opts.input,
|
|
579
|
-
path: opts.path,
|
|
580
|
-
procedure: opts.procedure,
|
|
581
|
-
signal: opts.signal,
|
|
582
|
-
lastEventId: opts.lastEventId,
|
|
583
|
-
errors: createEffectErrorConstructorMap(effectErrorMap)
|
|
584
|
-
};
|
|
585
|
-
const spanName = spanConfig?.name ?? opts.path.join(".");
|
|
586
|
-
const captureStackTrace = spanConfig?.captureStackTrace ?? defaultCaptureStackTrace;
|
|
587
|
-
const resolver = Effect.fnUntraced(effectFn);
|
|
588
|
-
const tracedEffect = Effect.withSpan(resolver(effectOpts), spanName, {
|
|
589
|
-
captureStackTrace
|
|
590
|
-
});
|
|
591
|
-
const parentFiberRefs = getCurrentFiberRefs();
|
|
592
|
-
const effectWithRefs = parentFiberRefs ? Effect.fiberIdWith(
|
|
593
|
-
(fiberId) => Effect.flatMap(
|
|
594
|
-
Effect.getFiberRefs,
|
|
595
|
-
(fiberRefs) => Effect.setFiberRefs(
|
|
596
|
-
FiberRefs.joinAs(fiberRefs, fiberId, parentFiberRefs)
|
|
597
|
-
).pipe(Effect.andThen(tracedEffect))
|
|
598
|
-
)
|
|
599
|
-
) : tracedEffect;
|
|
600
|
-
const exit = await runtime.runPromiseExit(effectWithRefs, {
|
|
601
|
-
signal: opts.signal
|
|
602
|
-
});
|
|
603
|
-
if (Exit.isFailure(exit)) {
|
|
604
|
-
throw toORPCErrorFromCause(exit.cause);
|
|
605
|
-
}
|
|
606
|
-
return exit.value;
|
|
607
|
-
};
|
|
953
|
+
// src/runtime-source.ts
|
|
954
|
+
import { ManagedRuntime } from "effect";
|
|
955
|
+
function toManagedRuntime(source) {
|
|
956
|
+
return ManagedRuntime.isManagedRuntime(source) ? source : ManagedRuntime.make(
|
|
957
|
+
source
|
|
958
|
+
);
|
|
608
959
|
}
|
|
609
960
|
|
|
610
961
|
// src/effect-builder.ts
|
|
@@ -614,6 +965,9 @@ var builderVirtualDescriptors = {
|
|
|
614
965
|
errors: { enumerable: false },
|
|
615
966
|
handler: { enumerable: false },
|
|
616
967
|
lazy: { enumerable: false },
|
|
968
|
+
middleware: { enumerable: false },
|
|
969
|
+
provide: { enumerable: false },
|
|
970
|
+
provideOptional: { enumerable: false },
|
|
617
971
|
router: { enumerable: false },
|
|
618
972
|
traced: { enumerable: false }
|
|
619
973
|
};
|
|
@@ -621,6 +975,9 @@ var builderVirtualKeys = [
|
|
|
621
975
|
"~effect",
|
|
622
976
|
"errors",
|
|
623
977
|
"effect",
|
|
978
|
+
"middleware",
|
|
979
|
+
"provide",
|
|
980
|
+
"provideOptional",
|
|
624
981
|
"traced",
|
|
625
982
|
"handler",
|
|
626
983
|
"router",
|
|
@@ -643,7 +1000,9 @@ function getEffectBuilderDef(context) {
|
|
|
643
1000
|
...context.upstream["~orpc"],
|
|
644
1001
|
effectErrorMap: context.state.effectErrorMap,
|
|
645
1002
|
runtime: context.state.runtime,
|
|
646
|
-
spanConfig: context.state.spanConfig
|
|
1003
|
+
spanConfig: context.state.spanConfig,
|
|
1004
|
+
effectSteps: context.state.effectSteps,
|
|
1005
|
+
effectHandler: context.state.effectHandler
|
|
647
1006
|
};
|
|
648
1007
|
}
|
|
649
1008
|
function wrapBuilderLike(builder, state) {
|
|
@@ -652,11 +1011,38 @@ function wrapBuilderLike(builder, state) {
|
|
|
652
1011
|
...builder["~orpc"],
|
|
653
1012
|
effectErrorMap: state.effectErrorMap,
|
|
654
1013
|
runtime: state.runtime,
|
|
655
|
-
spanConfig: state.spanConfig
|
|
1014
|
+
spanConfig: state.spanConfig,
|
|
1015
|
+
effectSteps: state.effectSteps,
|
|
1016
|
+
effectHandler: state.effectHandler
|
|
656
1017
|
},
|
|
657
1018
|
unwrapEffectUpstream(builder)
|
|
658
1019
|
);
|
|
659
1020
|
}
|
|
1021
|
+
function appendEffectStep2(state, step) {
|
|
1022
|
+
return {
|
|
1023
|
+
...state,
|
|
1024
|
+
effectSteps: [...state.effectSteps ?? [], step]
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
function flushEffectSteps2(builder, state) {
|
|
1028
|
+
if (!state.effectSteps?.length) {
|
|
1029
|
+
return { builder, state };
|
|
1030
|
+
}
|
|
1031
|
+
const middleware = createEffectPipelineMiddleware({
|
|
1032
|
+
effectErrorMap: state.effectErrorMap,
|
|
1033
|
+
runtime: state.runtime,
|
|
1034
|
+
steps: state.effectSteps
|
|
1035
|
+
});
|
|
1036
|
+
return {
|
|
1037
|
+
builder: Reflect.apply(Reflect.get(builder, "use", builder), builder, [
|
|
1038
|
+
middleware
|
|
1039
|
+
]),
|
|
1040
|
+
state: {
|
|
1041
|
+
...state,
|
|
1042
|
+
effectSteps: void 0
|
|
1043
|
+
}
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
660
1046
|
function createEffectBuilderProxy(target) {
|
|
661
1047
|
return createNodeProxy(target, {
|
|
662
1048
|
getVirtual(context, prop) {
|
|
@@ -688,13 +1074,20 @@ function createEffectBuilderProxy(target) {
|
|
|
688
1074
|
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
689
1075
|
return (effectFn) => {
|
|
690
1076
|
const defaultCaptureStackTrace = addSpanStackTrace();
|
|
1077
|
+
const effectHandler = {
|
|
1078
|
+
defaultCaptureStackTrace,
|
|
1079
|
+
effectFn,
|
|
1080
|
+
spanConfig: state.spanConfig
|
|
1081
|
+
};
|
|
691
1082
|
return new EffectDecoratedProcedure({
|
|
692
1083
|
...effectDef,
|
|
1084
|
+
effectHandler,
|
|
693
1085
|
handler: async (opts) => {
|
|
694
1086
|
return createEffectProcedureHandler({
|
|
695
1087
|
defaultCaptureStackTrace,
|
|
696
1088
|
effectErrorMap: state.effectErrorMap,
|
|
697
1089
|
effectFn,
|
|
1090
|
+
effectSteps: state.effectSteps,
|
|
698
1091
|
runtime: state.runtime,
|
|
699
1092
|
spanConfig: state.spanConfig
|
|
700
1093
|
})(opts);
|
|
@@ -702,6 +1095,77 @@ function createEffectBuilderProxy(target) {
|
|
|
702
1095
|
});
|
|
703
1096
|
};
|
|
704
1097
|
});
|
|
1098
|
+
case "middleware":
|
|
1099
|
+
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
1100
|
+
return (middleware) => {
|
|
1101
|
+
if (isEffectMiddleware(middleware)) {
|
|
1102
|
+
const effectMiddleware = createEffectPipelineMiddleware({
|
|
1103
|
+
effectErrorMap: state.effectErrorMap,
|
|
1104
|
+
runtime: state.runtime,
|
|
1105
|
+
steps: [
|
|
1106
|
+
...state.effectSteps ?? [],
|
|
1107
|
+
{ _tag: "middleware", middleware }
|
|
1108
|
+
]
|
|
1109
|
+
});
|
|
1110
|
+
return Reflect.apply(
|
|
1111
|
+
Reflect.get(source, "middleware", source),
|
|
1112
|
+
source,
|
|
1113
|
+
[effectMiddleware]
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
return Reflect.apply(
|
|
1117
|
+
Reflect.get(source, "middleware", source),
|
|
1118
|
+
source,
|
|
1119
|
+
[middleware]
|
|
1120
|
+
);
|
|
1121
|
+
};
|
|
1122
|
+
});
|
|
1123
|
+
case "provide":
|
|
1124
|
+
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
1125
|
+
return (tagOrLayer, provider) => {
|
|
1126
|
+
return wrapBuilderLike(
|
|
1127
|
+
source,
|
|
1128
|
+
appendEffectStep2(
|
|
1129
|
+
state,
|
|
1130
|
+
Layer3.isLayer(tagOrLayer) ? { _tag: "provideLayer", layer: tagOrLayer } : { _tag: "provide", provider, tag: tagOrLayer }
|
|
1131
|
+
)
|
|
1132
|
+
);
|
|
1133
|
+
};
|
|
1134
|
+
});
|
|
1135
|
+
case "provideOptional":
|
|
1136
|
+
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
1137
|
+
return (tag, provider) => {
|
|
1138
|
+
return wrapBuilderLike(
|
|
1139
|
+
source,
|
|
1140
|
+
appendEffectStep2(state, {
|
|
1141
|
+
_tag: "provideOptional",
|
|
1142
|
+
provider,
|
|
1143
|
+
tag
|
|
1144
|
+
})
|
|
1145
|
+
);
|
|
1146
|
+
};
|
|
1147
|
+
});
|
|
1148
|
+
case "use":
|
|
1149
|
+
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
1150
|
+
return (middleware, ...rest) => {
|
|
1151
|
+
if (isEffectMiddleware(middleware) && rest.length === 0) {
|
|
1152
|
+
return wrapBuilderLike(
|
|
1153
|
+
source,
|
|
1154
|
+
appendEffectStep2(state, {
|
|
1155
|
+
_tag: "middleware",
|
|
1156
|
+
middleware
|
|
1157
|
+
})
|
|
1158
|
+
);
|
|
1159
|
+
}
|
|
1160
|
+
const flushed = flushEffectSteps2(source, state);
|
|
1161
|
+
const nextBuilder = Reflect.apply(
|
|
1162
|
+
Reflect.get(flushed.builder, "use", flushed.builder),
|
|
1163
|
+
flushed.builder,
|
|
1164
|
+
[middleware, ...rest]
|
|
1165
|
+
);
|
|
1166
|
+
return wrapBuilderLike(nextBuilder, flushed.state);
|
|
1167
|
+
};
|
|
1168
|
+
});
|
|
705
1169
|
case "traced":
|
|
706
1170
|
return getOrCreateVirtualMethod2(context, prop, () => {
|
|
707
1171
|
return (spanName) => wrapBuilderLike(source, {
|
|
@@ -763,8 +1227,10 @@ function addSpanStackTrace() {
|
|
|
763
1227
|
}
|
|
764
1228
|
var EffectBuilder = class {
|
|
765
1229
|
constructor(def, builder) {
|
|
766
|
-
const { runtime, spanConfig, effectErrorMap, ...orpcDef } = def;
|
|
1230
|
+
const { runtime, spanConfig, effectErrorMap, effectSteps, ...orpcDef } = def;
|
|
767
1231
|
attachEffectState(this, builder ?? new Builder(orpcDef), {
|
|
1232
|
+
effectSteps,
|
|
1233
|
+
effectHandler: def.effectHandler,
|
|
768
1234
|
effectErrorMap,
|
|
769
1235
|
runtime,
|
|
770
1236
|
spanConfig
|
|
@@ -772,9 +1238,13 @@ var EffectBuilder = class {
|
|
|
772
1238
|
return createEffectBuilderProxy(this);
|
|
773
1239
|
}
|
|
774
1240
|
};
|
|
775
|
-
function makeEffectORPC(
|
|
776
|
-
const
|
|
1241
|
+
function makeEffectORPC(source, builder) {
|
|
1242
|
+
const sourceIsBuilder = source !== void 0 && isBuilderLike(source);
|
|
1243
|
+
const resolvedBuilder = sourceIsBuilder ? source : builder ?? emptyBuilder();
|
|
777
1244
|
const effectErrorMap = getEffectErrorMap(resolvedBuilder);
|
|
1245
|
+
const runtime = toManagedRuntime(
|
|
1246
|
+
sourceIsBuilder || source === void 0 ? Layer3.empty : source
|
|
1247
|
+
);
|
|
778
1248
|
return new EffectBuilder(
|
|
779
1249
|
{
|
|
780
1250
|
...resolvedBuilder["~orpc"],
|
|
@@ -1040,11 +1510,11 @@ function wrapContractNode(contract, target, runtime) {
|
|
|
1040
1510
|
}
|
|
1041
1511
|
});
|
|
1042
1512
|
}
|
|
1043
|
-
function implementEffect(contract,
|
|
1513
|
+
function implementEffect(contract, source) {
|
|
1044
1514
|
return wrapContractNode(
|
|
1045
1515
|
contract,
|
|
1046
1516
|
implement(contract),
|
|
1047
|
-
|
|
1517
|
+
toManagedRuntime(source)
|
|
1048
1518
|
);
|
|
1049
1519
|
}
|
|
1050
1520
|
export {
|