@akterjs/cli 0.0.0-stage → 0.1.1
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/LICENSE +201 -0
- package/README.md +47 -2
- package/dist/Argument-D81dqizB.mjs +57 -0
- package/dist/Array-B4kuTQeW.mjs +2323 -0
- package/dist/Boolean-kILIvmhE.mjs +26 -0
- package/dist/ChildProcess-BCIwxPGc.mjs +577 -0
- package/dist/CliError-Cf5xqkkj.mjs +633 -0
- package/dist/Command-Dzq9KM-h.mjs +5135 -0
- package/dist/Config-B6OND9WR.mjs +854 -0
- package/dist/Console-BKHUkH6a.mjs +141 -0
- package/dist/Data-CeCULr0-.mjs +251 -0
- package/dist/Digest-CBd3uv5B.mjs +348 -0
- package/dist/Duration-EH9Vy4U6.mjs +791 -0
- package/dist/Effect-CKFpqbmw.mjs +12911 -0
- package/dist/FileSystem-4pPcEb_i.mjs +1366 -0
- package/dist/HttpClientError-BUeMWx70.mjs +303 -0
- package/dist/HttpClientResponse-D5ZKICVV.mjs +855 -0
- package/dist/Match-CGPLZYrV.mjs +434 -0
- package/dist/MutableHashMap-f8nW8AJR.mjs +376 -0
- package/dist/MutableHashSet-_HI572Ya.mjs +155 -0
- package/dist/MutableRef-D4Qv592C.mjs +107 -0
- package/dist/Number-BvkRkfc-.mjs +137 -0
- package/dist/Option-DkxSnBhp.mjs +3967 -0
- package/dist/Order-C1JC991I.mjs +481 -0
- package/dist/Path-Djdv_eF5.mjs +130 -0
- package/dist/Queue-CO5UQ6os.mjs +1394 -0
- package/dist/Redacted-RkJrG5Me.mjs +160 -0
- package/dist/Ref-BIPOxJNH.mjs +267 -0
- package/dist/Runtime-BInIAwK3.mjs +297 -0
- package/dist/Schema-MiKt5K1v.mjs +10999 -0
- package/dist/SecureRandom-B_U4ysO3.mjs +279 -0
- package/dist/Semaphore-DOVJ4ZGS.mjs +177 -0
- package/dist/Stdio-KylmOBX_.mjs +74 -0
- package/dist/Stream-bK9QIETN.mjs +4012 -0
- package/dist/String-q5dcsVe4.mjs +351 -0
- package/dist/TerminalCapabilities-w_44MAca.mjs +1769 -0
- package/dist/WebCrypto-ZI_GNVlw.mjs +33 -0
- package/dist/actor-call.service-CGM_vD9u.mjs +1269 -0
- package/dist/actor-client.adapter-Coem7gF1.mjs +3691 -0
- package/dist/akter-program.config-D8yb9xQP.mjs +7034 -0
- package/dist/akter.cli.mjs +5 -0
- package/dist/app-cli.config.mjs +49 -0
- package/dist/app-entry.pure.mjs +31 -0
- package/dist/archive/akter-archive.schema.mjs +65 -0
- package/dist/archive/akter-archive.service.mjs +309 -0
- package/dist/archive/archive-cli.config.mjs +45 -0
- package/dist/archive/archive-invalid.errors.mjs +5 -0
- package/dist/archive/archived-lineage.pure.mjs +13 -0
- package/dist/archive/tar.pure.mjs +291 -0
- package/dist/archive/zstd.adapter.mjs +46 -0
- package/dist/bench/bench-report.pure.mjs +120 -0
- package/dist/bench/bench-runner.pure.mjs +89 -0
- package/dist/bench/bench.service.mjs +301 -0
- package/dist/cli-runtime.layer-BqK2mmVL.mjs +1191 -0
- package/dist/cli-runtime.layer.mjs +1 -0
- package/dist/cloud-client.adapter-Cy1BjDbG.mjs +3186 -0
- package/dist/cloud-client.adapter-DOVMoYAj.mjs +304 -0
- package/dist/command/akter-commands.config.mjs +32 -0
- package/dist/command/akter-program.config.mjs +1 -0
- package/dist/credentials/credentials.service.mjs +226 -0
- package/dist/credentials/keychain.adapter.mjs +92 -0
- package/dist/credentials/login.config.mjs +251 -0
- package/dist/deploy/auth/api-attempt.service.mjs +30 -0
- package/dist/deploy/auth/token-refresh.errors.mjs +4 -0
- package/dist/deploy/build-bundle.adapter.mjs +133 -0
- package/dist/deploy/build-manifest.pure.mjs +44 -0
- package/dist/deploy/cloud-client.adapter.mjs +1 -0
- package/dist/deploy/cloud-url.pure.mjs +17 -0
- package/dist/deploy/deploy-failed.errors.mjs +17 -0
- package/dist/deploy/deploy.service.mjs +156 -0
- package/dist/deploy/request-failure.pure.mjs +87 -0
- package/dist/dev-runner.pure.mjs +30 -0
- package/dist/docs/doc-topics.pure.mjs +21 -0
- package/dist/docs/docs.config.mjs +1 -0
- package/dist/docs.config-D2amjsje.mjs +190 -0
- package/dist/docs.config-D3zzLzLR.mjs +190 -0
- package/dist/export/actor-export.service.mjs +267 -0
- package/dist/export/export-failed.errors.mjs +4 -0
- package/dist/export/export-failure.pure.mjs +18 -0
- package/dist/export/ordered-lines.pure.mjs +43 -0
- package/dist/export/ranged-download.pure.mjs +66 -0
- package/dist/export/snapshot-download.pure.mjs +86 -0
- package/dist/history-runner.pure.mjs +186 -0
- package/dist/history-since.pure.mjs +17 -0
- package/dist/hosted-runtime.layer-Cx3IPsEd.mjs +16358 -0
- package/dist/local/environment-cli.config.mjs +90 -0
- package/dist/local/environment-runner.pure.mjs +75 -0
- package/dist/local/local-cli.config.mjs +159 -0
- package/dist/logs/log-follow.config.mjs +21 -0
- package/dist/logs/log-follow.service.mjs +87 -0
- package/dist/logs/log-lines.pure.mjs +44 -0
- package/dist/migrate-runner.pure.mjs +28 -0
- package/dist/operation-input.pure-CS9iUhqK.mjs +1383 -0
- package/dist/operation-registry.pure-DVC8EDgj.mjs +283 -0
- package/dist/registry/actor-call.service.mjs +1 -0
- package/dist/registry/actor-commands.config.mjs +127 -0
- package/dist/registry/actor-refusal.pure.mjs +34 -0
- package/dist/registry/approval.service.mjs +80 -0
- package/dist/registry/cloud-commands.config.mjs +151 -0
- package/dist/registry/cloud-served.pure.mjs +31 -0
- package/dist/registry/operation-call.service.mjs +262 -0
- package/dist/registry/operation-input.pure.mjs +1 -0
- package/dist/registry/operation-output.pure.mjs +91 -0
- package/dist/registry/served-command.config.mjs +57 -0
- package/dist/runner-exited.errors.mjs +10 -0
- package/dist/terminal/cli-exit.errors.mjs +38 -0
- package/dist/terminal/cli-failure.pure.mjs +31 -0
- package/dist/terminal/confirm.adapter.mjs +27 -0
- package/package.json +61 -3
|
@@ -0,0 +1,3691 @@
|
|
|
1
|
+
import { F as PipeInspectableProto, On as pipeArguments, S as none$1, Sn as identity, _ as isSome, _n as constUndefined, b as map, bn as dual, bt as setStackTraceLimit, gn as constTrue, gt as assignProperty, h as isNone, hn as constFalse, qt as hasProperty, un as isTagged, vn as constVoid, w as some, x as match, yt as getStackTraceLimit } from "./Option-DkxSnBhp.mjs";
|
|
2
|
+
import { $i as encode, $r as isInterruptReason, $t as suspend$1, An as spaced, At as provideContext, B as flatMap, C as catch_, Ct as onExitPrimitive, Dr as isFailure, E as contextWith, En as exponential, Et as orDie, Gr as hasDies, Gt as scoped, Hn as effectContext, Hr as filterInterruptors, Ir as StackTrace, J as forkChild, Jn as succeed$2, Jr as interruptors, Jt as serviceOption, K as forEach, Kr as hasInterrupts, Lt as retry, M as fail, Mr as void_$1, N as failCause, Nn as upTo, Nt as raceFirst, O as die$1, On as min, Or as isSuccess, Pn as while_, Q as fromOption, Qn as close, R as filterOrFail, Rr as combine, Rt as runFork, Sn as yieldNow, Sr as failCause$1, St as onExit, T as context, Tr as interrupt$1, Un as effectDiscard, Ut as sandbox, Vn as effect, W as fnUntraced, Wr as fromReasons, Wt as scope, X as forkScoped, Xn as addFinalizer$1, Xt as succeed, Y as forkIn, Yn as Scope, Yt as sleep, Zn as addFinalizerExit, _r as succeed$3, aa as Service$1, at as isEffect, bn as withParentSpan, br as die$2, bt as never, ca as get, ci as squash, cr as done, da as getOrUndefinedUnsafe, dr as into, dt as map$1, ea as compose, en as sync, et as gen, fa as getUnsafe, fn as uninterruptible, gn as void_, gr as makeUnsafe$1, h as catchCauseIf, ha as merge, hn as useSpan, ht as mapError, i as addFinalizer$2, ia as Reference, in as timeout, ir as provide, it as interruptible, jr as succeed$1, jt as provideService, ki as forkUnsafe, kn as setInputType, kt as provide$1, l as as, ln as try_, lr as doneUnsafe, m as catchCause, ma as makeUnsafe$2, mn as updateContext, mr as isDoneUnsafe, n as acquireRelease, na as has, o as andThen, oa as add, on as timeoutOrElse, p as callback, pa as make$7, pn as uninterruptibleMask, pt as mapBothEager, qr as hasInterruptsOnly, r as acquireUseRelease, ra as toPredicate, rr as makeUnsafe$3, rt as interrupt, s as annotateCurrentSpan, sa as empty, sr as _await, st as logError, ta as fromPredicate, tn as tap, tt as ignore, ua as getOrUndefined, ut as makeSpanScoped, va as Prototype, vn as whileLoop, vt as matchCauseEffect, wt as onInterrupt, xn as withSpan, xr as fail$1, xt as onError, y as catchIf, yn as withFiber, yt as matchEffect, zr as die, zt as runForkWith } from "./Effect-CKFpqbmw.mjs";
|
|
3
|
+
import { I as partition, K as empty$1, j as map$2, r as contains, u as findFirst } from "./Array-B4kuTQeW.mjs";
|
|
4
|
+
import { $ as declare, An as InvalidType, B as TaggedStruct, Dt as isGreaterThanOrEqualTo, F as String$1, I as Struct, K as Uint8Array$1, Kn as empty$2, Nn as makeCompositeAtKey, Q as brand, S as Literals, T as NonEmptyArray, Ut as isMinLength, V as TaggedUnion, X as Unknown, Y as Union, Yt as isSchema, Z as Void, Zn as merge$1, _n as defaultParseOptions, a as Boolean, an as optionalKey, at as decodeUnknownEffect, bn as isNever, c as Class, cn as toCodecJson, d as Defect, en as link, et as declareConstructor, fn as omit, fr as map$3, g as Finite, ht as isBetween, i as BigIntFromString, in as optional, j as OptionFromNullOr, m as Exit, mt as is, n as ArraySchema, nn as makeFilter, or as fromEntries, p as Error$1, pn as decodeEffect, q as Uint8ArrayFromBase64, qn as fromInput, qt as isPattern, rt as decodeSync, s as Cause, sn as tag, st as encodeEffect, tn as make$8, v as Int, w as Never, wn as transform, x as Literal, z as TaggedError } from "./Schema-MiKt5K1v.mjs";
|
|
5
|
+
import { l as millis$1, p as seconds } from "./Duration-EH9Vy4U6.mjs";
|
|
6
|
+
import { i as TaggedError$1, r as TaggedClass } from "./Data-CeCULr0-.mjs";
|
|
7
|
+
import { M as uint8Array, P as currentTimeMillis, j as text } from "./HttpClientResponse-D5ZKICVV.mjs";
|
|
8
|
+
import { a as remove$1, i as has$1, n as empty$3, o as set, r as get$1 } from "./MutableHashMap-f8nW8AJR.mjs";
|
|
9
|
+
import { D as mapAccum, G as runForEachArray, I as provideContext$1, R as retry$1, _t as interruptAll, ft as makeUnsafe$4, gt as interrupt$2, ht as getCurrent, nt as unwrap, vt as interruptAs, w as isStream, x as fromQueue, yt as join } from "./Stream-bK9QIETN.mjs";
|
|
10
|
+
import { m as shutdownUnsafe, o as failCause$2, r as end, t as bounded$1, u as offerAll } from "./Queue-CO5UQ6os.mjs";
|
|
11
|
+
import { t as SecureRandom } from "./SecureRandom-B_U4ysO3.mjs";
|
|
12
|
+
import { t as WebCrypto } from "./WebCrypto-ZI_GNVlw.mjs";
|
|
13
|
+
import { n as makeUnsafe$5 } from "./Semaphore-DOVJ4ZGS.mjs";
|
|
14
|
+
import { a as webCryptoDigest, i as sha256 } from "./Digest-CBd3uv5B.mjs";
|
|
15
|
+
import { a as option, r as Redacted, s as ConfigProvider } from "./Config-B6OND9WR.mjs";
|
|
16
|
+
import { a as HttpClientErrorSchema } from "./HttpClientError-BUeMWx70.mjs";
|
|
17
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/FiberMap.js
|
|
18
|
+
/**
|
|
19
|
+
* Manages fibers by key inside a scope.
|
|
20
|
+
*
|
|
21
|
+
* A `FiberMap<K, A, E>` owns a map of running fibers, interrupts them when its
|
|
22
|
+
* scope closes, and automatically removes each entry when the corresponding
|
|
23
|
+
* fiber completes. Use it when a program needs to start, replace, join, or
|
|
24
|
+
* interrupt background work by a stable key while keeping all fibers tied to
|
|
25
|
+
* one scope.
|
|
26
|
+
*
|
|
27
|
+
* @stability stable
|
|
28
|
+
* @since 2.0.0
|
|
29
|
+
*/
|
|
30
|
+
const TypeId$6 = "~effect/FiberMap";
|
|
31
|
+
/**
|
|
32
|
+
* Returns `true` if a value is a `FiberMap`.
|
|
33
|
+
*
|
|
34
|
+
* **Details**
|
|
35
|
+
*
|
|
36
|
+
* This is a type guard that checks for the `FiberMap` runtime marker.
|
|
37
|
+
*
|
|
38
|
+
* **Example** (Checking if a value is a FiberMap)
|
|
39
|
+
*
|
|
40
|
+
* ```ts import.meta.vitest
|
|
41
|
+
* import { Effect, FiberMap } from "effect"
|
|
42
|
+
*
|
|
43
|
+
* const program = Effect.gen(function*() {
|
|
44
|
+
* const map = yield* FiberMap.make<string>()
|
|
45
|
+
*
|
|
46
|
+
* return [FiberMap.isFiberMap(map), FiberMap.isFiberMap({}), FiberMap.isFiberMap(null)]
|
|
47
|
+
* })
|
|
48
|
+
*
|
|
49
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
50
|
+
* actual // => [true, false, false]
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @stability stable
|
|
54
|
+
* @category guards
|
|
55
|
+
* @since 2.0.0
|
|
56
|
+
*/
|
|
57
|
+
const isFiberMap = (u) => hasProperty(u, TypeId$6);
|
|
58
|
+
const Proto$2 = {
|
|
59
|
+
[TypeId$6]: TypeId$6,
|
|
60
|
+
[Symbol.iterator]() {
|
|
61
|
+
if (this.state._tag === "Closed") return empty$1();
|
|
62
|
+
return this.state.backing[Symbol.iterator]();
|
|
63
|
+
},
|
|
64
|
+
...PipeInspectableProto,
|
|
65
|
+
toJSON() {
|
|
66
|
+
return {
|
|
67
|
+
_id: "FiberMap",
|
|
68
|
+
state: this.state
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const makeUnsafe = (backing, deferred) => {
|
|
73
|
+
const self = Object.create(Proto$2);
|
|
74
|
+
self.state = {
|
|
75
|
+
_tag: "Open",
|
|
76
|
+
backing,
|
|
77
|
+
fibers: /* @__PURE__ */ new Set()
|
|
78
|
+
};
|
|
79
|
+
self.deferred = deferred;
|
|
80
|
+
return self;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Creates a scoped `FiberMap` for storing fibers by key.
|
|
84
|
+
*
|
|
85
|
+
* **Details**
|
|
86
|
+
*
|
|
87
|
+
* When the associated Scope is closed, all fibers in the map will be
|
|
88
|
+
* interrupted. You can add fibers to the map using `FiberMap.set` or
|
|
89
|
+
* `FiberMap.run`, and the fibers will be automatically removed from the
|
|
90
|
+
* `FiberMap` when they complete.
|
|
91
|
+
*
|
|
92
|
+
* **Example** (Creating a scoped FiberMap)
|
|
93
|
+
*
|
|
94
|
+
* ```ts import.meta.vitest
|
|
95
|
+
* import { Effect, FiberMap } from "effect"
|
|
96
|
+
*
|
|
97
|
+
* const program = Effect.gen(function*() {
|
|
98
|
+
* const map = yield* FiberMap.make<string>()
|
|
99
|
+
*
|
|
100
|
+
* // run some effects and add the fibers to the map
|
|
101
|
+
* yield* FiberMap.run(map, "fiber a", Effect.never)
|
|
102
|
+
* yield* FiberMap.run(map, "fiber b", Effect.never)
|
|
103
|
+
*
|
|
104
|
+
* yield* Effect.yieldNow
|
|
105
|
+
* return yield* FiberMap.size(map)
|
|
106
|
+
* }).pipe(
|
|
107
|
+
* Effect.scoped // The fibers will be interrupted when the scope is closed
|
|
108
|
+
* )
|
|
109
|
+
*
|
|
110
|
+
* const actual = await Effect.runPromise(program)
|
|
111
|
+
* actual // => 2
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @stability stable
|
|
115
|
+
* @category constructors
|
|
116
|
+
* @since 2.0.0
|
|
117
|
+
*/
|
|
118
|
+
const make$6 = () => acquireRelease(sync(() => makeUnsafe(empty$3(), makeUnsafe$1())), (map) => suspend$1(() => {
|
|
119
|
+
const state = map.state;
|
|
120
|
+
if (state._tag === "Closed") return void_;
|
|
121
|
+
map.state = { _tag: "Closed" };
|
|
122
|
+
return interruptAll(state.fibers).pipe(into(map.deferred));
|
|
123
|
+
}));
|
|
124
|
+
const internalFiberId = -1;
|
|
125
|
+
const isInternalInterruption = /*#__PURE__*/ toPredicate(/*#__PURE__*/ compose(filterInterruptors, /*#__PURE__*/ has(internalFiberId)));
|
|
126
|
+
/**
|
|
127
|
+
* Adds a fiber to the `FiberMap` under a key using a synchronous, unsafe
|
|
128
|
+
* mutation.
|
|
129
|
+
*
|
|
130
|
+
* **When to use**
|
|
131
|
+
*
|
|
132
|
+
* Use when an existing forked fiber must be installed under a key immediately
|
|
133
|
+
* and synchronous interruption of the replaced fiber is acceptable.
|
|
134
|
+
*
|
|
135
|
+
* **Details**
|
|
136
|
+
*
|
|
137
|
+
* When the fiber completes, it is removed from the map. If the key already has
|
|
138
|
+
* a fiber, that previous fiber is interrupted unless `onlyIfMissing` is set;
|
|
139
|
+
* in that case a different new fiber is interrupted and the existing entry is
|
|
140
|
+
* kept, while re-registering the existing fiber is a no-op.
|
|
141
|
+
*
|
|
142
|
+
* **Example** (Adding a fiber unsafely)
|
|
143
|
+
*
|
|
144
|
+
* ```ts import.meta.vitest
|
|
145
|
+
* import { Deferred, Effect, Fiber, FiberMap } from "effect"
|
|
146
|
+
*
|
|
147
|
+
* const program = Effect.gen(function*() {
|
|
148
|
+
* const map = yield* FiberMap.make<string>()
|
|
149
|
+
* const deferred = yield* Deferred.make<string>()
|
|
150
|
+
*
|
|
151
|
+
* // Create a fiber and add it to the map
|
|
152
|
+
* const fiber = yield* Effect.forkChild(Deferred.await(deferred))
|
|
153
|
+
* FiberMap.setUnsafe(map, "greeting", fiber)
|
|
154
|
+
*
|
|
155
|
+
* yield* Deferred.succeed(deferred, "Hello")
|
|
156
|
+
*
|
|
157
|
+
* // Join the fiber to get its successful value
|
|
158
|
+
* return yield* Fiber.join(fiber)
|
|
159
|
+
* })
|
|
160
|
+
*
|
|
161
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
162
|
+
* actual // => "Hello"
|
|
163
|
+
* ```
|
|
164
|
+
*
|
|
165
|
+
* @stability stable
|
|
166
|
+
* @category combinators
|
|
167
|
+
* @since 4.0.0
|
|
168
|
+
*/
|
|
169
|
+
const setUnsafe = /*#__PURE__*/ dual((args) => isFiberMap(args[0]), (self, key, fiber, options) => {
|
|
170
|
+
if (self.state._tag === "Closed") {
|
|
171
|
+
fiber.interruptUnsafe(internalFiberId);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const previous = get$1(self.state.backing, key);
|
|
175
|
+
if (previous._tag === "Some") {
|
|
176
|
+
if (previous.value === fiber) return;
|
|
177
|
+
else if (options?.onlyIfMissing === true) {
|
|
178
|
+
fiber.interruptUnsafe(internalFiberId);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
set(self.state.backing, key, fiber);
|
|
183
|
+
self.state.fibers.add(fiber);
|
|
184
|
+
if (previous._tag === "Some") previous.value.interruptUnsafe(internalFiberId);
|
|
185
|
+
fiber.addObserver((exit) => {
|
|
186
|
+
if (self.state._tag === "Closed") return;
|
|
187
|
+
self.state.fibers.delete(fiber);
|
|
188
|
+
const current = get$1(self.state.backing, key);
|
|
189
|
+
if (isSome(current) && fiber === current.value) remove$1(self.state.backing, key);
|
|
190
|
+
if (isFailure(exit) && (options?.propagateInterruption === true ? !isInternalInterruption(exit.cause) : !hasInterruptsOnly(exit.cause))) doneUnsafe(self.deferred, exit);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Checks whether a key exists in the FiberMap.
|
|
195
|
+
*
|
|
196
|
+
* **Example** (Checking if a key exists unsafely)
|
|
197
|
+
*
|
|
198
|
+
* ```ts import.meta.vitest
|
|
199
|
+
* import { Effect, FiberMap } from "effect"
|
|
200
|
+
*
|
|
201
|
+
* const program = Effect.gen(function*() {
|
|
202
|
+
* const map = yield* FiberMap.make<string>()
|
|
203
|
+
*
|
|
204
|
+
* // Add a fiber to the map
|
|
205
|
+
* yield* FiberMap.run(map, "task1", Effect.never)
|
|
206
|
+
*
|
|
207
|
+
* // Check if keys exist
|
|
208
|
+
* return [FiberMap.hasUnsafe(map, "task1"), FiberMap.hasUnsafe(map, "task2")]
|
|
209
|
+
* })
|
|
210
|
+
*
|
|
211
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
212
|
+
* actual // => [true, false]
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* @stability stable
|
|
216
|
+
* @category combinators
|
|
217
|
+
* @since 4.0.0
|
|
218
|
+
*/
|
|
219
|
+
const hasUnsafe = /*#__PURE__*/ dual(2, (self, key) => self.state._tag === "Closed" ? false : has$1(self.state.backing, key));
|
|
220
|
+
/**
|
|
221
|
+
* Removes a fiber from the FiberMap, interrupting it if it exists.
|
|
222
|
+
*
|
|
223
|
+
* **Example** (Removing a fiber)
|
|
224
|
+
*
|
|
225
|
+
* ```ts import.meta.vitest
|
|
226
|
+
* import { Effect, FiberMap } from "effect"
|
|
227
|
+
*
|
|
228
|
+
* const program = Effect.gen(function*() {
|
|
229
|
+
* const map = yield* FiberMap.make<string>()
|
|
230
|
+
*
|
|
231
|
+
* // Add some fibers to the map
|
|
232
|
+
* yield* FiberMap.run(map, "task1", Effect.never)
|
|
233
|
+
* yield* FiberMap.run(map, "task2", Effect.never)
|
|
234
|
+
*
|
|
235
|
+
* const sizeBefore = yield* FiberMap.size(map)
|
|
236
|
+
*
|
|
237
|
+
* // Remove a specific fiber (this will interrupt it)
|
|
238
|
+
* yield* FiberMap.remove(map, "task1")
|
|
239
|
+
*
|
|
240
|
+
* return [sizeBefore, yield* FiberMap.size(map)]
|
|
241
|
+
* })
|
|
242
|
+
*
|
|
243
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
244
|
+
* actual // => [2, 1]
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* @stability stable
|
|
248
|
+
* @category combinators
|
|
249
|
+
* @since 2.0.0
|
|
250
|
+
*/
|
|
251
|
+
const remove = /*#__PURE__*/ dual(2, (self, key) => suspend$1(() => {
|
|
252
|
+
if (self.state._tag === "Closed") return void_;
|
|
253
|
+
const fiber = get$1(self.state.backing, key);
|
|
254
|
+
if (fiber._tag === "None") return void_;
|
|
255
|
+
return interruptAs(fiber.value, internalFiberId);
|
|
256
|
+
}));
|
|
257
|
+
const constInterruptedFiber = /*#__PURE__*/ function() {
|
|
258
|
+
let fiber = void 0;
|
|
259
|
+
return () => {
|
|
260
|
+
if (fiber === void 0) fiber = runFork(interrupt);
|
|
261
|
+
return fiber;
|
|
262
|
+
};
|
|
263
|
+
}();
|
|
264
|
+
/**
|
|
265
|
+
* Forks an Effect and stores the resulting fiber in the `FiberMap` under a key.
|
|
266
|
+
*
|
|
267
|
+
* **Details**
|
|
268
|
+
*
|
|
269
|
+
* When the fiber completes, it is removed from the map. If the key already has
|
|
270
|
+
* a fiber, the previous fiber is interrupted unless `onlyIfMissing` is set.
|
|
271
|
+
* Set `startImmediately: false` to defer startup. By default, the effect starts
|
|
272
|
+
* immediately.
|
|
273
|
+
*
|
|
274
|
+
* **Example** (Forking effects into a map)
|
|
275
|
+
*
|
|
276
|
+
* ```ts import.meta.vitest
|
|
277
|
+
* import { Effect, Fiber, FiberMap } from "effect"
|
|
278
|
+
*
|
|
279
|
+
* const program = Effect.gen(function*() {
|
|
280
|
+
* const map = yield* FiberMap.make<string>()
|
|
281
|
+
*
|
|
282
|
+
* // Run effects and add the fibers to the map
|
|
283
|
+
* const fiber1 = yield* FiberMap.run(map, "task1", Effect.succeed("Hello"))
|
|
284
|
+
* const fiber2 = yield* FiberMap.run(map, "task2", Effect.succeed("World"))
|
|
285
|
+
*
|
|
286
|
+
* // Join the fibers to get their successful values
|
|
287
|
+
* const result1 = yield* Fiber.join(fiber1)
|
|
288
|
+
* const result2 = yield* Fiber.join(fiber2)
|
|
289
|
+
* return [result1, result2, yield* FiberMap.size(map)]
|
|
290
|
+
* })
|
|
291
|
+
*
|
|
292
|
+
* const actual = await Effect.runPromise(Effect.scoped(program))
|
|
293
|
+
* actual // => ["Hello", "World", 0]
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* @stability stable
|
|
297
|
+
* @category combinators
|
|
298
|
+
* @since 2.0.0
|
|
299
|
+
*/
|
|
300
|
+
const run = function() {
|
|
301
|
+
const self = arguments[0];
|
|
302
|
+
if (isEffect(arguments[2])) return runImpl(self, arguments[1], arguments[2], arguments[3]);
|
|
303
|
+
const key = arguments[1];
|
|
304
|
+
const options = arguments[2];
|
|
305
|
+
return (effect) => runImpl(self, key, effect, options);
|
|
306
|
+
};
|
|
307
|
+
const runImpl = (self, key, effect, options) => withFiber((parent) => {
|
|
308
|
+
if (self.state._tag === "Closed") return interrupt;
|
|
309
|
+
else if (options?.onlyIfMissing === true && hasUnsafe(self, key)) return sync(constInterruptedFiber);
|
|
310
|
+
const fiber = forkUnsafe(parent, effect, options?.startImmediately ?? true, true);
|
|
311
|
+
setUnsafe(self, key, fiber, options);
|
|
312
|
+
return succeed(fiber);
|
|
313
|
+
});
|
|
314
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/PrimaryKey.js
|
|
315
|
+
/**
|
|
316
|
+
* Defines the unique identifier used to identify objects that implement the `PrimaryKey` interface.
|
|
317
|
+
*
|
|
318
|
+
* **When to use**
|
|
319
|
+
*
|
|
320
|
+
* Use to implement the `PrimaryKey` protocol as a computed property key on
|
|
321
|
+
* classes or object literals that expose a stable string identifier.
|
|
322
|
+
*
|
|
323
|
+
* @see {@link PrimaryKey} for the protocol interface that declares the method keyed by this symbol
|
|
324
|
+
* @see {@link value} for reading the string key from a `PrimaryKey` value
|
|
325
|
+
* @see {@link isPrimaryKey} for checking whether an unknown value carries this method
|
|
326
|
+
*
|
|
327
|
+
* @stability stable
|
|
328
|
+
* @category symbols
|
|
329
|
+
* @since 2.0.0
|
|
330
|
+
*/
|
|
331
|
+
const symbol = "~effect/PrimaryKey";
|
|
332
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/workflow/internal/crypto.js
|
|
333
|
+
const encoder$2 = /*#__PURE__*/ new TextEncoder();
|
|
334
|
+
/**
|
|
335
|
+
* Execution ids and idempotency keys are persisted, so they keep the first 16
|
|
336
|
+
* bytes of the SHA-256 digest as 32 hex characters.
|
|
337
|
+
*
|
|
338
|
+
* @internal
|
|
339
|
+
*/
|
|
340
|
+
const makeHashDigest = (original) => WebCrypto.use((crypto) => map$1(webCryptoDigest(crypto, sha256, encoder$2.encode(original)), (bytes) => encode(bytes).slice(0, 32)));
|
|
341
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/workflow/Workflow.js
|
|
342
|
+
/**
|
|
343
|
+
* Defines typed durable workflows.
|
|
344
|
+
*
|
|
345
|
+
* A `Workflow` has a stable tag, schemas for payload, success, and failure, and
|
|
346
|
+
* an idempotency key used to derive execution ids. Workflow definitions can be
|
|
347
|
+
* executed, discarded, polled, interrupted, resumed, and registered with a
|
|
348
|
+
* handler layer. This module also includes workflow result types, compensation
|
|
349
|
+
* and cleanup helpers, suspension support, and settings for defect capture or
|
|
350
|
+
* failure suspension.
|
|
351
|
+
*
|
|
352
|
+
* @stability unstable
|
|
353
|
+
* @since 4.0.0
|
|
354
|
+
*/
|
|
355
|
+
const TypeId$5 = "~effect/workflow/Workflow";
|
|
356
|
+
const EngineTag$1 = /*#__PURE__*/ Service$1("effect/workflow/WorkflowEngine");
|
|
357
|
+
const InstanceTag$1 = /*#__PURE__*/ Service$1("effect/workflow/WorkflowEngine/WorkflowInstance");
|
|
358
|
+
const makeExecutionIdFromPayload = (self, payload) => makeHashDigest(`${self._tag.length}:${self._tag}:${self.idempotencyKey(payload)}`);
|
|
359
|
+
const Proto$1 = {
|
|
360
|
+
[TypeId$5]: TypeId$5,
|
|
361
|
+
annotate(tag, value) {
|
|
362
|
+
return makeProto$2({
|
|
363
|
+
_tag: this._tag,
|
|
364
|
+
payloadSchema: this.payloadSchema,
|
|
365
|
+
successSchema: this.successSchema,
|
|
366
|
+
errorSchema: this.errorSchema,
|
|
367
|
+
annotations: add(this.annotations, tag, value),
|
|
368
|
+
idempotencyKey: this.idempotencyKey,
|
|
369
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
annotateMerge(context) {
|
|
373
|
+
return makeProto$2({
|
|
374
|
+
_tag: this._tag,
|
|
375
|
+
payloadSchema: this.payloadSchema,
|
|
376
|
+
successSchema: this.successSchema,
|
|
377
|
+
errorSchema: this.errorSchema,
|
|
378
|
+
annotations: merge(this.annotations, context),
|
|
379
|
+
idempotencyKey: this.idempotencyKey,
|
|
380
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
execute(fields, opts) {
|
|
384
|
+
return suspend$1(() => {
|
|
385
|
+
const payload = this.payloadSchema.make(fields);
|
|
386
|
+
const run = flatMap(EngineTag$1, (engine) => flatMap(makeExecutionIdFromPayload(this, payload), (executionId) => andThen(annotateCurrentSpan({ executionId }), engine.execute(this, {
|
|
387
|
+
executionId,
|
|
388
|
+
payload,
|
|
389
|
+
discard: opts?.discard,
|
|
390
|
+
detached: opts?.detached,
|
|
391
|
+
suspendedRetrySchedule: this.suspendedRetrySchedule
|
|
392
|
+
}))));
|
|
393
|
+
return opts?.discard ? run : withPendingActivity(run);
|
|
394
|
+
}).pipe(withSpan(`${this._tag}.execute`, {}, { captureStackTrace: false }));
|
|
395
|
+
},
|
|
396
|
+
poll(executionId) {
|
|
397
|
+
return flatMap(EngineTag$1, (engine) => engine.poll(this, executionId)).pipe(withSpan(`${this._tag}.poll`, { attributes: { executionId } }, { captureStackTrace: false }));
|
|
398
|
+
},
|
|
399
|
+
interrupt(executionId) {
|
|
400
|
+
return flatMap(EngineTag$1, (engine) => engine.interrupt(this, executionId)).pipe(withSpan(`${this._tag}.interrupt`, { attributes: { executionId } }, { captureStackTrace: false }));
|
|
401
|
+
},
|
|
402
|
+
resume(executionId) {
|
|
403
|
+
return flatMap(EngineTag$1, (engine) => engine.resume(this, executionId)).pipe(withSpan(`${this._tag}.resume`, { attributes: { executionId } }, { captureStackTrace: false }));
|
|
404
|
+
},
|
|
405
|
+
toLayer(execute) {
|
|
406
|
+
return effectDiscard(flatMap(EngineTag$1, (engine) => engine.register(this, execute)));
|
|
407
|
+
},
|
|
408
|
+
executionId(payload) {
|
|
409
|
+
return flatMap(orDie(this.payloadSchema.makeEffect(payload)), (payload) => makeExecutionIdFromPayload(this, payload));
|
|
410
|
+
},
|
|
411
|
+
withCompensation: (...args) => withCompensation(...args)
|
|
412
|
+
};
|
|
413
|
+
const makeProto$2 = (options) => {
|
|
414
|
+
function Workflow() {}
|
|
415
|
+
Object.setPrototypeOf(Workflow, Proto$1);
|
|
416
|
+
Object.assign(Workflow, options);
|
|
417
|
+
return Workflow;
|
|
418
|
+
};
|
|
419
|
+
/**
|
|
420
|
+
* Creates a durable workflow definition with schemas, annotations, and
|
|
421
|
+
* deterministic execution IDs derived from the workflow tag and idempotency
|
|
422
|
+
* key.
|
|
423
|
+
*
|
|
424
|
+
* @stability unstable
|
|
425
|
+
* @category constructors
|
|
426
|
+
* @since 4.0.0
|
|
427
|
+
*/
|
|
428
|
+
const make$5 = (tag, options) => makeProto$2({
|
|
429
|
+
_tag: tag,
|
|
430
|
+
payloadSchema: isSchema(options.payload) ? options.payload : Struct(options.payload),
|
|
431
|
+
successSchema: options.success ?? Void,
|
|
432
|
+
errorSchema: options.error ?? Never,
|
|
433
|
+
annotations: options.annotations ?? empty(),
|
|
434
|
+
idempotencyKey: options.idempotencyKey,
|
|
435
|
+
suspendedRetrySchedule: options.suspendedRetrySchedule
|
|
436
|
+
});
|
|
437
|
+
const ResultTypeId = "~effect/workflow/Workflow/Result";
|
|
438
|
+
/**
|
|
439
|
+
* Returns `true` when a value is a workflow `Result`.
|
|
440
|
+
*
|
|
441
|
+
* @stability unstable
|
|
442
|
+
* @category guards
|
|
443
|
+
* @since 4.0.0
|
|
444
|
+
*/
|
|
445
|
+
const isResult = (u) => hasProperty(u, ResultTypeId);
|
|
446
|
+
/**
|
|
447
|
+
* Represents a completed workflow execution with its success or failure `Exit`.
|
|
448
|
+
*
|
|
449
|
+
* @stability unstable
|
|
450
|
+
* @category models
|
|
451
|
+
* @since 4.0.0
|
|
452
|
+
*/
|
|
453
|
+
var Complete = class Complete extends (/*#__PURE__*/ TaggedClass("Complete")) {
|
|
454
|
+
/**
|
|
455
|
+
* Marks this value as a workflow result for runtime guards.
|
|
456
|
+
*
|
|
457
|
+
* @stability unstable
|
|
458
|
+
* @since 4.0.0
|
|
459
|
+
*/
|
|
460
|
+
[ResultTypeId] = ResultTypeId;
|
|
461
|
+
/**
|
|
462
|
+
* Builds the schema for completed workflow results from success and error schemas.
|
|
463
|
+
*
|
|
464
|
+
* @stability unstable
|
|
465
|
+
* @since 4.0.0
|
|
466
|
+
*/
|
|
467
|
+
static Schema(options) {
|
|
468
|
+
const schema = declareConstructor()([Exit(options.success, options.error, Defect())], ([exit]) => (input, ast, options) => {
|
|
469
|
+
if (!(isResult(input) && input._tag === "Complete")) return fail(new InvalidType(ast, input, options));
|
|
470
|
+
return mapBothEager(decodeEffect(exit)(input.exit, options), {
|
|
471
|
+
onSuccess: (exit) => new Complete({ exit }),
|
|
472
|
+
onFailure: (issue) => makeCompositeAtKey(ast, "exit", issue, input, options)
|
|
473
|
+
});
|
|
474
|
+
}, {
|
|
475
|
+
expected: "Workflow.Complete",
|
|
476
|
+
toCodecJson: ([exit]) => link()(Struct({
|
|
477
|
+
_tag: tag("Complete"),
|
|
478
|
+
exit
|
|
479
|
+
}), transform({
|
|
480
|
+
decode: (encoded) => new Complete({ exit: encoded.exit }),
|
|
481
|
+
encode: (result) => ({
|
|
482
|
+
_tag: "Complete",
|
|
483
|
+
exit: result.exit
|
|
484
|
+
})
|
|
485
|
+
}))
|
|
486
|
+
});
|
|
487
|
+
return make$8(schema.ast, {
|
|
488
|
+
success: options.success,
|
|
489
|
+
error: options.error
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
};
|
|
493
|
+
/**
|
|
494
|
+
* Represents a suspended workflow execution, optionally carrying the cause that
|
|
495
|
+
* triggered suspension.
|
|
496
|
+
*
|
|
497
|
+
* **Details**
|
|
498
|
+
*
|
|
499
|
+
* `failed` marks this execution's own `SuspendOnFailure` and requires explicit
|
|
500
|
+
* `resume` or `interrupt`. Inherited child failures do not set it.
|
|
501
|
+
*
|
|
502
|
+
* @stability unstable
|
|
503
|
+
* @category schemas
|
|
504
|
+
* @since 4.0.0
|
|
505
|
+
*/
|
|
506
|
+
var Suspended = class extends (/*#__PURE__*/ Class("effect/workflow/Workflow/Suspended")({
|
|
507
|
+
_tag: /*#__PURE__*/ tag("Suspended"),
|
|
508
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Cause(Never, /*#__PURE__*/ Defect())),
|
|
509
|
+
failed: /*#__PURE__*/ optional(Boolean)
|
|
510
|
+
})) {
|
|
511
|
+
/**
|
|
512
|
+
* Marks this value as a workflow result for runtime guards.
|
|
513
|
+
*
|
|
514
|
+
* @stability unstable
|
|
515
|
+
* @since 4.0.0
|
|
516
|
+
*/
|
|
517
|
+
[ResultTypeId] = ResultTypeId;
|
|
518
|
+
};
|
|
519
|
+
/**
|
|
520
|
+
* Runs an effect as a workflow execution and converts its outcome into a
|
|
521
|
+
* `Result`, handling suspension, defect capture, interruption, and workflow
|
|
522
|
+
* scope finalization.
|
|
523
|
+
*
|
|
524
|
+
* @stability unstable
|
|
525
|
+
* @category converting
|
|
526
|
+
* @since 4.0.0
|
|
527
|
+
*/
|
|
528
|
+
const intoResult = (effect) => contextWith((context) => {
|
|
529
|
+
const instance = get(context, InstanceTag$1);
|
|
530
|
+
const captureDefects = get(instance.workflow.annotations, CaptureDefects);
|
|
531
|
+
const suspendOnFailure = get(instance.workflow.annotations, SuspendOnFailure);
|
|
532
|
+
return uninterruptibleMask((restore) => effect.pipe(forkChild({ startImmediately: true }), flatMap((fiber) => onInterrupt(restore(join(fiber)), () => interrupt$2(fiber))))).pipe(interruptible, suspendOnFailure ? catchCause((cause) => {
|
|
533
|
+
if (instance.abandoned || instance.interrupted) return failCause(cause);
|
|
534
|
+
instance.suspended = true;
|
|
535
|
+
if (!hasInterruptsOnly(cause)) {
|
|
536
|
+
instance.failed = true;
|
|
537
|
+
instance.cause = die(squash(cause));
|
|
538
|
+
}
|
|
539
|
+
return interrupt;
|
|
540
|
+
}) : identity, scoped, matchCauseEffect({
|
|
541
|
+
onSuccess: (value) => succeed(new Complete({ exit: succeed$1(value) })),
|
|
542
|
+
onFailure: (cause) => {
|
|
543
|
+
const [interrupts, reasons] = partition(cause.reasons, fromPredicate(isInterruptReason));
|
|
544
|
+
const hasInterruptsOnly = interrupts.length === cause.reasons.length;
|
|
545
|
+
const filtered = reasons.length === 0 ? cause : fromReasons(reasons);
|
|
546
|
+
const abandoned = instance.abandoned && !instance.interrupted && hasInterruptsOnly;
|
|
547
|
+
instance.abandoned = abandoned;
|
|
548
|
+
if (instance.suspended && hasInterruptsOnly && !abandoned) return succeed(new Suspended(instance.failed ? {
|
|
549
|
+
cause: instance.cause,
|
|
550
|
+
failed: true
|
|
551
|
+
} : { cause: instance.cause }));
|
|
552
|
+
if (!instance.interrupted && hasInterruptsOnly) return failCause(filtered);
|
|
553
|
+
return !captureDefects && hasDies(cause) ? failCause(filtered) : succeed(new Complete({ exit: failCause$1(filtered) }));
|
|
554
|
+
}
|
|
555
|
+
}), (eff) => onExitPrimitive(eff, (exit) => {
|
|
556
|
+
if (isFailure(exit)) return close(instance.scope, exit);
|
|
557
|
+
else if (exit.value._tag === "Complete") return close(instance.scope, exit.value.exit);
|
|
558
|
+
return void_;
|
|
559
|
+
}, true), uninterruptible);
|
|
560
|
+
});
|
|
561
|
+
/**
|
|
562
|
+
* Wraps an activity-like effect so workflow suspension waits for currently
|
|
563
|
+
* running activities to finish or suspend.
|
|
564
|
+
*
|
|
565
|
+
* @stability unstable
|
|
566
|
+
* @category resource management
|
|
567
|
+
* @since 4.0.0
|
|
568
|
+
*/
|
|
569
|
+
const wrapActivityResult = (effect, isSuspend) => contextWith((context) => {
|
|
570
|
+
const instance = get(context, InstanceTag$1);
|
|
571
|
+
return acquireUseRelease(sync(() => adoptActivityUnsafe(context, instance) ?? registerActivityUnsafe(instance)), () => effect, (registration, exit) => {
|
|
572
|
+
releaseActivityUnsafe(registration);
|
|
573
|
+
const isSuspended = isSuccess(exit) && isSuspend(exit.value);
|
|
574
|
+
if (isSuccess(exit) && isResult(exit.value) && exit.value._tag === "Suspended" && exit.value.cause) instance.cause = instance.cause ? combine(instance.cause, exit.value.cause) : exit.value.cause;
|
|
575
|
+
return isSuspended && instance.activityState.count > 0 ? waitForZero(instance) : void_;
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
const PendingActivityRegistration = /*#__PURE__*/ Service$1("effect/workflow/Workflow/PendingActivityRegistration");
|
|
579
|
+
const registerActivityUnsafe = (instance) => {
|
|
580
|
+
const state = instance.activityState;
|
|
581
|
+
if (state.count === 0) state.latch.closeUnsafe();
|
|
582
|
+
state.count++;
|
|
583
|
+
return {
|
|
584
|
+
instance,
|
|
585
|
+
state: "pending"
|
|
586
|
+
};
|
|
587
|
+
};
|
|
588
|
+
const adoptActivityUnsafe = (context, instance) => {
|
|
589
|
+
const pending = getOrUndefined(context, PendingActivityRegistration);
|
|
590
|
+
if (!pending || pending.instance !== instance) return;
|
|
591
|
+
if (pending.state !== "pending") throw new Error("Workflow.wrapActivityResult: pending child registration has already been consumed");
|
|
592
|
+
pending.state = "adopted";
|
|
593
|
+
return pending;
|
|
594
|
+
};
|
|
595
|
+
const releaseActivityUnsafe = (registration) => {
|
|
596
|
+
if (registration.state === "released") return;
|
|
597
|
+
registration.state = "released";
|
|
598
|
+
const state = registration.instance.activityState;
|
|
599
|
+
state.count--;
|
|
600
|
+
if (state.count === 0) state.latch.openUnsafe();
|
|
601
|
+
};
|
|
602
|
+
/**
|
|
603
|
+
* Registers a pending child workflow execution with the current workflow
|
|
604
|
+
* instance before any asynchronous work runs. `wrapActivityResult` adopts the
|
|
605
|
+
* registration once the execution is dispatched.
|
|
606
|
+
*/
|
|
607
|
+
const withPendingActivity = (effect) => contextWith((context) => {
|
|
608
|
+
const instance = getOrUndefined(context, InstanceTag$1);
|
|
609
|
+
if (!instance) return effect;
|
|
610
|
+
return acquireUseRelease(sync(() => registerActivityUnsafe(instance)), (registration) => provideService(effect, PendingActivityRegistration, registration), (registration) => sync(() => releaseActivityUnsafe(registration)));
|
|
611
|
+
});
|
|
612
|
+
const waitForZero = /*#__PURE__*/ fnUntraced(function* (instance) {
|
|
613
|
+
const state = instance.activityState;
|
|
614
|
+
while (true) {
|
|
615
|
+
if (state.count > 0) {
|
|
616
|
+
yield* state.latch.await;
|
|
617
|
+
yield* yieldNow;
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
yield* yieldNow;
|
|
621
|
+
if (state.count === 0) return;
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
/**
|
|
625
|
+
* Adds an exit finalizer to the current workflow scope, preserving the
|
|
626
|
+
* services available when the finalizer is registered.
|
|
627
|
+
*
|
|
628
|
+
* **Details**
|
|
629
|
+
*
|
|
630
|
+
* Body-level `Effect.onExit` finalizers cannot observe a deposited workflow
|
|
631
|
+
* interrupt. Use this function for terminal-state work that must observe it.
|
|
632
|
+
* Finalizers are skipped when a cluster owner abandons a run attempt for
|
|
633
|
+
* replay; owner-local scope finalizers registered with {@link provideScope}
|
|
634
|
+
* still run.
|
|
635
|
+
*
|
|
636
|
+
* @stability unstable
|
|
637
|
+
* @category resource management
|
|
638
|
+
* @since 4.0.0
|
|
639
|
+
*/
|
|
640
|
+
const addFinalizer = /*#__PURE__*/ fnUntraced(function* (f) {
|
|
641
|
+
const instance = yield* InstanceTag$1;
|
|
642
|
+
const services = yield* context();
|
|
643
|
+
yield* addFinalizerExit(instance.scope, (exit) => instance.abandoned ? void_ : provideContext(f(exit), services));
|
|
644
|
+
});
|
|
645
|
+
/**
|
|
646
|
+
* Adds compensation logic to an effect inside a Workflow.
|
|
647
|
+
*
|
|
648
|
+
* **When to use**
|
|
649
|
+
*
|
|
650
|
+
* Use when a top-level workflow step needs compensating cleanup if the overall
|
|
651
|
+
* workflow later fails after the step succeeds.
|
|
652
|
+
*
|
|
653
|
+
* **Details**
|
|
654
|
+
*
|
|
655
|
+
* The compensation finalizer is called if the entire workflow fails, allowing you to perform cleanup or other actions based on the success value and the cause of the workflow failure.
|
|
656
|
+
*
|
|
657
|
+
* **Gotchas**
|
|
658
|
+
*
|
|
659
|
+
* Compensation finalizers are only registered for top-level effects in the workflow and do not work for nested activities.
|
|
660
|
+
*
|
|
661
|
+
* @stability unstable
|
|
662
|
+
* @category compensation
|
|
663
|
+
* @since 4.0.0
|
|
664
|
+
*/
|
|
665
|
+
const withCompensation = /*#__PURE__*/ dual(2, (effect, compensation) => uninterruptibleMask((restore) => tap(restore(effect), (value) => addFinalizer((exit) => isSuccess(exit) ? void_ : compensation(value, exit.cause)))));
|
|
666
|
+
/**
|
|
667
|
+
* Marks a workflow instance as suspended and interrupts the current fiber to
|
|
668
|
+
* stop execution until it is resumed.
|
|
669
|
+
*
|
|
670
|
+
* @stability unstable
|
|
671
|
+
* @category interruption
|
|
672
|
+
* @since 4.0.0
|
|
673
|
+
*/
|
|
674
|
+
const suspend = (instance) => interruptible(callback(() => {
|
|
675
|
+
instance.suspended = true;
|
|
676
|
+
const fiber = getCurrent();
|
|
677
|
+
fiber.interruptUnsafe(fiber.id);
|
|
678
|
+
}));
|
|
679
|
+
/**
|
|
680
|
+
* Captures defects for a workflow and includes them in the result of the workflow or its activities.
|
|
681
|
+
*
|
|
682
|
+
* **Details**
|
|
683
|
+
*
|
|
684
|
+
* By default, this annotation is set to `true`, meaning defects are captured.
|
|
685
|
+
*
|
|
686
|
+
* @stability unstable
|
|
687
|
+
* @category services
|
|
688
|
+
* @since 4.0.0
|
|
689
|
+
*/
|
|
690
|
+
const CaptureDefects = /*#__PURE__*/ Reference("effect/workflow/Workflow/CaptureDefects", { defaultValue: constTrue });
|
|
691
|
+
/**
|
|
692
|
+
* Marks a workflow to suspend when it encounters any error.
|
|
693
|
+
*
|
|
694
|
+
* **Details**
|
|
695
|
+
*
|
|
696
|
+
* The suspended execution can later be resumed with the workflow's `resume` method, for example `MyWorkflow.resume(executionId)`.
|
|
697
|
+
*
|
|
698
|
+
* @stability unstable
|
|
699
|
+
* @category services
|
|
700
|
+
* @since 4.0.0
|
|
701
|
+
*/
|
|
702
|
+
const SuspendOnFailure = /*#__PURE__*/ Reference("effect/workflow/Workflow/SuspendOnFailure", { defaultValue: constFalse });
|
|
703
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/workflow/Activity.js
|
|
704
|
+
const TypeId$4 = "~effect/workflow/Activity";
|
|
705
|
+
/**
|
|
706
|
+
* Creates a workflow activity from an effect, using the provided schemas to
|
|
707
|
+
* encode successes and failures for durable execution.
|
|
708
|
+
*
|
|
709
|
+
* **Gotchas**
|
|
710
|
+
*
|
|
711
|
+
* Only completed activity results are memoized. If the activity suspends while
|
|
712
|
+
* awaiting child workflows or a durable clock, its body runs again when the
|
|
713
|
+
* parent workflow replays. Side effects before the suspension can repeat;
|
|
714
|
+
* make those side effects idempotent.
|
|
715
|
+
*
|
|
716
|
+
* @stability unstable
|
|
717
|
+
* @category constructors
|
|
718
|
+
* @since 4.0.0
|
|
719
|
+
*/
|
|
720
|
+
const make$4 = (options) => {
|
|
721
|
+
const successSchema = options.success ?? Void;
|
|
722
|
+
const errorSchema = options.error ?? Never;
|
|
723
|
+
const successSchemaJson = toCodecJson(successSchema);
|
|
724
|
+
const errorSchemaJson = toCodecJson(errorSchema);
|
|
725
|
+
let execute;
|
|
726
|
+
const executeWithoutInterrupt = retryOnInterrupt(options.name, options.interruptRetryPolicy)(options.execute);
|
|
727
|
+
const self = {
|
|
728
|
+
...Prototype({
|
|
729
|
+
label: "Activity",
|
|
730
|
+
evaluate(_) {
|
|
731
|
+
return execute;
|
|
732
|
+
}
|
|
733
|
+
}),
|
|
734
|
+
[TypeId$4]: TypeId$4,
|
|
735
|
+
name: options.name,
|
|
736
|
+
successSchema,
|
|
737
|
+
errorSchema,
|
|
738
|
+
exitSchema: Exit(successSchemaJson, errorSchemaJson, Defect()),
|
|
739
|
+
exitSchemaPartial: Exit(successSchemaJson, errorSchemaJson, Unknown),
|
|
740
|
+
annotations: options.annotations ?? empty(),
|
|
741
|
+
annotate(tag, value) {
|
|
742
|
+
return make$4({
|
|
743
|
+
...options,
|
|
744
|
+
annotations: add(self.annotations, tag, value)
|
|
745
|
+
});
|
|
746
|
+
},
|
|
747
|
+
annotateMerge(context) {
|
|
748
|
+
return make$4({
|
|
749
|
+
...options,
|
|
750
|
+
annotations: merge(self.annotations, context)
|
|
751
|
+
});
|
|
752
|
+
},
|
|
753
|
+
execute: executeWithoutInterrupt,
|
|
754
|
+
executeEncoded: matchEffect(executeWithoutInterrupt, {
|
|
755
|
+
onFailure: (error) => flatMap(orDie(encodeEffect(errorSchemaJson)(error)), fail),
|
|
756
|
+
onSuccess: (value) => orDie(encodeEffect(successSchemaJson)(value))
|
|
757
|
+
})
|
|
758
|
+
};
|
|
759
|
+
execute = makeExecute(self);
|
|
760
|
+
return self;
|
|
761
|
+
};
|
|
762
|
+
const interruptRetryPolicy = /*#__PURE__*/ min([exponential(400, 1.5), spaced("10 seconds")]).pipe(/*#__PURE__*/ setInputType(), /*#__PURE__*/ while_((meta) => meta.attempt <= 10 && hasInterrupts(meta.input)));
|
|
763
|
+
const retryOnInterrupt = (name, policy = interruptRetryPolicy) => (effect) => flatMap(InstanceTag, (instance) => effect.pipe(sandbox, retry({
|
|
764
|
+
schedule: policy,
|
|
765
|
+
while: () => !instance.suspended
|
|
766
|
+
}), catch_((cause) => hasInterrupts(cause) && !instance.suspended ? die$1(`Activity "${name}" interrupted and retry attempts exhausted`) : failCause(cause))));
|
|
767
|
+
/**
|
|
768
|
+
* Context reference containing the current activity retry attempt, defaulting
|
|
769
|
+
* to `1`.
|
|
770
|
+
*
|
|
771
|
+
* @stability unstable
|
|
772
|
+
* @category services
|
|
773
|
+
* @since 4.0.0
|
|
774
|
+
*/
|
|
775
|
+
const CurrentAttempt = /*#__PURE__*/ Reference("effect/workflow/Activity/CurrentAttempt", { defaultValue: () => 1 });
|
|
776
|
+
/**
|
|
777
|
+
* Computes a deterministic activity idempotency key from the current workflow
|
|
778
|
+
* execution ID, the supplied name, and optionally the current attempt.
|
|
779
|
+
*
|
|
780
|
+
* @stability unstable
|
|
781
|
+
* @category idempotency
|
|
782
|
+
* @since 4.0.0
|
|
783
|
+
*/
|
|
784
|
+
const idempotencyKey = /*#__PURE__*/ fnUntraced(function* (name, options) {
|
|
785
|
+
let key = `${(yield* InstanceTag).executionId}`;
|
|
786
|
+
if (options?.includeAttempt) {
|
|
787
|
+
const attempt = yield* CurrentAttempt;
|
|
788
|
+
key += `-${attempt}`;
|
|
789
|
+
}
|
|
790
|
+
key += `-${name}`;
|
|
791
|
+
return yield* makeHashDigest(key);
|
|
792
|
+
});
|
|
793
|
+
const EngineTag = /*#__PURE__*/ Service$1("effect/workflow/WorkflowEngine");
|
|
794
|
+
const InstanceTag = /*#__PURE__*/ Service$1("effect/workflow/WorkflowEngine/WorkflowInstance");
|
|
795
|
+
const makeExecute = /*#__PURE__*/ fnUntraced(function* (activity) {
|
|
796
|
+
const engine = yield* EngineTag;
|
|
797
|
+
const instance = yield* InstanceTag;
|
|
798
|
+
const attempt = yield* CurrentAttempt;
|
|
799
|
+
yield* annotateCurrentSpan({ executionId: instance.executionId });
|
|
800
|
+
const result = yield* wrapActivityResult(engine.activityExecute(activity, attempt), (_) => _._tag === "Suspended");
|
|
801
|
+
if (result._tag === "Suspended") {
|
|
802
|
+
if (result.failed) instance.failed = true;
|
|
803
|
+
return yield* suspend(instance);
|
|
804
|
+
}
|
|
805
|
+
return yield* result.exit;
|
|
806
|
+
}, (effect, activity) => withSpan(effect, activity.name, { captureStackTrace: false }));
|
|
807
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/socket/Socket.js
|
|
808
|
+
/**
|
|
809
|
+
* Runtime type identifier attached to `Socket` services.
|
|
810
|
+
*
|
|
811
|
+
* @stability unstable
|
|
812
|
+
* @category type IDs
|
|
813
|
+
* @since 4.0.0
|
|
814
|
+
*/
|
|
815
|
+
const TypeId$3 = "~effect/socket/Socket";
|
|
816
|
+
/**
|
|
817
|
+
* Service tag for bidirectional socket transports.
|
|
818
|
+
*
|
|
819
|
+
* **When to use**
|
|
820
|
+
*
|
|
821
|
+
* Use to access or provide the socket implementation used by programs that
|
|
822
|
+
* read and write frames through the Effect environment.
|
|
823
|
+
*
|
|
824
|
+
* @stability unstable
|
|
825
|
+
* @category services
|
|
826
|
+
* @since 4.0.0
|
|
827
|
+
*/
|
|
828
|
+
const Socket = /*#__PURE__*/ Service$1("effect/socket/Socket");
|
|
829
|
+
/**
|
|
830
|
+
* Constructs a `Socket` from a reader acquisition and a scoped writer.
|
|
831
|
+
*
|
|
832
|
+
* **Details**
|
|
833
|
+
*
|
|
834
|
+
* The reader must fail a suspended pull when its acquisition scope closes; see
|
|
835
|
+
* `Socket` for why. A reader that leaves a pull blocked forever will hang any
|
|
836
|
+
* consumer that shuts the socket down by closing that scope.
|
|
837
|
+
*
|
|
838
|
+
* @stability unstable
|
|
839
|
+
* @category constructors
|
|
840
|
+
* @since 4.0.0
|
|
841
|
+
*/
|
|
842
|
+
const make$3 = (options) => Socket.of({
|
|
843
|
+
[TypeId$3]: TypeId$3,
|
|
844
|
+
reader: options.reader,
|
|
845
|
+
writer: options.writer
|
|
846
|
+
});
|
|
847
|
+
const encoder$1 = /*#__PURE__*/ new TextEncoder();
|
|
848
|
+
const CloseEventTypeId = "~effect/socket/Socket/CloseEvent";
|
|
849
|
+
/**
|
|
850
|
+
* Returns `true` when a value is a `CloseEvent`.
|
|
851
|
+
*
|
|
852
|
+
* @stability unstable
|
|
853
|
+
* @category guards
|
|
854
|
+
* @since 4.0.0
|
|
855
|
+
*/
|
|
856
|
+
const isCloseEvent = (u) => hasProperty(u, CloseEventTypeId);
|
|
857
|
+
/**
|
|
858
|
+
* Runtime type identifier attached to `SocketError` values.
|
|
859
|
+
*
|
|
860
|
+
* @stability unstable
|
|
861
|
+
* @category type IDs
|
|
862
|
+
* @since 4.0.0
|
|
863
|
+
*/
|
|
864
|
+
const SocketErrorTypeId = "~effect/socket/Socket/SocketError";
|
|
865
|
+
/**
|
|
866
|
+
* Returns `true` when a value is a `SocketError`.
|
|
867
|
+
*
|
|
868
|
+
* @stability unstable
|
|
869
|
+
* @category guards
|
|
870
|
+
* @since 4.0.0
|
|
871
|
+
*/
|
|
872
|
+
const isSocketError = (u) => hasProperty(u, SocketErrorTypeId);
|
|
873
|
+
/**
|
|
874
|
+
* Typed error for failures that occur while reading from a socket.
|
|
875
|
+
*
|
|
876
|
+
* @stability unstable
|
|
877
|
+
* @category errors
|
|
878
|
+
* @since 4.0.0
|
|
879
|
+
*/
|
|
880
|
+
var SocketReadError = class extends (/*#__PURE__*/ Error$1("effect/socket/Socket/SocketReadError")({
|
|
881
|
+
_tag: /*#__PURE__*/ tag("SocketReadError"),
|
|
882
|
+
cause: /*#__PURE__*/ Defect()
|
|
883
|
+
})) {
|
|
884
|
+
/**
|
|
885
|
+
* Default message used for socket read failures.
|
|
886
|
+
*
|
|
887
|
+
* @stability unstable
|
|
888
|
+
* @since 4.0.0
|
|
889
|
+
*/
|
|
890
|
+
message = `An error occurred during Read`;
|
|
891
|
+
};
|
|
892
|
+
/**
|
|
893
|
+
* Typed error for failures that occur while writing to a socket.
|
|
894
|
+
*
|
|
895
|
+
* @stability unstable
|
|
896
|
+
* @category errors
|
|
897
|
+
* @since 4.0.0
|
|
898
|
+
*/
|
|
899
|
+
var SocketWriteError = class extends (/*#__PURE__*/ Error$1("effect/socket/Socket/SocketWriteError")({
|
|
900
|
+
_tag: /*#__PURE__*/ tag("SocketWriteError"),
|
|
901
|
+
cause: /*#__PURE__*/ Defect()
|
|
902
|
+
})) {
|
|
903
|
+
/**
|
|
904
|
+
* Default message used for socket write failures.
|
|
905
|
+
*
|
|
906
|
+
* @stability unstable
|
|
907
|
+
* @since 4.0.0
|
|
908
|
+
*/
|
|
909
|
+
message = `An error occurred during Write`;
|
|
910
|
+
};
|
|
911
|
+
/**
|
|
912
|
+
* Typed error for failures that occur while opening a socket, including
|
|
913
|
+
* unknown open failures and open timeouts.
|
|
914
|
+
*
|
|
915
|
+
* @stability unstable
|
|
916
|
+
* @category errors
|
|
917
|
+
* @since 4.0.0
|
|
918
|
+
*/
|
|
919
|
+
var SocketOpenError = class extends (/*#__PURE__*/ Error$1("effect/socket/Socket/SocketOpenError")({
|
|
920
|
+
_tag: /*#__PURE__*/ tag("SocketOpenError"),
|
|
921
|
+
kind: /*#__PURE__*/ Literals(["Unknown", "Timeout"]),
|
|
922
|
+
cause: /*#__PURE__*/ Defect()
|
|
923
|
+
})) {
|
|
924
|
+
/**
|
|
925
|
+
* Formats timeout and unknown open failures for display.
|
|
926
|
+
*
|
|
927
|
+
* @stability unstable
|
|
928
|
+
* @since 4.0.0
|
|
929
|
+
*/
|
|
930
|
+
get message() {
|
|
931
|
+
return this.kind === "Timeout" ? `timeout waiting for "open"` : `An error occurred during Open`;
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* Typed error for an unsupported or failed in-place TLS upgrade.
|
|
936
|
+
*
|
|
937
|
+
* @stability unstable
|
|
938
|
+
* @category errors
|
|
939
|
+
* @since 4.0.0
|
|
940
|
+
*/
|
|
941
|
+
var SocketUpgradeError = class SocketUpgradeError extends (/*#__PURE__*/ Error$1("effect/socket/Socket/SocketUpgradeError")({
|
|
942
|
+
_tag: /*#__PURE__*/ tag("SocketUpgradeError"),
|
|
943
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Defect())
|
|
944
|
+
})) {
|
|
945
|
+
/**
|
|
946
|
+
* An upgrade implementation for transports that cannot wrap the connection
|
|
947
|
+
* with TLS.
|
|
948
|
+
*
|
|
949
|
+
* @stability unstable
|
|
950
|
+
* @since 4.0.0
|
|
951
|
+
*/
|
|
952
|
+
static unsupported = () => fail(new SocketError({ reason: new SocketUpgradeError({}) }));
|
|
953
|
+
get message() {
|
|
954
|
+
return this.cause === void 0 ? `Socket does not support TLS upgrade` : `An error occurred during TLS upgrade`;
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
/**
|
|
958
|
+
* Typed error for a socket close, carrying the close code and optional close
|
|
959
|
+
* reason.
|
|
960
|
+
*
|
|
961
|
+
* **Details**
|
|
962
|
+
*
|
|
963
|
+
* Sockets never classify closes: any close, whatever the code, fails the
|
|
964
|
+
* reader with a `SocketError` wrapping this reason. Consumers that treat a
|
|
965
|
+
* close as normal catch it.
|
|
966
|
+
*
|
|
967
|
+
* @stability unstable
|
|
968
|
+
* @category errors
|
|
969
|
+
* @since 4.0.0
|
|
970
|
+
*/
|
|
971
|
+
var SocketCloseError = class extends (/*#__PURE__*/ Error$1("effect/socket/Socket/SocketCloseError")({
|
|
972
|
+
_tag: /*#__PURE__*/ tag("SocketCloseError"),
|
|
973
|
+
code: Int,
|
|
974
|
+
closeReason: /*#__PURE__*/ optional(String$1)
|
|
975
|
+
})) {
|
|
976
|
+
get message() {
|
|
977
|
+
if (this.closeReason) return `${this.code}: ${this.closeReason}`;
|
|
978
|
+
return `${this.code}`;
|
|
979
|
+
}
|
|
980
|
+
};
|
|
981
|
+
/**
|
|
982
|
+
* Schema for all socket-specific error reasons.
|
|
983
|
+
*
|
|
984
|
+
* @stability unstable
|
|
985
|
+
* @category errors
|
|
986
|
+
* @since 4.0.0
|
|
987
|
+
*/
|
|
988
|
+
const SocketErrorReason = /*#__PURE__*/ Union([
|
|
989
|
+
SocketReadError,
|
|
990
|
+
SocketWriteError,
|
|
991
|
+
SocketOpenError,
|
|
992
|
+
SocketUpgradeError,
|
|
993
|
+
SocketCloseError
|
|
994
|
+
]);
|
|
995
|
+
/**
|
|
996
|
+
* Tagged error that wraps socket read, write, open, upgrade, and close failures
|
|
997
|
+
* while preserving the underlying reason.
|
|
998
|
+
*
|
|
999
|
+
* @stability unstable
|
|
1000
|
+
* @category errors
|
|
1001
|
+
* @since 4.0.0
|
|
1002
|
+
*/
|
|
1003
|
+
var SocketError = class extends (/*#__PURE__*/ TaggedError(SocketErrorTypeId)("SocketError", {
|
|
1004
|
+
_tag: /*#__PURE__*/ tag("SocketError"),
|
|
1005
|
+
reason: SocketErrorReason
|
|
1006
|
+
})) {
|
|
1007
|
+
constructor(props) {
|
|
1008
|
+
if ("cause" in props.reason) super({
|
|
1009
|
+
...props,
|
|
1010
|
+
cause: props.reason.cause
|
|
1011
|
+
});
|
|
1012
|
+
else super(props);
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Marks this value as a socket error wrapper for runtime guards.
|
|
1016
|
+
*
|
|
1017
|
+
* @stability unstable
|
|
1018
|
+
* @since 4.0.0
|
|
1019
|
+
*/
|
|
1020
|
+
[SocketErrorTypeId] = SocketErrorTypeId;
|
|
1021
|
+
/**
|
|
1022
|
+
* Returns `true` when the value is a `SocketError`.
|
|
1023
|
+
*
|
|
1024
|
+
* @stability unstable
|
|
1025
|
+
* @since 4.0.0
|
|
1026
|
+
*/
|
|
1027
|
+
static is(u) {
|
|
1028
|
+
return isSocketError(u);
|
|
1029
|
+
}
|
|
1030
|
+
message = this.reason.message;
|
|
1031
|
+
};
|
|
1032
|
+
const closeError = (code, closeReason) => new SocketError({ reason: new SocketCloseError({
|
|
1033
|
+
code,
|
|
1034
|
+
closeReason
|
|
1035
|
+
}) });
|
|
1036
|
+
const isPausable = (ws) => "pause" in ws && typeof ws.pause === "function";
|
|
1037
|
+
/**
|
|
1038
|
+
* Builds a `Socket` from a scoped WebSocket acquisition effect.
|
|
1039
|
+
*
|
|
1040
|
+
* **Details**
|
|
1041
|
+
*
|
|
1042
|
+
* Reader acquisition runs `acquire`, attaches event listeners, then waits for
|
|
1043
|
+
* the socket to open. Implementations exposing `pause`/`resume` (the `ws`
|
|
1044
|
+
* package) remain flowing until buffered frames reach the configured
|
|
1045
|
+
* `highWaterMark` (64 KiB by default). Draining the buffer resumes the
|
|
1046
|
+
* transport. Incoming frames that arrive in the same tick are coalesced into
|
|
1047
|
+
* one batch. Implementations without pause (browsers) buffer incoming frames,
|
|
1048
|
+
* optionally failing the socket with a `SocketReadError` when `highWaterMark`
|
|
1049
|
+
* bytes are exceeded (default unbounded). Message boundaries survive: each
|
|
1050
|
+
* pulled batch contains one element per frame.
|
|
1051
|
+
*
|
|
1052
|
+
* @stability unstable
|
|
1053
|
+
* @category constructors
|
|
1054
|
+
* @since 4.0.0
|
|
1055
|
+
*/
|
|
1056
|
+
const fromWebSocket = (acquire, options) => withFiber((fiber) => {
|
|
1057
|
+
let currentWS;
|
|
1058
|
+
const latch = makeUnsafe$4(false);
|
|
1059
|
+
const acquireContext = fiber.context;
|
|
1060
|
+
const reader = gen(function* () {
|
|
1061
|
+
const scope$2 = yield* scope;
|
|
1062
|
+
const ws = yield* provide(acquire, scope$2);
|
|
1063
|
+
if ("binaryType" in ws) ws.binaryType = "arraybuffer";
|
|
1064
|
+
const pausable = isPausable(ws);
|
|
1065
|
+
const highWaterMark = options?.highWaterMark ?? (pausable ? defaultHighWaterMark : void 0);
|
|
1066
|
+
let open = ws.readyState === 1;
|
|
1067
|
+
let paused = pausable && "isPaused" in ws && ws.isPaused === true;
|
|
1068
|
+
let buffer = [];
|
|
1069
|
+
let bufferSize = 0;
|
|
1070
|
+
let error;
|
|
1071
|
+
let waiter;
|
|
1072
|
+
let openWaiter;
|
|
1073
|
+
function pauseWebSocket() {
|
|
1074
|
+
if (!pausable || paused) return;
|
|
1075
|
+
ws.pause();
|
|
1076
|
+
paused = true;
|
|
1077
|
+
}
|
|
1078
|
+
function resumeWebSocket() {
|
|
1079
|
+
if (!pausable || !paused) return;
|
|
1080
|
+
ws.resume();
|
|
1081
|
+
paused = false;
|
|
1082
|
+
}
|
|
1083
|
+
function takeBuffer() {
|
|
1084
|
+
const chunk = buffer;
|
|
1085
|
+
buffer = [];
|
|
1086
|
+
bufferSize = 0;
|
|
1087
|
+
if (error === void 0) resumeWebSocket();
|
|
1088
|
+
return chunk;
|
|
1089
|
+
}
|
|
1090
|
+
function deliver() {
|
|
1091
|
+
if (waiter === void 0 || buffer.length === 0) return;
|
|
1092
|
+
const resume = waiter;
|
|
1093
|
+
waiter = void 0;
|
|
1094
|
+
resume(succeed(takeBuffer()));
|
|
1095
|
+
}
|
|
1096
|
+
function push(data) {
|
|
1097
|
+
buffer.push(data);
|
|
1098
|
+
if (highWaterMark !== void 0) bufferSize += typeof data === "string" ? encoder$1.encode(data).byteLength : data.byteLength;
|
|
1099
|
+
if (waiter !== void 0) deliver();
|
|
1100
|
+
if (pausable && bufferSize >= highWaterMark) pauseWebSocket();
|
|
1101
|
+
else if (!pausable && !waiter && highWaterMark !== void 0 && bufferSize > highWaterMark) fail$2(new SocketError({ reason: new SocketReadError({ cause: /* @__PURE__ */ new Error(`Socket highWaterMark of ${highWaterMark} bytes exceeded`) }) }));
|
|
1102
|
+
}
|
|
1103
|
+
function fail$2(err) {
|
|
1104
|
+
if (error === void 0) error = err;
|
|
1105
|
+
if (openWaiter !== void 0) {
|
|
1106
|
+
const { cleanup, resume } = openWaiter;
|
|
1107
|
+
openWaiter = void 0;
|
|
1108
|
+
cleanup();
|
|
1109
|
+
resume(fail(error));
|
|
1110
|
+
}
|
|
1111
|
+
if (waiter !== void 0) {
|
|
1112
|
+
const resume = waiter;
|
|
1113
|
+
waiter = void 0;
|
|
1114
|
+
resume(buffer.length > 0 ? succeed(takeBuffer()) : fail(error));
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
function onMessage(event) {
|
|
1118
|
+
const data = event.data;
|
|
1119
|
+
if (typeof Blob !== "undefined" && data instanceof Blob) {
|
|
1120
|
+
data.arrayBuffer().then((buf) => push(new Uint8Array(buf)), (cause) => {
|
|
1121
|
+
fail$2(new SocketError({ reason: new SocketReadError({ cause }) }));
|
|
1122
|
+
});
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
push(data instanceof ArrayBuffer ? new Uint8Array(data) : data);
|
|
1126
|
+
}
|
|
1127
|
+
function onError(event) {
|
|
1128
|
+
fail$2(new SocketError({ reason: open ? new SocketReadError({ cause: event }) : new SocketOpenError({
|
|
1129
|
+
kind: "Unknown",
|
|
1130
|
+
cause: event
|
|
1131
|
+
}) }));
|
|
1132
|
+
}
|
|
1133
|
+
function onClose(event) {
|
|
1134
|
+
fail$2(closeError(typeof event.code === "number" ? event.code : 1006, event.reason));
|
|
1135
|
+
}
|
|
1136
|
+
ws.addEventListener("message", onMessage);
|
|
1137
|
+
ws.addEventListener("error", onError, { once: true });
|
|
1138
|
+
ws.addEventListener("close", onClose, { once: true });
|
|
1139
|
+
yield* addFinalizer$1(scope$2, sync(() => {
|
|
1140
|
+
fail$2(closeError(1006));
|
|
1141
|
+
ws.removeEventListener("message", onMessage);
|
|
1142
|
+
ws.addEventListener("error", constVoid);
|
|
1143
|
+
ws.removeEventListener("error", onError);
|
|
1144
|
+
ws.removeEventListener("close", onClose);
|
|
1145
|
+
if (pausable) try {
|
|
1146
|
+
resumeWebSocket();
|
|
1147
|
+
} catch {}
|
|
1148
|
+
latch.closeUnsafe();
|
|
1149
|
+
currentWS = void 0;
|
|
1150
|
+
}));
|
|
1151
|
+
if (ws.readyState >= 2) return yield* fail(error ?? closeError(1006));
|
|
1152
|
+
if (!open) {
|
|
1153
|
+
yield* callback((resume) => {
|
|
1154
|
+
const onOpen = () => {
|
|
1155
|
+
if (openWaiter?.resume !== resume) return;
|
|
1156
|
+
openWaiter = void 0;
|
|
1157
|
+
ws.removeEventListener("open", onOpen);
|
|
1158
|
+
resume(void_);
|
|
1159
|
+
};
|
|
1160
|
+
const cleanup = () => ws.removeEventListener("open", onOpen);
|
|
1161
|
+
openWaiter = {
|
|
1162
|
+
resume,
|
|
1163
|
+
cleanup
|
|
1164
|
+
};
|
|
1165
|
+
ws.addEventListener("open", onOpen, { once: true });
|
|
1166
|
+
return sync(() => {
|
|
1167
|
+
if (openWaiter?.resume === resume) openWaiter = void 0;
|
|
1168
|
+
cleanup();
|
|
1169
|
+
});
|
|
1170
|
+
}).pipe(timeoutOrElse({
|
|
1171
|
+
duration: options?.openTimeout ?? 1e4,
|
|
1172
|
+
orElse: () => fail(new SocketError({ reason: new SocketOpenError({
|
|
1173
|
+
kind: "Timeout",
|
|
1174
|
+
cause: /* @__PURE__ */ new Error("timeout waiting for \"open\"")
|
|
1175
|
+
}) }))
|
|
1176
|
+
}));
|
|
1177
|
+
open = true;
|
|
1178
|
+
}
|
|
1179
|
+
if (error === void 0 && bufferSize < highWaterMark) resumeWebSocket();
|
|
1180
|
+
currentWS = ws;
|
|
1181
|
+
latch.openUnsafe();
|
|
1182
|
+
return {
|
|
1183
|
+
pull: callback((resume) => {
|
|
1184
|
+
if (buffer.length > 0) return resume(succeed(takeBuffer()));
|
|
1185
|
+
if (error !== void 0) return resume(fail(error));
|
|
1186
|
+
waiter = resume;
|
|
1187
|
+
return sync(() => {
|
|
1188
|
+
if (waiter === resume) waiter = void 0;
|
|
1189
|
+
});
|
|
1190
|
+
}),
|
|
1191
|
+
upgrade: SocketUpgradeError.unsupported
|
|
1192
|
+
};
|
|
1193
|
+
}).pipe(updateContext((input) => merge(acquireContext, input)));
|
|
1194
|
+
const write = (chunk) => suspend$1(() => {
|
|
1195
|
+
const ws = currentWS;
|
|
1196
|
+
if (ws === void 0) return latch.whenOpen(write(chunk));
|
|
1197
|
+
try {
|
|
1198
|
+
if (isCloseEvent(chunk)) ws.close(chunk.code, chunk.reason);
|
|
1199
|
+
else ws.send(chunk);
|
|
1200
|
+
return void_;
|
|
1201
|
+
} catch (cause) {
|
|
1202
|
+
return fail(new SocketError({ reason: new SocketWriteError({ cause }) }));
|
|
1203
|
+
}
|
|
1204
|
+
});
|
|
1205
|
+
const writeAll = (chunks) => suspend$1(() => {
|
|
1206
|
+
const ws = currentWS;
|
|
1207
|
+
if (ws === void 0) return latch.whenOpen(writeAll(chunks));
|
|
1208
|
+
try {
|
|
1209
|
+
for (let i = 0; i < chunks.length; i++) ws.send(chunks[i]);
|
|
1210
|
+
return void_;
|
|
1211
|
+
} catch (cause) {
|
|
1212
|
+
return fail(new SocketError({ reason: new SocketWriteError({ cause }) }));
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
const writer = succeed({
|
|
1216
|
+
write,
|
|
1217
|
+
writeAll
|
|
1218
|
+
});
|
|
1219
|
+
return succeed(make$3({
|
|
1220
|
+
reader,
|
|
1221
|
+
writer
|
|
1222
|
+
}));
|
|
1223
|
+
});
|
|
1224
|
+
const defaultHighWaterMark = 65536;
|
|
1225
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcSchema.js
|
|
1226
|
+
/**
|
|
1227
|
+
* RPC schema markers and interruption annotations.
|
|
1228
|
+
*
|
|
1229
|
+
* This module contains the small pieces of schema metadata that the RPC
|
|
1230
|
+
* declaration, client, server, cluster, and reactivity layers share. It marks
|
|
1231
|
+
* streamed responses and annotates interruptions that came from a remote client
|
|
1232
|
+
* closing or cancelling a request.
|
|
1233
|
+
*
|
|
1234
|
+
* @stability unstable
|
|
1235
|
+
* @since 4.0.0
|
|
1236
|
+
*/
|
|
1237
|
+
const StreamSchemaTypeId = "~effect/rpc/RpcSchema/StreamSchema";
|
|
1238
|
+
/**
|
|
1239
|
+
* Returns `true` when a schema is an RPC stream schema created by
|
|
1240
|
+
* `RpcSchema.Stream`.
|
|
1241
|
+
*
|
|
1242
|
+
* @stability unstable
|
|
1243
|
+
* @category guards
|
|
1244
|
+
* @since 4.0.0
|
|
1245
|
+
*/
|
|
1246
|
+
function isStreamSchema(schema) {
|
|
1247
|
+
return hasProperty(schema, StreamSchemaTypeId);
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* @internal
|
|
1251
|
+
*/
|
|
1252
|
+
function getStreamSchemas(schema) {
|
|
1253
|
+
return isStreamSchema(schema) ? some({
|
|
1254
|
+
success: schema.success,
|
|
1255
|
+
error: schema.error
|
|
1256
|
+
}) : none$1();
|
|
1257
|
+
}
|
|
1258
|
+
const schema = /*#__PURE__*/ declare(isStream);
|
|
1259
|
+
/**
|
|
1260
|
+
* Creates an RPC stream schema from a stream element success schema and stream
|
|
1261
|
+
* error schema.
|
|
1262
|
+
*
|
|
1263
|
+
* @stability unstable
|
|
1264
|
+
* @category constructors
|
|
1265
|
+
* @since 4.0.0
|
|
1266
|
+
*/
|
|
1267
|
+
function Stream(success, error) {
|
|
1268
|
+
return make$8(schema.ast, {
|
|
1269
|
+
[StreamSchemaTypeId]: StreamSchemaTypeId,
|
|
1270
|
+
success,
|
|
1271
|
+
error
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Annotation that marks interruptions that originate from an RPC client
|
|
1276
|
+
* abort.
|
|
1277
|
+
*
|
|
1278
|
+
* @stability unstable
|
|
1279
|
+
* @category services
|
|
1280
|
+
* @since 4.0.0
|
|
1281
|
+
*/
|
|
1282
|
+
var ClientAbort = class extends (/*#__PURE__*/ Service$1()("effect/rpc/RpcSchema/ClientAbort")) {
|
|
1283
|
+
static annotation = /*#__PURE__*/ this.context(true).pipe(/*#__PURE__*/ add(StackTrace, {
|
|
1284
|
+
name: "ClientAbort",
|
|
1285
|
+
stack: constUndefined,
|
|
1286
|
+
parent: void 0
|
|
1287
|
+
}));
|
|
1288
|
+
};
|
|
1289
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/Rpc.js
|
|
1290
|
+
const TypeId$2 = "~effect/rpc/Rpc";
|
|
1291
|
+
/**
|
|
1292
|
+
* Represents server-side metadata for the client associated with an RPC request.
|
|
1293
|
+
*
|
|
1294
|
+
* **When to use**
|
|
1295
|
+
*
|
|
1296
|
+
* Use to inspect or annotate the connected client while handling an RPC request
|
|
1297
|
+
* on the server.
|
|
1298
|
+
*
|
|
1299
|
+
* **Details**
|
|
1300
|
+
*
|
|
1301
|
+
* It stores the client id and request annotations that handlers can read or
|
|
1302
|
+
* extend.
|
|
1303
|
+
*
|
|
1304
|
+
* @stability unstable
|
|
1305
|
+
* @category models
|
|
1306
|
+
* @since 4.0.0
|
|
1307
|
+
*/
|
|
1308
|
+
var ServerClient = class {
|
|
1309
|
+
id;
|
|
1310
|
+
annotations;
|
|
1311
|
+
constructor(id) {
|
|
1312
|
+
this.id = id;
|
|
1313
|
+
this.annotations = empty();
|
|
1314
|
+
}
|
|
1315
|
+
annotate(tag, value) {
|
|
1316
|
+
this.annotations = add(this.annotations, tag, value);
|
|
1317
|
+
return this;
|
|
1318
|
+
}
|
|
1319
|
+
};
|
|
1320
|
+
const Proto = {
|
|
1321
|
+
[TypeId$2]: TypeId$2,
|
|
1322
|
+
pipe() {
|
|
1323
|
+
return pipeArguments(this, arguments);
|
|
1324
|
+
},
|
|
1325
|
+
setSuccess(successSchema) {
|
|
1326
|
+
return makeProto$1({
|
|
1327
|
+
_tag: this._tag,
|
|
1328
|
+
payloadSchema: this.payloadSchema,
|
|
1329
|
+
successSchema,
|
|
1330
|
+
errorSchema: this.errorSchema,
|
|
1331
|
+
defectSchema: this.defectSchema,
|
|
1332
|
+
annotations: this.annotations,
|
|
1333
|
+
middlewares: this.middlewares
|
|
1334
|
+
});
|
|
1335
|
+
},
|
|
1336
|
+
setError(errorSchema) {
|
|
1337
|
+
return makeProto$1({
|
|
1338
|
+
_tag: this._tag,
|
|
1339
|
+
payloadSchema: this.payloadSchema,
|
|
1340
|
+
successSchema: this.successSchema,
|
|
1341
|
+
errorSchema,
|
|
1342
|
+
defectSchema: this.defectSchema,
|
|
1343
|
+
annotations: this.annotations,
|
|
1344
|
+
middlewares: this.middlewares
|
|
1345
|
+
});
|
|
1346
|
+
},
|
|
1347
|
+
setPayload(payloadSchema) {
|
|
1348
|
+
return makeProto$1({
|
|
1349
|
+
_tag: this._tag,
|
|
1350
|
+
payloadSchema: isSchema(payloadSchema) ? payloadSchema : Struct(payloadSchema),
|
|
1351
|
+
successSchema: this.successSchema,
|
|
1352
|
+
errorSchema: this.errorSchema,
|
|
1353
|
+
defectSchema: this.defectSchema,
|
|
1354
|
+
annotations: this.annotations,
|
|
1355
|
+
middlewares: this.middlewares
|
|
1356
|
+
});
|
|
1357
|
+
},
|
|
1358
|
+
middleware(middleware) {
|
|
1359
|
+
return makeProto$1({
|
|
1360
|
+
_tag: this._tag,
|
|
1361
|
+
payloadSchema: this.payloadSchema,
|
|
1362
|
+
successSchema: this.successSchema,
|
|
1363
|
+
errorSchema: this.errorSchema,
|
|
1364
|
+
defectSchema: this.defectSchema,
|
|
1365
|
+
annotations: this.annotations,
|
|
1366
|
+
middlewares: /* @__PURE__ */ new Set([...this.middlewares, middleware])
|
|
1367
|
+
});
|
|
1368
|
+
},
|
|
1369
|
+
prefix(prefix) {
|
|
1370
|
+
return makeProto$1({
|
|
1371
|
+
_tag: `${prefix}${this._tag}`,
|
|
1372
|
+
payloadSchema: this.payloadSchema,
|
|
1373
|
+
successSchema: this.successSchema,
|
|
1374
|
+
errorSchema: this.errorSchema,
|
|
1375
|
+
defectSchema: this.defectSchema,
|
|
1376
|
+
annotations: this.annotations,
|
|
1377
|
+
middlewares: this.middlewares
|
|
1378
|
+
});
|
|
1379
|
+
},
|
|
1380
|
+
annotate(tag, value) {
|
|
1381
|
+
return makeProto$1({
|
|
1382
|
+
_tag: this._tag,
|
|
1383
|
+
payloadSchema: this.payloadSchema,
|
|
1384
|
+
successSchema: this.successSchema,
|
|
1385
|
+
errorSchema: this.errorSchema,
|
|
1386
|
+
defectSchema: this.defectSchema,
|
|
1387
|
+
middlewares: this.middlewares,
|
|
1388
|
+
annotations: add(this.annotations, tag, value)
|
|
1389
|
+
});
|
|
1390
|
+
},
|
|
1391
|
+
annotateMerge(context) {
|
|
1392
|
+
return makeProto$1({
|
|
1393
|
+
_tag: this._tag,
|
|
1394
|
+
payloadSchema: this.payloadSchema,
|
|
1395
|
+
successSchema: this.successSchema,
|
|
1396
|
+
errorSchema: this.errorSchema,
|
|
1397
|
+
defectSchema: this.defectSchema,
|
|
1398
|
+
middlewares: this.middlewares,
|
|
1399
|
+
annotations: merge(this.annotations, context)
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
const makeProto$1 = (options) => {
|
|
1404
|
+
function Rpc() {}
|
|
1405
|
+
Object.setPrototypeOf(Rpc, Proto);
|
|
1406
|
+
Object.assign(Rpc, options);
|
|
1407
|
+
Rpc.key = `effect/rpc/Rpc/${options._tag}`;
|
|
1408
|
+
return Rpc;
|
|
1409
|
+
};
|
|
1410
|
+
/**
|
|
1411
|
+
* Creates an RPC definition with the supplied tag and optional schemas.
|
|
1412
|
+
*
|
|
1413
|
+
* **Details**
|
|
1414
|
+
*
|
|
1415
|
+
* Payload options can be either a schema or struct fields. `stream: true` wraps
|
|
1416
|
+
* the success and error schemas in a stream schema and sets the normal error
|
|
1417
|
+
* schema to `Schema.Never`. `primaryKey` creates a payload class with a
|
|
1418
|
+
* primary key derived from the payload value.
|
|
1419
|
+
*
|
|
1420
|
+
* @stability unstable
|
|
1421
|
+
* @category constructors
|
|
1422
|
+
* @since 4.0.0
|
|
1423
|
+
*/
|
|
1424
|
+
const make$2 = (tag, options) => {
|
|
1425
|
+
const successSchema = options?.success ?? Void;
|
|
1426
|
+
const errorSchema = options?.error ?? Never;
|
|
1427
|
+
const defectSchema = options?.defect ?? Defect();
|
|
1428
|
+
let payloadSchema;
|
|
1429
|
+
if (options?.primaryKey) payloadSchema = class Payload extends Class(`effect/rpc/Rpc/${tag}`)(options.payload) {
|
|
1430
|
+
[symbol]() {
|
|
1431
|
+
return options.primaryKey(this);
|
|
1432
|
+
}
|
|
1433
|
+
};
|
|
1434
|
+
else payloadSchema = isSchema(options?.payload) ? options?.payload : options?.payload ? Struct(options?.payload) : Void;
|
|
1435
|
+
return makeProto$1({
|
|
1436
|
+
_tag: tag,
|
|
1437
|
+
payloadSchema,
|
|
1438
|
+
successSchema: options?.stream ? Stream(successSchema, errorSchema) : successSchema,
|
|
1439
|
+
errorSchema: options?.stream ? Never : errorSchema,
|
|
1440
|
+
defectSchema,
|
|
1441
|
+
annotations: empty(),
|
|
1442
|
+
middlewares: /* @__PURE__ */ new Set()
|
|
1443
|
+
});
|
|
1444
|
+
};
|
|
1445
|
+
const exitSchemaCache = /*#__PURE__*/ new WeakMap();
|
|
1446
|
+
/**
|
|
1447
|
+
* Builds the `Schema.Exit` used to encode and decode RPC results.
|
|
1448
|
+
*
|
|
1449
|
+
* **Details**
|
|
1450
|
+
*
|
|
1451
|
+
* The failure side includes the RPC error schema, middleware error schemas, and
|
|
1452
|
+
* stream error schema for streaming RPCs. Streaming RPCs use `Schema.Void` for
|
|
1453
|
+
* the exit success value. The schema is cached per RPC definition.
|
|
1454
|
+
*
|
|
1455
|
+
* @stability unstable
|
|
1456
|
+
* @category constructors
|
|
1457
|
+
* @since 4.0.0
|
|
1458
|
+
*/
|
|
1459
|
+
const exitSchema = (self) => {
|
|
1460
|
+
if (exitSchemaCache.has(self)) return exitSchemaCache.get(self);
|
|
1461
|
+
const rpc = self;
|
|
1462
|
+
const failures = /* @__PURE__ */ new Set([rpc.errorSchema]);
|
|
1463
|
+
const streamSchemas = getStreamSchemas(rpc.successSchema);
|
|
1464
|
+
if (isSome(streamSchemas)) failures.add(streamSchemas.value.error);
|
|
1465
|
+
for (const middleware of rpc.middlewares) failures.add(middleware.error);
|
|
1466
|
+
const schema = Exit(isSome(streamSchemas) ? Void : rpc.successSchema, Union([...failures]), rpc.defectSchema);
|
|
1467
|
+
exitSchemaCache.set(self, schema);
|
|
1468
|
+
return schema;
|
|
1469
|
+
};
|
|
1470
|
+
/**
|
|
1471
|
+
* Annotation that sets the schema parse options used by `RpcClient` and
|
|
1472
|
+
* `RpcServer` when encoding and decoding an RPC's payload, success values,
|
|
1473
|
+
* stream chunks, and exits.
|
|
1474
|
+
*
|
|
1475
|
+
* **Details**
|
|
1476
|
+
*
|
|
1477
|
+
* The default value is `SchemaAST.defaultParseOptions`. Set `concurrency` to
|
|
1478
|
+
* parse product elements concurrently, which lets decoding transformations that
|
|
1479
|
+
* call `Effect.request` share `RequestResolver` batches. Annotate a single RPC
|
|
1480
|
+
* with `annotate`, or every RPC in a group with `RpcGroup.annotateRpcs`.
|
|
1481
|
+
*
|
|
1482
|
+
* @stability unstable
|
|
1483
|
+
* @category annotations
|
|
1484
|
+
* @since 4.0.0
|
|
1485
|
+
*/
|
|
1486
|
+
const ParseOptions = /*#__PURE__*/ Reference("effect/rpc/Rpc/ParseOptions", { defaultValue: () => defaultParseOptions });
|
|
1487
|
+
const WrapperTypeId = "~effect/rpc/Rpc/Wrapper";
|
|
1488
|
+
/**
|
|
1489
|
+
* Returns `true` when the value is an RPC `Wrapper`.
|
|
1490
|
+
*
|
|
1491
|
+
* @stability unstable
|
|
1492
|
+
* @category guards
|
|
1493
|
+
* @since 4.0.0
|
|
1494
|
+
*/
|
|
1495
|
+
const isWrapper = (u) => WrapperTypeId in u;
|
|
1496
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcGroup.js
|
|
1497
|
+
const RpcGroupProto = {
|
|
1498
|
+
add(...rpcs) {
|
|
1499
|
+
const requests = new Map(this.requests);
|
|
1500
|
+
for (const rpc of rpcs) requests.set(rpc._tag, rpc);
|
|
1501
|
+
return makeProto({
|
|
1502
|
+
requests,
|
|
1503
|
+
annotations: this.annotations
|
|
1504
|
+
});
|
|
1505
|
+
},
|
|
1506
|
+
merge(...groups) {
|
|
1507
|
+
const requests = new Map(this.requests);
|
|
1508
|
+
const annotations = new Map(this.annotations.mapUnsafe);
|
|
1509
|
+
for (const group of groups) {
|
|
1510
|
+
for (const [tag, rpc] of group.requests) requests.set(tag, rpc);
|
|
1511
|
+
for (const [key, value] of group.annotations.mapUnsafe) annotations.set(key, value);
|
|
1512
|
+
}
|
|
1513
|
+
return makeProto({
|
|
1514
|
+
requests,
|
|
1515
|
+
annotations: makeUnsafe$2(annotations)
|
|
1516
|
+
});
|
|
1517
|
+
},
|
|
1518
|
+
omit(...tags) {
|
|
1519
|
+
const requests = new Map(this.requests);
|
|
1520
|
+
for (const tag of tags) requests.delete(tag);
|
|
1521
|
+
return makeProto({
|
|
1522
|
+
requests,
|
|
1523
|
+
annotations: this.annotations
|
|
1524
|
+
});
|
|
1525
|
+
},
|
|
1526
|
+
middleware(middleware) {
|
|
1527
|
+
const requests = /* @__PURE__ */ new Map();
|
|
1528
|
+
for (const [tag, rpc] of this.requests) requests.set(tag, rpc.middleware(middleware));
|
|
1529
|
+
return makeProto({
|
|
1530
|
+
requests,
|
|
1531
|
+
annotations: this.annotations
|
|
1532
|
+
});
|
|
1533
|
+
},
|
|
1534
|
+
toHandlers(build) {
|
|
1535
|
+
const self = this;
|
|
1536
|
+
return gen(function* () {
|
|
1537
|
+
const services = yield* context();
|
|
1538
|
+
const handlers = isEffect(build) ? yield* build : build;
|
|
1539
|
+
const contextMap = /* @__PURE__ */ new Map();
|
|
1540
|
+
self.requests.forEach((rpc, tag) => {
|
|
1541
|
+
contextMap.set(rpc.key, {
|
|
1542
|
+
tag: rpc._tag,
|
|
1543
|
+
handler: handlers[tag],
|
|
1544
|
+
context: services
|
|
1545
|
+
});
|
|
1546
|
+
});
|
|
1547
|
+
return makeUnsafe$2(contextMap);
|
|
1548
|
+
});
|
|
1549
|
+
},
|
|
1550
|
+
prefix(prefix) {
|
|
1551
|
+
const requests = /* @__PURE__ */ new Map();
|
|
1552
|
+
for (const rpc of this.requests.values()) {
|
|
1553
|
+
const newRpc = rpc.prefix(prefix);
|
|
1554
|
+
requests.set(newRpc._tag, newRpc);
|
|
1555
|
+
}
|
|
1556
|
+
return makeProto({
|
|
1557
|
+
requests,
|
|
1558
|
+
annotations: this.annotations
|
|
1559
|
+
});
|
|
1560
|
+
},
|
|
1561
|
+
toLayer(build) {
|
|
1562
|
+
return effectContext(this.toHandlers(build));
|
|
1563
|
+
},
|
|
1564
|
+
of: identity,
|
|
1565
|
+
toLayerHandler(service, build) {
|
|
1566
|
+
const self = this;
|
|
1567
|
+
return effectContext(gen(function* () {
|
|
1568
|
+
const services = yield* context();
|
|
1569
|
+
const handler = isEffect(build) ? yield* build : build;
|
|
1570
|
+
const contextMap = /* @__PURE__ */ new Map();
|
|
1571
|
+
const rpc = self.requests.get(service);
|
|
1572
|
+
contextMap.set(rpc.key, {
|
|
1573
|
+
handler,
|
|
1574
|
+
context: services
|
|
1575
|
+
});
|
|
1576
|
+
return makeUnsafe$2(contextMap);
|
|
1577
|
+
}));
|
|
1578
|
+
},
|
|
1579
|
+
accessHandler(service) {
|
|
1580
|
+
return contextWith((parentContext) => {
|
|
1581
|
+
const rpc = this.requests.get(service);
|
|
1582
|
+
const { handler, context } = getOrUndefinedUnsafe(parentContext, rpc.key);
|
|
1583
|
+
return succeed((payload, options) => {
|
|
1584
|
+
options.rpc = rpc;
|
|
1585
|
+
const result = handler(payload, options);
|
|
1586
|
+
const effectOrStream = isWrapper(result) ? result.value : result;
|
|
1587
|
+
return isEffect(effectOrStream) ? provide$1(effectOrStream, context) : provideContext$1(effectOrStream, context);
|
|
1588
|
+
});
|
|
1589
|
+
});
|
|
1590
|
+
},
|
|
1591
|
+
annotate(service, value) {
|
|
1592
|
+
return makeProto({
|
|
1593
|
+
requests: this.requests,
|
|
1594
|
+
annotations: add(this.annotations, service, value)
|
|
1595
|
+
});
|
|
1596
|
+
},
|
|
1597
|
+
annotateRpcs(service, value) {
|
|
1598
|
+
return this.annotateRpcsMerge(make$7(service, value));
|
|
1599
|
+
},
|
|
1600
|
+
annotateMerge(context) {
|
|
1601
|
+
return makeProto({
|
|
1602
|
+
requests: this.requests,
|
|
1603
|
+
annotations: merge(this.annotations, context)
|
|
1604
|
+
});
|
|
1605
|
+
},
|
|
1606
|
+
annotateRpcsMerge(context) {
|
|
1607
|
+
const requests = /* @__PURE__ */ new Map();
|
|
1608
|
+
for (const [tag, rpc] of this.requests) requests.set(tag, rpc.annotateMerge(merge(context, rpc.annotations)));
|
|
1609
|
+
return makeProto({
|
|
1610
|
+
requests,
|
|
1611
|
+
annotations: this.annotations
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
const makeProto = (options) => Object.assign(function() {}, RpcGroupProto, {
|
|
1616
|
+
requests: options.requests,
|
|
1617
|
+
annotations: options.annotations
|
|
1618
|
+
});
|
|
1619
|
+
/**
|
|
1620
|
+
* Creates an `RpcGroup` from one or more RPC definitions.
|
|
1621
|
+
*
|
|
1622
|
+
* @stability unstable
|
|
1623
|
+
* @category constructors
|
|
1624
|
+
* @since 4.0.0
|
|
1625
|
+
*/
|
|
1626
|
+
const make$1 = (...rpcs) => makeProto({
|
|
1627
|
+
requests: new Map(rpcs.map((rpc) => [rpc._tag, rpc])),
|
|
1628
|
+
annotations: empty()
|
|
1629
|
+
});
|
|
1630
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/workers/Transferable.js
|
|
1631
|
+
/**
|
|
1632
|
+
* Marks encoded worker message fields that should move through `postMessage` as
|
|
1633
|
+
* transfer-list entries.
|
|
1634
|
+
*
|
|
1635
|
+
* Worker messages still pass through schema encoding and structured clone, but
|
|
1636
|
+
* schemas wrapped with `schema` can also report backing resources such as
|
|
1637
|
+
* `ArrayBuffer`, `ImageData.data.buffer`, or `MessagePort` to a `Collector`.
|
|
1638
|
+
* Worker platforms then pass the collected values as the transfer list for the
|
|
1639
|
+
* same `postMessage` call, avoiding copies for large payloads and ports.
|
|
1640
|
+
*
|
|
1641
|
+
* @stability unstable
|
|
1642
|
+
* @since 4.0.0
|
|
1643
|
+
*/
|
|
1644
|
+
/**
|
|
1645
|
+
* Service for collecting `Transferable` objects while encoding worker messages
|
|
1646
|
+
* so they can be passed to `postMessage` transfer lists.
|
|
1647
|
+
*
|
|
1648
|
+
* @stability unstable
|
|
1649
|
+
* @category services
|
|
1650
|
+
* @since 4.0.0
|
|
1651
|
+
*/
|
|
1652
|
+
var Collector = class extends (/*#__PURE__*/ Service$1()("effect/workers/Transferable/Collector")) {};
|
|
1653
|
+
/**
|
|
1654
|
+
* Creates a mutable `Collector` service directly, exposing unsafe synchronous
|
|
1655
|
+
* methods for reading, adding, and clearing collected transferables.
|
|
1656
|
+
*
|
|
1657
|
+
* @stability unstable
|
|
1658
|
+
* @category constructors
|
|
1659
|
+
* @since 4.0.0
|
|
1660
|
+
*/
|
|
1661
|
+
const makeCollectorUnsafe = () => {
|
|
1662
|
+
let tranferables = [];
|
|
1663
|
+
const unsafeAddAll = (transfers) => {
|
|
1664
|
+
tranferables.push(...transfers);
|
|
1665
|
+
};
|
|
1666
|
+
const unsafeRead = () => tranferables;
|
|
1667
|
+
const unsafeClear = () => {
|
|
1668
|
+
const prev = tranferables;
|
|
1669
|
+
tranferables = [];
|
|
1670
|
+
return prev;
|
|
1671
|
+
};
|
|
1672
|
+
return Collector.of({
|
|
1673
|
+
addAllUnsafe: unsafeAddAll,
|
|
1674
|
+
addAll: (transferables) => sync(() => unsafeAddAll(transferables)),
|
|
1675
|
+
readUnsafe: unsafeRead,
|
|
1676
|
+
read: sync(unsafeRead),
|
|
1677
|
+
clearUnsafe: unsafeClear,
|
|
1678
|
+
clear: sync(unsafeClear)
|
|
1679
|
+
});
|
|
1680
|
+
};
|
|
1681
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/workers/WorkerError.js
|
|
1682
|
+
/**
|
|
1683
|
+
* Worker error reason for failures while spawning or setting up a worker.
|
|
1684
|
+
*
|
|
1685
|
+
* @stability unstable
|
|
1686
|
+
* @category errors
|
|
1687
|
+
* @since 4.0.0
|
|
1688
|
+
*/
|
|
1689
|
+
var WorkerSpawnError = class extends (/*#__PURE__*/ Error$1("effect/workers/WorkerError/WorkerSpawnError")({
|
|
1690
|
+
_tag: /*#__PURE__*/ tag("WorkerSpawnError"),
|
|
1691
|
+
message: String$1,
|
|
1692
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Defect())
|
|
1693
|
+
})) {};
|
|
1694
|
+
/**
|
|
1695
|
+
* Worker error reason for failures while sending a message to a worker.
|
|
1696
|
+
*
|
|
1697
|
+
* @stability unstable
|
|
1698
|
+
* @category errors
|
|
1699
|
+
* @since 4.0.0
|
|
1700
|
+
*/
|
|
1701
|
+
var WorkerSendError = class extends (/*#__PURE__*/ Error$1("effect/workers/WorkerError/WorkerSendError")({
|
|
1702
|
+
_tag: /*#__PURE__*/ tag("WorkerSendError"),
|
|
1703
|
+
message: String$1,
|
|
1704
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Defect())
|
|
1705
|
+
})) {};
|
|
1706
|
+
/**
|
|
1707
|
+
* Worker error reason for failures while receiving or handling a message from a
|
|
1708
|
+
* worker.
|
|
1709
|
+
*
|
|
1710
|
+
* @stability unstable
|
|
1711
|
+
* @category errors
|
|
1712
|
+
* @since 4.0.0
|
|
1713
|
+
*/
|
|
1714
|
+
var WorkerReceiveError = class extends (/*#__PURE__*/ Error$1("effect/workers/WorkerError/WorkerReceiveError")({
|
|
1715
|
+
_tag: /*#__PURE__*/ tag("WorkerReceiveError"),
|
|
1716
|
+
message: String$1,
|
|
1717
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Defect())
|
|
1718
|
+
})) {};
|
|
1719
|
+
/**
|
|
1720
|
+
* Worker error reason for an unclassified worker failure.
|
|
1721
|
+
*
|
|
1722
|
+
* @stability unstable
|
|
1723
|
+
* @category errors
|
|
1724
|
+
* @since 4.0.0
|
|
1725
|
+
*/
|
|
1726
|
+
var WorkerUnknownError = class extends (/*#__PURE__*/ Error$1("effect/workers/WorkerError/WorkerUnknownError")({
|
|
1727
|
+
_tag: /*#__PURE__*/ tag("WorkerUnknownError"),
|
|
1728
|
+
message: String$1,
|
|
1729
|
+
cause: /*#__PURE__*/ optional(/*#__PURE__*/ Defect())
|
|
1730
|
+
})) {};
|
|
1731
|
+
/**
|
|
1732
|
+
* Schema for decoding and encoding all supported worker error reason variants.
|
|
1733
|
+
*
|
|
1734
|
+
* @stability unstable
|
|
1735
|
+
* @category schemas
|
|
1736
|
+
* @since 4.0.0
|
|
1737
|
+
*/
|
|
1738
|
+
const WorkerErrorReason = /*#__PURE__*/ Union([
|
|
1739
|
+
WorkerSpawnError,
|
|
1740
|
+
WorkerSendError,
|
|
1741
|
+
WorkerReceiveError,
|
|
1742
|
+
WorkerUnknownError
|
|
1743
|
+
]);
|
|
1744
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/internal/tracing.js
|
|
1745
|
+
/**
|
|
1746
|
+
* Names the span after the RPC method, or `${spanPrefix}.${tag}` when a prefix
|
|
1747
|
+
* is configured.
|
|
1748
|
+
*
|
|
1749
|
+
* @internal
|
|
1750
|
+
*/
|
|
1751
|
+
const spanName = (spanPrefix, tag) => spanPrefix === void 0 ? tag : `${spanPrefix}.${tag}`;
|
|
1752
|
+
/**
|
|
1753
|
+
* Default RPC span attributes, overridden by user `spanAttributes`.
|
|
1754
|
+
*
|
|
1755
|
+
* @internal
|
|
1756
|
+
*/
|
|
1757
|
+
const spanAttributes = (tag, attributes) => ({
|
|
1758
|
+
"rpc.system.name": "effect_rpc",
|
|
1759
|
+
"rpc.method": tag,
|
|
1760
|
+
...attributes
|
|
1761
|
+
});
|
|
1762
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcClientError.js
|
|
1763
|
+
/**
|
|
1764
|
+
* Client-side protocol failures reported by unstable RPC transports.
|
|
1765
|
+
*
|
|
1766
|
+
* `RpcClientError` is the error type generated clients use when a call fails
|
|
1767
|
+
* before a remote handler can return its declared typed error. Its `reason`
|
|
1768
|
+
* covers built-in transport failures from HTTP, sockets, and workers, plus
|
|
1769
|
+
* `RpcClientDefect` values for malformed or incompatible protocol data.
|
|
1770
|
+
*
|
|
1771
|
+
* @stability unstable
|
|
1772
|
+
* @since 4.0.0
|
|
1773
|
+
*/
|
|
1774
|
+
const TypeId$1 = "~effect/rpc/RpcClientError";
|
|
1775
|
+
/**
|
|
1776
|
+
* Represents a client-side RPC defect, such as a protocol violation or
|
|
1777
|
+
* decoding failure, with a message and original cause.
|
|
1778
|
+
*
|
|
1779
|
+
* @stability unstable
|
|
1780
|
+
* @category errors
|
|
1781
|
+
* @since 4.0.0
|
|
1782
|
+
*/
|
|
1783
|
+
var RpcClientDefect = class extends (/*#__PURE__*/ Error$1("effect/rpc/RpcClientError/RpcClientDefect")({
|
|
1784
|
+
_tag: /*#__PURE__*/ tag("RpcClientDefect"),
|
|
1785
|
+
message: String$1,
|
|
1786
|
+
cause: /*#__PURE__*/ Defect()
|
|
1787
|
+
})) {};
|
|
1788
|
+
/**
|
|
1789
|
+
* Error wrapper for RPC client failures, including worker, socket, HTTP client,
|
|
1790
|
+
* and client protocol defect failures.
|
|
1791
|
+
*
|
|
1792
|
+
* @stability unstable
|
|
1793
|
+
* @category errors
|
|
1794
|
+
* @since 4.0.0
|
|
1795
|
+
*/
|
|
1796
|
+
var RpcClientError = class extends (/*#__PURE__*/ Error$1(TypeId$1)({
|
|
1797
|
+
_tag: /*#__PURE__*/ tag("RpcClientError"),
|
|
1798
|
+
reason: /*#__PURE__*/ Union([
|
|
1799
|
+
WorkerErrorReason,
|
|
1800
|
+
SocketErrorReason,
|
|
1801
|
+
HttpClientErrorSchema,
|
|
1802
|
+
RpcClientDefect
|
|
1803
|
+
])
|
|
1804
|
+
})) {
|
|
1805
|
+
/**
|
|
1806
|
+
* Marks this value as an RPC client error for runtime guards.
|
|
1807
|
+
*
|
|
1808
|
+
* @stability unstable
|
|
1809
|
+
* @since 4.0.0
|
|
1810
|
+
*/
|
|
1811
|
+
[TypeId$1] = TypeId$1;
|
|
1812
|
+
get message() {
|
|
1813
|
+
return `${this.reason._tag}: ${this.reason.message}`;
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcMessage.js
|
|
1817
|
+
/**
|
|
1818
|
+
* Converts a bigint or string request id into the branded `RequestId` type.
|
|
1819
|
+
*
|
|
1820
|
+
* @stability unstable
|
|
1821
|
+
* @category constructors
|
|
1822
|
+
* @since 4.0.0
|
|
1823
|
+
*/
|
|
1824
|
+
const RequestId = (id) => id;
|
|
1825
|
+
/**
|
|
1826
|
+
* Represents the reusable `Eof` message value.
|
|
1827
|
+
*
|
|
1828
|
+
* @stability unstable
|
|
1829
|
+
* @category constants
|
|
1830
|
+
* @since 4.0.0
|
|
1831
|
+
*/
|
|
1832
|
+
const constEof = { _tag: "Eof" };
|
|
1833
|
+
/**
|
|
1834
|
+
* Represents the reusable `Ping` message value.
|
|
1835
|
+
*
|
|
1836
|
+
* @stability unstable
|
|
1837
|
+
* @category constants
|
|
1838
|
+
* @since 4.0.0
|
|
1839
|
+
*/
|
|
1840
|
+
const constPing = { _tag: "Ping" };
|
|
1841
|
+
/**
|
|
1842
|
+
* Creates a transport-encoded defect response around an already-encoded defect.
|
|
1843
|
+
*
|
|
1844
|
+
* **Details**
|
|
1845
|
+
*
|
|
1846
|
+
* Encode the defect with `protocol.codecFor(Schema.Defect())` before wrapping
|
|
1847
|
+
* it, because the codec that fills the defect hole belongs to the protocol.
|
|
1848
|
+
*
|
|
1849
|
+
* @stability unstable
|
|
1850
|
+
* @category constructors
|
|
1851
|
+
* @since 4.0.0
|
|
1852
|
+
*/
|
|
1853
|
+
const ResponseDefectEncoded = (encodedDefect) => ({
|
|
1854
|
+
_tag: "Defect",
|
|
1855
|
+
defect: encodedDefect
|
|
1856
|
+
});
|
|
1857
|
+
/**
|
|
1858
|
+
* Represents the reusable `Pong` message value.
|
|
1859
|
+
*
|
|
1860
|
+
* @stability unstable
|
|
1861
|
+
* @category constants
|
|
1862
|
+
* @since 4.0.0
|
|
1863
|
+
*/
|
|
1864
|
+
const constPong = { _tag: "Pong" };
|
|
1865
|
+
/**
|
|
1866
|
+
* Checks if the response type is terminal.
|
|
1867
|
+
*
|
|
1868
|
+
* @stability unstable
|
|
1869
|
+
* @category guards
|
|
1870
|
+
* @since 4.0.0
|
|
1871
|
+
*/
|
|
1872
|
+
const isTerminalResponse = (response) => {
|
|
1873
|
+
switch (response._tag) {
|
|
1874
|
+
case "Exit":
|
|
1875
|
+
case "Defect":
|
|
1876
|
+
case "ClientProtocolError": return true;
|
|
1877
|
+
default: return false;
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcSerialization.js
|
|
1881
|
+
/**
|
|
1882
|
+
* Serializes RPC protocol messages for transports.
|
|
1883
|
+
*
|
|
1884
|
+
* `RpcSerialization` is the boundary between `RpcMessage` envelopes and the
|
|
1885
|
+
* bytes or strings carried by a transport. This module provides built-in
|
|
1886
|
+
* serializers for JSON, newline-delimited JSON, JSON-RPC 2.0, and SchemaBinary,
|
|
1887
|
+
* including framed formats that can decode multiple messages
|
|
1888
|
+
* from streaming chunks.
|
|
1889
|
+
*
|
|
1890
|
+
* @stability unstable
|
|
1891
|
+
* @since 4.0.0
|
|
1892
|
+
*/
|
|
1893
|
+
const codecForJson = toCodecJson;
|
|
1894
|
+
let sharedTextDecoder;
|
|
1895
|
+
const decodeText = (bytes) => (sharedTextDecoder ??= new TextDecoder()).decode(bytes);
|
|
1896
|
+
/**
|
|
1897
|
+
* Service that describes how RPC protocol messages are encoded and decoded,
|
|
1898
|
+
* including the content type and whether the serialization format provides
|
|
1899
|
+
* message framing.
|
|
1900
|
+
*
|
|
1901
|
+
* **When to use**
|
|
1902
|
+
*
|
|
1903
|
+
* Use to provide the serialization boundary shared by RPC clients and servers
|
|
1904
|
+
* for a chosen wire format.
|
|
1905
|
+
*
|
|
1906
|
+
* @stability unstable
|
|
1907
|
+
* @category services
|
|
1908
|
+
* @since 4.0.0
|
|
1909
|
+
*/
|
|
1910
|
+
var RpcSerialization = class extends (/*#__PURE__*/ Service$1()("effect/rpc/RpcSerialization")) {};
|
|
1911
|
+
/**
|
|
1912
|
+
* Error raised when a streaming parser retains more data than its configured
|
|
1913
|
+
* buffer limit.
|
|
1914
|
+
*
|
|
1915
|
+
* @stability unstable
|
|
1916
|
+
* @category errors
|
|
1917
|
+
* @since 4.0.0
|
|
1918
|
+
*/
|
|
1919
|
+
var MaxBufferSizeExceeded = class extends (/*#__PURE__*/ TaggedError$1("MaxBufferSizeExceeded")) {
|
|
1920
|
+
get message() {
|
|
1921
|
+
return `RPC serialization buffer exceeded the maximum size of ${this.maxBufferSize}`;
|
|
1922
|
+
}
|
|
1923
|
+
};
|
|
1924
|
+
/**
|
|
1925
|
+
* Error raised when a non-empty NDJSON frame is not valid JSON.
|
|
1926
|
+
* The `cause` field preserves the original JSON parsing error.
|
|
1927
|
+
*
|
|
1928
|
+
* @stability unstable
|
|
1929
|
+
* @category errors
|
|
1930
|
+
* @since 4.0.0
|
|
1931
|
+
*/
|
|
1932
|
+
var NdjsonDecodeError = class extends (/*#__PURE__*/ TaggedError$1("NdjsonDecodeError")) {};
|
|
1933
|
+
const defaultMaxBufferSize = 16777216;
|
|
1934
|
+
const isBufferSizeExceeded = (bufferSize, maxBufferSize) => maxBufferSize !== "unbounded" && bufferSize > maxBufferSize;
|
|
1935
|
+
/**
|
|
1936
|
+
* JSON RPC serialization for whole message payloads. It does not include
|
|
1937
|
+
* message framing, so it is intended for transports that frame responses
|
|
1938
|
+
* themselves.
|
|
1939
|
+
*
|
|
1940
|
+
* @stability unstable
|
|
1941
|
+
* @category serialization
|
|
1942
|
+
* @since 4.0.0
|
|
1943
|
+
*/
|
|
1944
|
+
const json = /*#__PURE__*/ RpcSerialization.of({
|
|
1945
|
+
contentType: "application/json",
|
|
1946
|
+
includesFraming: false,
|
|
1947
|
+
codecFor: codecForJson,
|
|
1948
|
+
makeUnsafe: () => ({
|
|
1949
|
+
decode: (bytes) => {
|
|
1950
|
+
const decoded = JSON.parse(typeof bytes === "string" ? bytes : decodeText(bytes));
|
|
1951
|
+
return Array.isArray(decoded) ? decoded : [decoded];
|
|
1952
|
+
},
|
|
1953
|
+
encode: (response) => JSON.stringify(response)
|
|
1954
|
+
})
|
|
1955
|
+
});
|
|
1956
|
+
/**
|
|
1957
|
+
* Serializes RPC protocol messages as newline-delimited JSON, framing each message
|
|
1958
|
+
* with a trailing newline.
|
|
1959
|
+
*
|
|
1960
|
+
* @stability unstable
|
|
1961
|
+
* @category serialization
|
|
1962
|
+
* @since 4.0.0
|
|
1963
|
+
*/
|
|
1964
|
+
const makeNdjson = (options) => {
|
|
1965
|
+
const maxBufferSize = options?.maxBufferSize ?? defaultMaxBufferSize;
|
|
1966
|
+
return RpcSerialization.of({
|
|
1967
|
+
contentType: "application/x-ndjson",
|
|
1968
|
+
includesFraming: true,
|
|
1969
|
+
codecFor: codecForJson,
|
|
1970
|
+
makeUnsafe: () => {
|
|
1971
|
+
let decoder;
|
|
1972
|
+
let buffer = "";
|
|
1973
|
+
const failMaxBufferSize = (maxBufferSize) => {
|
|
1974
|
+
buffer = "";
|
|
1975
|
+
throw new MaxBufferSizeExceeded({ maxBufferSize });
|
|
1976
|
+
};
|
|
1977
|
+
return {
|
|
1978
|
+
decode: (bytes) => {
|
|
1979
|
+
buffer += typeof bytes === "string" ? bytes : (decoder ??= new TextDecoder()).decode(bytes, { stream: true });
|
|
1980
|
+
let position = 0;
|
|
1981
|
+
let nlIndex = buffer.indexOf("\n", position);
|
|
1982
|
+
const items = [];
|
|
1983
|
+
while (nlIndex !== -1) {
|
|
1984
|
+
if (isBufferSizeExceeded(nlIndex - position, maxBufferSize)) failMaxBufferSize(maxBufferSize);
|
|
1985
|
+
const line = buffer.slice(position, buffer[nlIndex - 1] === "\r" ? nlIndex - 1 : nlIndex);
|
|
1986
|
+
position = nlIndex + 1;
|
|
1987
|
+
if (line.length > 0) try {
|
|
1988
|
+
items.push(JSON.parse(line));
|
|
1989
|
+
} catch (cause) {
|
|
1990
|
+
buffer = "";
|
|
1991
|
+
throw new NdjsonDecodeError({ cause });
|
|
1992
|
+
}
|
|
1993
|
+
nlIndex = buffer.indexOf("\n", position);
|
|
1994
|
+
}
|
|
1995
|
+
buffer = buffer.slice(position);
|
|
1996
|
+
if (isBufferSizeExceeded(buffer.length, maxBufferSize)) failMaxBufferSize(maxBufferSize);
|
|
1997
|
+
return items;
|
|
1998
|
+
},
|
|
1999
|
+
encode: (response) => {
|
|
2000
|
+
if (Array.isArray(response)) {
|
|
2001
|
+
if (response.length === 0) return void 0;
|
|
2002
|
+
let data = "";
|
|
2003
|
+
for (let i = 0; i < response.length; i++) data += JSON.stringify(response[i]) + "\n";
|
|
2004
|
+
return data;
|
|
2005
|
+
}
|
|
2006
|
+
return JSON.stringify(response) + "\n";
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
};
|
|
2012
|
+
/**
|
|
2013
|
+
* Default newline-delimited JSON RPC serialization.
|
|
2014
|
+
*
|
|
2015
|
+
* @stability unstable
|
|
2016
|
+
* @category serialization
|
|
2017
|
+
* @since 4.0.0
|
|
2018
|
+
*/
|
|
2019
|
+
const ndjson = /*#__PURE__*/ makeNdjson();
|
|
2020
|
+
/**
|
|
2021
|
+
* RPC serialization layer that uses NDJSON for serialization.
|
|
2022
|
+
*
|
|
2023
|
+
* **When to use**
|
|
2024
|
+
*
|
|
2025
|
+
* Use when you have a transport protocol that does not provide message framing.
|
|
2026
|
+
*
|
|
2027
|
+
* @see {@link layerJson} for transports that already provide message framing
|
|
2028
|
+
*
|
|
2029
|
+
* @stability unstable
|
|
2030
|
+
* @category layers
|
|
2031
|
+
* @since 4.0.0
|
|
2032
|
+
*/
|
|
2033
|
+
const layerNdjson = /*#__PURE__*/ succeed$2(RpcSerialization)(ndjson);
|
|
2034
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/Utils.js
|
|
2035
|
+
/**
|
|
2036
|
+
* Buffers writes until `run` replays them with their original contexts and
|
|
2037
|
+
* installs the writer. Restores the previous writer when `run` ends.
|
|
2038
|
+
*
|
|
2039
|
+
* @stability unstable
|
|
2040
|
+
* @category services
|
|
2041
|
+
* @since 4.0.0
|
|
2042
|
+
*/
|
|
2043
|
+
const withRun = () => (f) => suspend$1(() => {
|
|
2044
|
+
const semaphore = makeUnsafe$5(1);
|
|
2045
|
+
let buffer = [];
|
|
2046
|
+
let write = (...args) => contextWith((context) => {
|
|
2047
|
+
buffer.push([args, context]);
|
|
2048
|
+
return void_;
|
|
2049
|
+
});
|
|
2050
|
+
return map$1(f((...args) => write(...args)), (a) => ({
|
|
2051
|
+
...a,
|
|
2052
|
+
run(f) {
|
|
2053
|
+
return semaphore.withPermits(1)(gen(function* () {
|
|
2054
|
+
const prev = write;
|
|
2055
|
+
for (const [args, context] of buffer) yield* provideContext(suspend$1(() => f(...args)), context);
|
|
2056
|
+
buffer = [];
|
|
2057
|
+
write = f;
|
|
2058
|
+
return yield* onExit(never, () => {
|
|
2059
|
+
write = prev;
|
|
2060
|
+
return void_;
|
|
2061
|
+
});
|
|
2062
|
+
}));
|
|
2063
|
+
}
|
|
2064
|
+
}));
|
|
2065
|
+
});
|
|
2066
|
+
/**
|
|
2067
|
+
* Builds an RPC client protocol service that tracks active client IDs and
|
|
2068
|
+
* buffers server responses per client until that client's `run` handler is
|
|
2069
|
+
* installed.
|
|
2070
|
+
*
|
|
2071
|
+
* @stability unstable
|
|
2072
|
+
* @category services
|
|
2073
|
+
* @since 4.0.0
|
|
2074
|
+
*/
|
|
2075
|
+
const withRunClient = (f) => suspend$1(() => {
|
|
2076
|
+
const clientIds = /* @__PURE__ */ new Set();
|
|
2077
|
+
const clientBuffers = /* @__PURE__ */ new Map();
|
|
2078
|
+
const clientWrites = /* @__PURE__ */ new Map();
|
|
2079
|
+
let write = (clientId, data) => contextWith((context) => {
|
|
2080
|
+
let buffer = clientBuffers.get(clientId);
|
|
2081
|
+
if (!buffer) {
|
|
2082
|
+
buffer = [];
|
|
2083
|
+
clientBuffers.set(clientId, buffer);
|
|
2084
|
+
}
|
|
2085
|
+
buffer.push([data, context]);
|
|
2086
|
+
return void_;
|
|
2087
|
+
});
|
|
2088
|
+
return map$1(f((clientId, data) => {
|
|
2089
|
+
const clientWrite = clientWrites.get(clientId);
|
|
2090
|
+
if (clientWrite) return clientWrite(data);
|
|
2091
|
+
return write(clientId, data);
|
|
2092
|
+
}, clientIds), (a) => ({
|
|
2093
|
+
...a,
|
|
2094
|
+
run(clientId, f) {
|
|
2095
|
+
return gen(function* () {
|
|
2096
|
+
clientIds.add(clientId);
|
|
2097
|
+
clientWrites.set(clientId, f);
|
|
2098
|
+
const buffer = clientBuffers.get(clientId);
|
|
2099
|
+
if (buffer) {
|
|
2100
|
+
clientBuffers.delete(clientId);
|
|
2101
|
+
for (const [args, context] of buffer) yield* provideContext(suspend$1(() => f(args)), context);
|
|
2102
|
+
}
|
|
2103
|
+
return yield* onExit(never, () => {
|
|
2104
|
+
clientIds.delete(clientId);
|
|
2105
|
+
clientWrites.delete(clientId);
|
|
2106
|
+
return void_;
|
|
2107
|
+
});
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
}));
|
|
2111
|
+
});
|
|
2112
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcClient.js
|
|
2113
|
+
const isRpcClientError = (u) => isTagged(u, "RpcClientError");
|
|
2114
|
+
let requestIdCounter = 0;
|
|
2115
|
+
/**
|
|
2116
|
+
* Creates an RPC client for an already-decoded message channel, returning the
|
|
2117
|
+
* client API together with a `write` function for delivering server messages
|
|
2118
|
+
* back to the client.
|
|
2119
|
+
*
|
|
2120
|
+
* @stability unstable
|
|
2121
|
+
* @category constructors
|
|
2122
|
+
* @since 4.0.0
|
|
2123
|
+
*/
|
|
2124
|
+
const makeNoSerialization = /*#__PURE__*/ fnUntraced(function* (group, options) {
|
|
2125
|
+
const spanPrefix = options.spanPrefix;
|
|
2126
|
+
const supportsAck = options?.supportsAck ?? true;
|
|
2127
|
+
const disableTracing = options?.disableTracing ?? false;
|
|
2128
|
+
const generateRequestId = options?.generateRequestId ?? (() => requestIdCounter++);
|
|
2129
|
+
const services = yield* context();
|
|
2130
|
+
const scope = get(services, Scope);
|
|
2131
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2132
|
+
let isShutdown = false;
|
|
2133
|
+
yield* addFinalizer$1(scope, withFiber((parent) => {
|
|
2134
|
+
isShutdown = true;
|
|
2135
|
+
return clearEntries(interrupt$1(parent.id));
|
|
2136
|
+
}));
|
|
2137
|
+
const clearEntries = fnUntraced(function* (exit) {
|
|
2138
|
+
const pending = Array.from(entries.values());
|
|
2139
|
+
entries.clear();
|
|
2140
|
+
for (const entry of pending) if (entry._tag === "Queue") yield* exit._tag === "Success" ? end(entry.queue) : failCause$2(entry.queue, exit.cause);
|
|
2141
|
+
else entry.resume(exit);
|
|
2142
|
+
}, uninterruptible);
|
|
2143
|
+
const onRequest = (rpc) => {
|
|
2144
|
+
const isStream = isStreamSchema(rpc.successSchema);
|
|
2145
|
+
const middleware = getRpcClientMiddleware(rpc);
|
|
2146
|
+
return (payload, opts) => {
|
|
2147
|
+
const headers = opts?.headers ? fromInput(opts.headers) : empty$2;
|
|
2148
|
+
const context = opts?.context ?? empty();
|
|
2149
|
+
if (!isStream) {
|
|
2150
|
+
const onRequest = (span) => onEffectRequest(rpc, middleware, span, rpc.payloadSchema.make(payload), headers, context, opts?.discard ?? false);
|
|
2151
|
+
return disableTracing ? onRequest(void 0) : useSpan(spanName(spanPrefix, rpc._tag), {
|
|
2152
|
+
kind: "client",
|
|
2153
|
+
attributes: spanAttributes(rpc._tag, options.spanAttributes)
|
|
2154
|
+
}, onRequest);
|
|
2155
|
+
}
|
|
2156
|
+
const queue = onStreamRequest(rpc, middleware, rpc.payloadSchema.make(payload), headers, opts?.streamBufferSize ?? 16, context);
|
|
2157
|
+
if (opts?.asQueue) return queue;
|
|
2158
|
+
return unwrap(map$1(queue, fromQueue));
|
|
2159
|
+
};
|
|
2160
|
+
};
|
|
2161
|
+
const onEffectRequest = (rpc, middleware, span, payload, headers, context, discard) => withFiber((parentFiber) => {
|
|
2162
|
+
if (isShutdown) return interrupt;
|
|
2163
|
+
const id = generateRequestId();
|
|
2164
|
+
const send = middleware((message) => options.onFromClient({
|
|
2165
|
+
message,
|
|
2166
|
+
context
|
|
2167
|
+
}), {
|
|
2168
|
+
_tag: "Request",
|
|
2169
|
+
id,
|
|
2170
|
+
tag: rpc._tag,
|
|
2171
|
+
payload,
|
|
2172
|
+
...span ? {
|
|
2173
|
+
traceId: span.traceId,
|
|
2174
|
+
spanId: span.spanId,
|
|
2175
|
+
sampled: span.sampled
|
|
2176
|
+
} : {},
|
|
2177
|
+
headers: merge$1(parentFiber.getRef(CurrentHeaders), headers),
|
|
2178
|
+
...discard ? { discard: true } : {}
|
|
2179
|
+
});
|
|
2180
|
+
let fiber;
|
|
2181
|
+
return onInterrupt(callback((resume) => {
|
|
2182
|
+
let acked = false;
|
|
2183
|
+
const entry = {
|
|
2184
|
+
_tag: "Effect",
|
|
2185
|
+
rpc,
|
|
2186
|
+
context,
|
|
2187
|
+
resume(exit) {
|
|
2188
|
+
if (discard && exit._tag === "Success") {
|
|
2189
|
+
acked = true;
|
|
2190
|
+
if (fiber?.pollUnsafe()) resume(void_$1);
|
|
2191
|
+
return;
|
|
2192
|
+
}
|
|
2193
|
+
resume(exit);
|
|
2194
|
+
if (fiber && !fiber.pollUnsafe()) parentFiber.currentDispatcher.scheduleTask(() => {
|
|
2195
|
+
fiber.interruptUnsafe(parentFiber.id);
|
|
2196
|
+
}, 0);
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
entries.set(id, entry);
|
|
2200
|
+
fiber = send.pipe(span ? withParentSpan(span, { captureStackTrace: false }) : identity, runForkWith(parentFiber.context));
|
|
2201
|
+
fiber.addObserver((exit) => {
|
|
2202
|
+
if (exit._tag === "Failure") {
|
|
2203
|
+
entries.delete(id);
|
|
2204
|
+
return resume(exit);
|
|
2205
|
+
} else if (acked) return resume(void_$1);
|
|
2206
|
+
});
|
|
2207
|
+
}), (interruptors) => {
|
|
2208
|
+
entries.delete(id);
|
|
2209
|
+
return andThen(interrupt$2(fiber), sendInterrupt(id, Array.from(interruptors), context));
|
|
2210
|
+
});
|
|
2211
|
+
});
|
|
2212
|
+
const onStreamRequest = fnUntraced(function* (rpc, middleware, payload, headers, streamBufferSize, context) {
|
|
2213
|
+
if (isShutdown) return yield* interrupt;
|
|
2214
|
+
const span = disableTracing ? void 0 : yield* makeSpanScoped(spanName(spanPrefix, rpc._tag), {
|
|
2215
|
+
kind: "client",
|
|
2216
|
+
attributes: spanAttributes(rpc._tag, options.spanAttributes)
|
|
2217
|
+
});
|
|
2218
|
+
const fiber = getCurrent();
|
|
2219
|
+
const id = generateRequestId();
|
|
2220
|
+
const scope = getUnsafe(fiber.context, Scope);
|
|
2221
|
+
const queue = yield* bounded$1(streamBufferSize);
|
|
2222
|
+
yield* addFinalizerExit(scope, (exit) => {
|
|
2223
|
+
shutdownUnsafe(queue);
|
|
2224
|
+
if (!entries.has(id)) return void_;
|
|
2225
|
+
entries.delete(id);
|
|
2226
|
+
return sendInterrupt(id, isFailure(exit) ? Array.from(interruptors(exit.cause)) : [], context);
|
|
2227
|
+
});
|
|
2228
|
+
entries.set(id, {
|
|
2229
|
+
_tag: "Queue",
|
|
2230
|
+
rpc,
|
|
2231
|
+
queue,
|
|
2232
|
+
scope,
|
|
2233
|
+
context
|
|
2234
|
+
});
|
|
2235
|
+
yield* middleware((message) => options.onFromClient({
|
|
2236
|
+
message,
|
|
2237
|
+
context
|
|
2238
|
+
}), {
|
|
2239
|
+
_tag: "Request",
|
|
2240
|
+
id,
|
|
2241
|
+
tag: rpc._tag,
|
|
2242
|
+
payload,
|
|
2243
|
+
...span ? {
|
|
2244
|
+
traceId: span.traceId,
|
|
2245
|
+
spanId: span.spanId,
|
|
2246
|
+
sampled: span.sampled
|
|
2247
|
+
} : {},
|
|
2248
|
+
headers: merge$1(fiber.getRef(CurrentHeaders), headers)
|
|
2249
|
+
}).pipe(span ? withParentSpan(span, { captureStackTrace: false }) : identity, onError((cause) => {
|
|
2250
|
+
if (!hasInterruptsOnly(cause)) entries.delete(id);
|
|
2251
|
+
return failCause$2(queue, cause);
|
|
2252
|
+
}), interruptible, forkIn(scope, { startImmediately: true }));
|
|
2253
|
+
return queue;
|
|
2254
|
+
});
|
|
2255
|
+
const getRpcClientMiddleware = (rpc) => {
|
|
2256
|
+
const middlewares = [];
|
|
2257
|
+
for (const tag of rpc.middlewares.values()) {
|
|
2258
|
+
const middleware = getOrUndefinedUnsafe(services, `${tag.key}/Client`);
|
|
2259
|
+
if (!middleware) continue;
|
|
2260
|
+
middlewares.push(middleware);
|
|
2261
|
+
}
|
|
2262
|
+
if (middlewares.length === 0) return (send, request) => send(request);
|
|
2263
|
+
return function loop(send, request, index = middlewares.length - 1) {
|
|
2264
|
+
if (index === -1) return send(request);
|
|
2265
|
+
return middlewares[index]({
|
|
2266
|
+
rpc,
|
|
2267
|
+
request,
|
|
2268
|
+
next(request) {
|
|
2269
|
+
return loop(send, request, index - 1);
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
};
|
|
2273
|
+
};
|
|
2274
|
+
const sendInterrupt = (requestId, interruptors, context) => callback((resume) => {
|
|
2275
|
+
const parentFiber = getCurrent();
|
|
2276
|
+
options.onFromClient({
|
|
2277
|
+
message: {
|
|
2278
|
+
_tag: "Interrupt",
|
|
2279
|
+
requestId,
|
|
2280
|
+
interruptors
|
|
2281
|
+
},
|
|
2282
|
+
context
|
|
2283
|
+
}).pipe(timeout(1e3), runForkWith(parentFiber.context)).addObserver(() => {
|
|
2284
|
+
resume(void_);
|
|
2285
|
+
});
|
|
2286
|
+
});
|
|
2287
|
+
const write = (message) => {
|
|
2288
|
+
switch (message._tag) {
|
|
2289
|
+
case "Chunk": {
|
|
2290
|
+
const requestId = message.requestId;
|
|
2291
|
+
const entry = entries.get(requestId);
|
|
2292
|
+
if (!entry || entry._tag !== "Queue") return void_;
|
|
2293
|
+
return offerAll(entry.queue, message.values).pipe(supportsAck ? flatMap((dropped) => dropped.length > 0 ? void_ : options.onFromClient({
|
|
2294
|
+
message: {
|
|
2295
|
+
_tag: "Ack",
|
|
2296
|
+
requestId: message.requestId
|
|
2297
|
+
},
|
|
2298
|
+
context: entry.context
|
|
2299
|
+
})) : identity, catchCause((cause) => failCause$2(entry.queue, cause)));
|
|
2300
|
+
}
|
|
2301
|
+
case "Exit": {
|
|
2302
|
+
const requestId = message.requestId;
|
|
2303
|
+
const entry = entries.get(requestId);
|
|
2304
|
+
if (!entry) return void_;
|
|
2305
|
+
entries.delete(requestId);
|
|
2306
|
+
if (entry._tag === "Effect") {
|
|
2307
|
+
entry.resume(message.exit);
|
|
2308
|
+
return void_;
|
|
2309
|
+
}
|
|
2310
|
+
return message.exit._tag === "Success" ? end(entry.queue) : failCause$2(entry.queue, message.exit.cause);
|
|
2311
|
+
}
|
|
2312
|
+
case "Defect": return clearEntries(die$2(message.defect));
|
|
2313
|
+
case "ClientEnd": return void_;
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
let client;
|
|
2317
|
+
if (options.flatten) {
|
|
2318
|
+
const fns = /* @__PURE__ */ new Map();
|
|
2319
|
+
client = function client(tag, payload, options) {
|
|
2320
|
+
let fn = fns.get(tag);
|
|
2321
|
+
if (!fn) {
|
|
2322
|
+
fn = onRequest(group.requests.get(tag));
|
|
2323
|
+
fns.set(tag, fn);
|
|
2324
|
+
}
|
|
2325
|
+
return fn(payload, options);
|
|
2326
|
+
};
|
|
2327
|
+
} else {
|
|
2328
|
+
client = {};
|
|
2329
|
+
group.requests.forEach((rpc) => {
|
|
2330
|
+
assignProperty(client, rpc._tag, onRequest(rpc));
|
|
2331
|
+
});
|
|
2332
|
+
}
|
|
2333
|
+
return {
|
|
2334
|
+
client,
|
|
2335
|
+
write
|
|
2336
|
+
};
|
|
2337
|
+
});
|
|
2338
|
+
let clientIdCounter = 0;
|
|
2339
|
+
/**
|
|
2340
|
+
* Creates a schema-aware RPC client for a group using the current client
|
|
2341
|
+
* `Protocol`, encoding requests and decoding server responses.
|
|
2342
|
+
*
|
|
2343
|
+
* @stability unstable
|
|
2344
|
+
* @category constructors
|
|
2345
|
+
* @since 4.0.0
|
|
2346
|
+
*/
|
|
2347
|
+
const make = /*#__PURE__*/ fnUntraced(function* (group, options) {
|
|
2348
|
+
const clientId = clientIdCounter++;
|
|
2349
|
+
const { codecFor, run, send, supportsAck, supportsTransferables } = yield* Protocol;
|
|
2350
|
+
const rpcSchemas = makeRpcSchemas(codecFor);
|
|
2351
|
+
const decodeDefect = decodeSync(codecFor(Defect()));
|
|
2352
|
+
const entries = /* @__PURE__ */ new Map();
|
|
2353
|
+
const closing = makeUnsafe$1();
|
|
2354
|
+
const interruptRequest = (requestId) => {
|
|
2355
|
+
if (!entries.has(requestId)) return void_;
|
|
2356
|
+
entries.delete(requestId);
|
|
2357
|
+
return send(clientId, {
|
|
2358
|
+
_tag: "Interrupt",
|
|
2359
|
+
requestId
|
|
2360
|
+
});
|
|
2361
|
+
};
|
|
2362
|
+
const { client, write } = yield* makeNoSerialization(group, {
|
|
2363
|
+
...options,
|
|
2364
|
+
supportsAck,
|
|
2365
|
+
onFromClient({ message }) {
|
|
2366
|
+
switch (message._tag) {
|
|
2367
|
+
case "Request": {
|
|
2368
|
+
const rpc = group.requests.get(message.tag);
|
|
2369
|
+
const collector = supportsTransferables ? makeCollectorUnsafe() : void 0;
|
|
2370
|
+
const fiber = getCurrent();
|
|
2371
|
+
const entry = {
|
|
2372
|
+
rpc,
|
|
2373
|
+
context: collector ? add(fiber.context, Collector, collector) : fiber.context,
|
|
2374
|
+
schemas: rpcSchemas(rpc),
|
|
2375
|
+
discard: message.discard === true
|
|
2376
|
+
};
|
|
2377
|
+
entries.set(message.id, entry);
|
|
2378
|
+
return entry.schemas.encodePayload(message.payload).pipe(provideContext(entry.context), orDie, flatMap((payload) => {
|
|
2379
|
+
if (isDoneUnsafe(closing)) {
|
|
2380
|
+
entries.delete(message.id);
|
|
2381
|
+
return interrupt;
|
|
2382
|
+
}
|
|
2383
|
+
return send(clientId, {
|
|
2384
|
+
...message,
|
|
2385
|
+
id: message.id,
|
|
2386
|
+
payload,
|
|
2387
|
+
headers: Object.entries(message.headers)
|
|
2388
|
+
}, collector && collector.readUnsafe());
|
|
2389
|
+
}), onError((cause) => hasInterruptsOnly(cause) ? void_ : sync(() => entries.delete(message.id))));
|
|
2390
|
+
}
|
|
2391
|
+
case "Ack":
|
|
2392
|
+
if (!entries.get(message.requestId)) return void_;
|
|
2393
|
+
return send(clientId, {
|
|
2394
|
+
_tag: "Ack",
|
|
2395
|
+
requestId: message.requestId
|
|
2396
|
+
});
|
|
2397
|
+
case "Interrupt": return interruptRequest(message.requestId);
|
|
2398
|
+
case "Eof": return void_;
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
});
|
|
2402
|
+
yield* run(clientId, (message) => {
|
|
2403
|
+
switch (message._tag) {
|
|
2404
|
+
case "Chunk": {
|
|
2405
|
+
const requestId = RequestId(message.requestId);
|
|
2406
|
+
const entry = entries.get(requestId);
|
|
2407
|
+
if (!entry || isNone(entry.schemas.decodeChunk)) return void_;
|
|
2408
|
+
const decodeChunk = entry.schemas.decodeChunk.value;
|
|
2409
|
+
return uninterruptibleMask((restore) => restore(decodeChunk(message.values).pipe(provideContext(entry.context), orDie, flatMap((chunk) => write({
|
|
2410
|
+
_tag: "Chunk",
|
|
2411
|
+
clientId: 0,
|
|
2412
|
+
requestId,
|
|
2413
|
+
values: chunk
|
|
2414
|
+
})))).pipe(onError((cause) => write({
|
|
2415
|
+
_tag: "Exit",
|
|
2416
|
+
clientId: 0,
|
|
2417
|
+
requestId,
|
|
2418
|
+
exit: failCause$1(cause)
|
|
2419
|
+
}).pipe(andThen(hasInterrupts(cause) ? void_ : raceFirst(ignore(interruptRequest(requestId)), _await(closing))))), catchCauseIf((cause) => !hasInterrupts(cause), () => void_)));
|
|
2420
|
+
}
|
|
2421
|
+
case "Exit": {
|
|
2422
|
+
const requestId = RequestId(message.requestId);
|
|
2423
|
+
const entry = entries.get(requestId);
|
|
2424
|
+
if (!entry) return void_;
|
|
2425
|
+
entries.delete(requestId);
|
|
2426
|
+
if (entry.discard && message.exit._tag === "Success") return write({
|
|
2427
|
+
_tag: "Exit",
|
|
2428
|
+
clientId: 0,
|
|
2429
|
+
requestId,
|
|
2430
|
+
exit: void_$1
|
|
2431
|
+
});
|
|
2432
|
+
return (entry.discard ? entry.schemas.decodeDiscardExit : entry.schemas.decodeExit)(message.exit).pipe(provideContext(entry.context), orDie, matchCauseEffect({
|
|
2433
|
+
onSuccess: (exit) => write({
|
|
2434
|
+
_tag: "Exit",
|
|
2435
|
+
clientId: 0,
|
|
2436
|
+
requestId,
|
|
2437
|
+
exit
|
|
2438
|
+
}),
|
|
2439
|
+
onFailure: (cause) => write({
|
|
2440
|
+
_tag: "Exit",
|
|
2441
|
+
clientId: 0,
|
|
2442
|
+
requestId,
|
|
2443
|
+
exit: failCause$1(cause)
|
|
2444
|
+
})
|
|
2445
|
+
}));
|
|
2446
|
+
}
|
|
2447
|
+
case "Defect":
|
|
2448
|
+
entries.clear();
|
|
2449
|
+
return write({
|
|
2450
|
+
_tag: "Defect",
|
|
2451
|
+
clientId: 0,
|
|
2452
|
+
defect: decodeDefect(message.defect)
|
|
2453
|
+
});
|
|
2454
|
+
case "ClientProtocolError": {
|
|
2455
|
+
const exit = fail$1(message.error);
|
|
2456
|
+
const requestIds = message.requestIds === void 0 ? Array.from(entries.keys()) : message.requestIds.map(RequestId).filter((requestId) => entries.has(requestId));
|
|
2457
|
+
for (const requestId of requestIds) entries.delete(requestId);
|
|
2458
|
+
return forEach(requestIds, (requestId) => write({
|
|
2459
|
+
_tag: "Exit",
|
|
2460
|
+
clientId: 0,
|
|
2461
|
+
requestId,
|
|
2462
|
+
exit
|
|
2463
|
+
})).pipe(uninterruptible);
|
|
2464
|
+
}
|
|
2465
|
+
default: return void_;
|
|
2466
|
+
}
|
|
2467
|
+
}).pipe(catchCause(logError), interruptible, forkScoped);
|
|
2468
|
+
yield* addFinalizer$2(() => succeed$3(closing, void 0));
|
|
2469
|
+
return client;
|
|
2470
|
+
});
|
|
2471
|
+
const makeRpcSchemas = (codecFor) => {
|
|
2472
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
2473
|
+
return (rpc) => {
|
|
2474
|
+
let entry = cache.get(rpc);
|
|
2475
|
+
if (entry !== void 0) return entry;
|
|
2476
|
+
const streamSchemas = getStreamSchemas(rpc.successSchema);
|
|
2477
|
+
const parseOptions = get(rpc.annotations, ParseOptions);
|
|
2478
|
+
const exitSchema$1 = exitSchema(rpc);
|
|
2479
|
+
let decodeDiscardExit;
|
|
2480
|
+
entry = {
|
|
2481
|
+
decodeChunk: map(streamSchemas, (streamSchemas) => decodeUnknownEffect(codecFor(NonEmptyArray(streamSchemas.success)), parseOptions)),
|
|
2482
|
+
encodePayload: encodeEffect(codecFor(rpc.payloadSchema), parseOptions),
|
|
2483
|
+
decodeExit: decodeUnknownEffect(codecFor(exitSchema$1), parseOptions),
|
|
2484
|
+
decodeDiscardExit: (encoded) => (decodeDiscardExit ??= decodeUnknownEffect(codecFor(Exit(Void, exitSchema$1.error, exitSchema$1.defect)), parseOptions))(encoded)
|
|
2485
|
+
};
|
|
2486
|
+
cache.set(rpc, entry);
|
|
2487
|
+
return entry;
|
|
2488
|
+
};
|
|
2489
|
+
};
|
|
2490
|
+
/**
|
|
2491
|
+
* Fiber reference containing headers that are merged into outgoing RPC
|
|
2492
|
+
* client requests.
|
|
2493
|
+
*
|
|
2494
|
+
* **When to use**
|
|
2495
|
+
*
|
|
2496
|
+
* Use to set request headers that should be automatically merged into outgoing
|
|
2497
|
+
* RPC client messages.
|
|
2498
|
+
*
|
|
2499
|
+
* @stability unstable
|
|
2500
|
+
* @category services
|
|
2501
|
+
* @since 4.0.0
|
|
2502
|
+
*/
|
|
2503
|
+
const CurrentHeaders = /*#__PURE__*/ Reference("effect/rpc/RpcClient/CurrentHeaders", { defaultValue: () => empty$2 });
|
|
2504
|
+
/**
|
|
2505
|
+
* Defines the service interface for an RPC client transport, responsible for running the
|
|
2506
|
+
* receive loop and sending encoded client messages.
|
|
2507
|
+
*
|
|
2508
|
+
* **When to use**
|
|
2509
|
+
*
|
|
2510
|
+
* Use to provide the transport boundary for RPC clients over HTTP, WebSocket,
|
|
2511
|
+
* workers, sockets, or custom protocols.
|
|
2512
|
+
*
|
|
2513
|
+
* **Details**
|
|
2514
|
+
*
|
|
2515
|
+
* A `Request` that `send` accepts stays pending until a reply names its id: an
|
|
2516
|
+
* `Exit`, or a `ClientProtocolError` that lists it in `requestIds`. Until then
|
|
2517
|
+
* the client keeps the request and the caller's context, unless the caller is
|
|
2518
|
+
* interrupted, the client closes or the connection fails. A transport that
|
|
2519
|
+
* only delivers requests, such as a message queue, writes a void `Exit` for a
|
|
2520
|
+
* `discard` request once the request is delivered, and fails `send` with an
|
|
2521
|
+
* `RpcClientError` for any other request.
|
|
2522
|
+
*
|
|
2523
|
+
* @stability unstable
|
|
2524
|
+
* @category services
|
|
2525
|
+
* @since 4.0.0
|
|
2526
|
+
*/
|
|
2527
|
+
var Protocol = class extends (/*#__PURE__*/ Service$1()("effect/rpc/RpcClient/Protocol")) {
|
|
2528
|
+
/**
|
|
2529
|
+
* Creates a client protocol service from the supplied RPC request runner.
|
|
2530
|
+
*
|
|
2531
|
+
* @stability unstable
|
|
2532
|
+
* @since 4.0.0
|
|
2533
|
+
*/
|
|
2534
|
+
static make = withRunClient;
|
|
2535
|
+
};
|
|
2536
|
+
/**
|
|
2537
|
+
* Creates a client `Protocol` that sends RPC requests through the supplied
|
|
2538
|
+
* `HttpClient` and decodes responses with the current `RpcSerialization`.
|
|
2539
|
+
*
|
|
2540
|
+
* **Details**
|
|
2541
|
+
*
|
|
2542
|
+
* Each request is sent as its own HTTP request unless `batch` is set. With
|
|
2543
|
+
* `batch`, the first request for a client opens a batch. Requests from the
|
|
2544
|
+
* same client made before `window` elapses join it, and the batch is sent once
|
|
2545
|
+
* the window elapses or it reaches `maxSize` requests, whichever comes first.
|
|
2546
|
+
*
|
|
2547
|
+
* @stability unstable
|
|
2548
|
+
* @category protocols
|
|
2549
|
+
* @since 4.0.0
|
|
2550
|
+
*/
|
|
2551
|
+
const makeProtocolHttp = (client, options) => options?.batch ? makeProtocolHttpBatched(client, options.batch) : makeProtocolHttpUnbatched(client);
|
|
2552
|
+
const makeProtocolHttpUnbatched = (client) => Protocol.make(fnUntraced(function* (writeResponse) {
|
|
2553
|
+
const serialization = yield* RpcSerialization;
|
|
2554
|
+
const exchange = makeHttpExchange(client, serialization, writeResponse);
|
|
2555
|
+
return {
|
|
2556
|
+
send: (clientId, request) => request._tag === "Request" ? flatMap(exchange.send(clientId, [request]), (pending) => exchange.requestExit(request, pending)) : void_,
|
|
2557
|
+
supportsAck: false,
|
|
2558
|
+
supportsTransferables: false,
|
|
2559
|
+
codecFor: serialization.codecFor
|
|
2560
|
+
};
|
|
2561
|
+
}));
|
|
2562
|
+
const makeProtocolHttpBatched = /*#__PURE__*/ fnUntraced(function* (client, options) {
|
|
2563
|
+
const { maxSize, window } = options;
|
|
2564
|
+
const scopes = /* @__PURE__ */ new Map();
|
|
2565
|
+
const closeScope = (clientId) => {
|
|
2566
|
+
const scope = scopes.get(clientId);
|
|
2567
|
+
if (scope === void 0) return void_;
|
|
2568
|
+
scopes.delete(clientId);
|
|
2569
|
+
return close(scope, void_$1);
|
|
2570
|
+
};
|
|
2571
|
+
const protocol = yield* Protocol.make(fnUntraced(function* (writeResponse) {
|
|
2572
|
+
const serialization = yield* RpcSerialization;
|
|
2573
|
+
const exchange = makeHttpExchange(client, serialization, writeResponse);
|
|
2574
|
+
const batches = /* @__PURE__ */ new Map();
|
|
2575
|
+
const closeBatch = (clientId, batch) => {
|
|
2576
|
+
if (batches.get(clientId) === batch) batches.delete(clientId);
|
|
2577
|
+
};
|
|
2578
|
+
const runBatch = (clientId, batch) => raceFirst(sleep(window), batch.full.await).pipe(andThen(suspend$1(() => {
|
|
2579
|
+
closeBatch(clientId, batch);
|
|
2580
|
+
return exchange.send(clientId, batch.requests);
|
|
2581
|
+
})), onExit((exit) => {
|
|
2582
|
+
closeBatch(clientId, batch);
|
|
2583
|
+
return done(batch.done, exit);
|
|
2584
|
+
}));
|
|
2585
|
+
const send = fnUntraced(function* (clientId, request) {
|
|
2586
|
+
let batch = batches.get(clientId);
|
|
2587
|
+
if (batch === void 0) {
|
|
2588
|
+
batch = {
|
|
2589
|
+
requests: [request],
|
|
2590
|
+
full: makeUnsafe$4(),
|
|
2591
|
+
done: makeUnsafe$1()
|
|
2592
|
+
};
|
|
2593
|
+
batches.set(clientId, batch);
|
|
2594
|
+
let scope = scopes.get(clientId);
|
|
2595
|
+
if (scope === void 0) {
|
|
2596
|
+
scope = makeUnsafe$3();
|
|
2597
|
+
scopes.set(clientId, scope);
|
|
2598
|
+
}
|
|
2599
|
+
yield* forkIn(runBatch(clientId, batch), scope, { startImmediately: true });
|
|
2600
|
+
} else batch.requests.push(request);
|
|
2601
|
+
if (batch.requests.length === maxSize) {
|
|
2602
|
+
closeBatch(clientId, batch);
|
|
2603
|
+
batch.full.openUnsafe();
|
|
2604
|
+
}
|
|
2605
|
+
return yield* exchange.requestExit(request, yield* _await(batch.done));
|
|
2606
|
+
});
|
|
2607
|
+
return {
|
|
2608
|
+
send: (clientId, request) => request._tag === "Request" ? send(clientId, request) : void_,
|
|
2609
|
+
supportsAck: false,
|
|
2610
|
+
supportsTransferables: false,
|
|
2611
|
+
codecFor: serialization.codecFor
|
|
2612
|
+
};
|
|
2613
|
+
}));
|
|
2614
|
+
return Protocol.of({
|
|
2615
|
+
...protocol,
|
|
2616
|
+
run: (clientId, f) => onExit(protocol.run(clientId, f), () => closeScope(clientId))
|
|
2617
|
+
});
|
|
2618
|
+
});
|
|
2619
|
+
const makeHttpExchange = (client, serialization, writeResponse) => {
|
|
2620
|
+
const isFramed = serialization.includesFraming;
|
|
2621
|
+
const httpClientError = (cause) => new RpcClientError({ reason: HttpClientErrorSchema.fromHttpClientError(cause) });
|
|
2622
|
+
const protocolDefect = (message, cause) => new RpcClientError({ reason: new RpcClientDefect({
|
|
2623
|
+
message,
|
|
2624
|
+
cause
|
|
2625
|
+
}) });
|
|
2626
|
+
const send = fnUntraced(function* (clientId, requests) {
|
|
2627
|
+
const parser = serialization.makeUnsafe();
|
|
2628
|
+
const encoded = parser.encode(requests.length === 1 ? requests[0] : requests);
|
|
2629
|
+
const body = typeof encoded === "string" ? text(encoded, serialization.contentType) : uint8Array(encoded, serialization.contentType);
|
|
2630
|
+
const response = yield* client.post("", { body }).pipe(mapError(httpClientError));
|
|
2631
|
+
const pending = /* @__PURE__ */ new Set();
|
|
2632
|
+
for (let i = 0; i < requests.length; i++) pending.add(String(requests[i].id));
|
|
2633
|
+
const onResponse = (response) => {
|
|
2634
|
+
if (response._tag === "Exit") pending.delete(String(response.requestId));
|
|
2635
|
+
else if (isTerminalResponse(response)) pending.clear();
|
|
2636
|
+
return writeResponse(clientId, response);
|
|
2637
|
+
};
|
|
2638
|
+
if (!isFramed) {
|
|
2639
|
+
const text = yield* response.text.pipe(mapError(httpClientError));
|
|
2640
|
+
const responses = yield* try_({
|
|
2641
|
+
try: () => parser.decode(text),
|
|
2642
|
+
catch: (cause) => protocolDefect("Error decoding HTTP response", cause)
|
|
2643
|
+
});
|
|
2644
|
+
if (!Array.isArray(responses)) return yield* protocolDefect("Expected an array of responses", responses);
|
|
2645
|
+
if (responses.length === 0) return;
|
|
2646
|
+
for (let i = 0; i < responses.length; i++) yield* onResponse(responses[i]);
|
|
2647
|
+
return pending;
|
|
2648
|
+
}
|
|
2649
|
+
let hasResponse = false;
|
|
2650
|
+
yield* runForEachArray(response.stream, (chunk) => try_({
|
|
2651
|
+
try: () => chunk.flatMap(parser.decode),
|
|
2652
|
+
catch: (cause) => protocolDefect("Error decoding HTTP response", cause)
|
|
2653
|
+
}).pipe(flatMap((responses) => {
|
|
2654
|
+
if (responses.length === 0) return void_;
|
|
2655
|
+
hasResponse = true;
|
|
2656
|
+
let i = 0;
|
|
2657
|
+
return whileLoop({
|
|
2658
|
+
while: () => i < responses.length,
|
|
2659
|
+
body: () => onResponse(responses[i++]),
|
|
2660
|
+
step: constVoid
|
|
2661
|
+
});
|
|
2662
|
+
}))).pipe(mapError((cause) => isRpcClientError(cause) ? cause : httpClientError(cause)));
|
|
2663
|
+
return hasResponse ? pending : void 0;
|
|
2664
|
+
});
|
|
2665
|
+
const requestExit = (request, pending) => {
|
|
2666
|
+
if (pending === void 0) return fail$1(protocolDefect("Received empty HTTP response from RPC server", request));
|
|
2667
|
+
else if (pending.has(String(request.id))) return fail$1(protocolDefect("HTTP response ended before RPC request completed", request));
|
|
2668
|
+
return void_$1;
|
|
2669
|
+
};
|
|
2670
|
+
return {
|
|
2671
|
+
send,
|
|
2672
|
+
requestExit
|
|
2673
|
+
};
|
|
2674
|
+
};
|
|
2675
|
+
// ../../node_modules/.pnpm/effect@4.1.2_patch_hash=0e61176203bb1256381ce1c5b488d7951983ce38ff698647d3f4617383abbf07/node_modules/effect/dist/rpc/RpcMiddleware.js
|
|
2676
|
+
/**
|
|
2677
|
+
* Middleware services for the unstable RPC runtime.
|
|
2678
|
+
*
|
|
2679
|
+
* A middleware service wraps server handler execution and can also install a
|
|
2680
|
+
* client-side wrapper for generated clients. Its metadata records the services
|
|
2681
|
+
* provided to downstream handlers, the services required by the middleware
|
|
2682
|
+
* implementation, the schema for server-visible failures, the client-only error
|
|
2683
|
+
* type, and whether generated clients must require the matching client layer.
|
|
2684
|
+
*
|
|
2685
|
+
* @stability unstable
|
|
2686
|
+
* @since 4.0.0
|
|
2687
|
+
*/
|
|
2688
|
+
/**
|
|
2689
|
+
* The runtime type id used to attach and inspect RPC middleware metadata.
|
|
2690
|
+
*
|
|
2691
|
+
* @stability unstable
|
|
2692
|
+
* @category type IDs
|
|
2693
|
+
* @since 4.0.0
|
|
2694
|
+
*/
|
|
2695
|
+
const TypeId = "~effect/rpc/RpcMiddleware";
|
|
2696
|
+
/**
|
|
2697
|
+
* Creates a typed RPC middleware service class, with optional service
|
|
2698
|
+
* requirements, provided services, error schema, and client-side requirement
|
|
2699
|
+
* metadata.
|
|
2700
|
+
*
|
|
2701
|
+
* @stability unstable
|
|
2702
|
+
* @category constructors
|
|
2703
|
+
* @since 4.0.0
|
|
2704
|
+
*/
|
|
2705
|
+
const Service = () => (id, options) => {
|
|
2706
|
+
const limit = getStackTraceLimit();
|
|
2707
|
+
let creationError;
|
|
2708
|
+
if (limit !== 0) {
|
|
2709
|
+
setStackTraceLimit(2);
|
|
2710
|
+
creationError = new globalThis.Error();
|
|
2711
|
+
setStackTraceLimit(limit);
|
|
2712
|
+
}
|
|
2713
|
+
function ServiceClass() {}
|
|
2714
|
+
const ServiceClass_ = ServiceClass;
|
|
2715
|
+
Object.setPrototypeOf(ServiceClass, Object.getPrototypeOf(Service$1(id)));
|
|
2716
|
+
ServiceClass.key = id;
|
|
2717
|
+
Object.defineProperty(ServiceClass, "stack", { get() {
|
|
2718
|
+
return creationError?.stack;
|
|
2719
|
+
} });
|
|
2720
|
+
ServiceClass_[TypeId] = TypeId;
|
|
2721
|
+
ServiceClass_.error = options?.error ?? Never;
|
|
2722
|
+
ServiceClass_.requiredForClient = options?.requiredForClient ?? false;
|
|
2723
|
+
return ServiceClass;
|
|
2724
|
+
};
|
|
2725
|
+
// ../effect/src/contract/actor/actor-already-exists.errors.ts
|
|
2726
|
+
var ActorAlreadyExistsError = class extends TaggedError()("ActorAlreadyExistsError", { actor: String$1 }) {};
|
|
2727
|
+
// ../effect/src/contract/actor/actor-erased.errors.ts
|
|
2728
|
+
var ActorErasedError = class extends TaggedError()("ActorErasedError", { actor: String$1 }) {};
|
|
2729
|
+
// ../effect/src/contract/actor/actor-not-created.errors.ts
|
|
2730
|
+
var ActorNotCreatedError = class extends TaggedError()("ActorNotCreatedError", { actor: String$1 }) {};
|
|
2731
|
+
// ../effect/src/contract/client/actor-unavailable.errors.ts
|
|
2732
|
+
var ActorUnavailableError = class extends TaggedError()("ActorUnavailableError", {
|
|
2733
|
+
actor: String$1,
|
|
2734
|
+
message: String$1
|
|
2735
|
+
}) {};
|
|
2736
|
+
// ../effect/src/contract/caller/caller-not-allowed.errors.ts
|
|
2737
|
+
/**
|
|
2738
|
+
* The caller's kind may not call this member. Its message names the refused kind and the declaration that admits it,
|
|
2739
|
+
* such as `apiKey` for a script, agent or bench signed in with an Akter Cloud API key.
|
|
2740
|
+
*/
|
|
2741
|
+
var CallerNotAllowedError = class extends TaggedError()("CallerNotAllowedError", {
|
|
2742
|
+
actor: String$1,
|
|
2743
|
+
kind: String$1,
|
|
2744
|
+
member: String$1
|
|
2745
|
+
}) {
|
|
2746
|
+
get message() {
|
|
2747
|
+
if (this.member === "akter.files") return `${this.actor}'s files refuse caller kind "${this.kind}". To admit it, list it in the actor's files: Akter.fileAccess({ callers: ["${this.kind}"] }), and allow it in files.authorize.`;
|
|
2748
|
+
if (this.member === "fork") return `${this.actor}.fork refuses caller kind "${this.kind}". Fork admits only an app's operators, the "user" and "apiKey" caller kinds.`;
|
|
2749
|
+
return `${this.actor}.${this.member} refuses caller kind "${this.kind}". To admit it, declare it on the actor, as in callers: { ${this.kind}: Akter.Principal, user: Akter.Principal }, and add "${this.kind}" to the member's callers if it lists them.`;
|
|
2750
|
+
}
|
|
2751
|
+
};
|
|
2752
|
+
// ../effect/src/contract/caller/unauthenticated.errors.ts
|
|
2753
|
+
var UnauthenticatedError = class extends TaggedError()("UnauthenticatedError", { message: String$1 }) {};
|
|
2754
|
+
// ../effect/src/contract/command/command-id-expired.errors.ts
|
|
2755
|
+
var CommandIdExpiredError = class extends TaggedError()("CommandIdExpiredError", {
|
|
2756
|
+
actor: String$1,
|
|
2757
|
+
commandId: String$1,
|
|
2758
|
+
keptSince: Int,
|
|
2759
|
+
mintedAt: Int
|
|
2760
|
+
}) {};
|
|
2761
|
+
// ../effect/src/contract/hosted/handler-failed.errors.ts
|
|
2762
|
+
/**
|
|
2763
|
+
* A handler failed outside its declared error contract. `platform` is true when the failure was Akter's, not the
|
|
2764
|
+
* handler's: a platform error such as `FilesUnavailableError` escaped it. Akter Cloud doesn't bill a call that ends
|
|
2765
|
+
* with one. A handler's own failure, such as a statement its SQL got wrong, carries no `platform`.
|
|
2766
|
+
*/
|
|
2767
|
+
var HandlerFailedError = class extends TaggedError()("HandlerFailedError", {
|
|
2768
|
+
actor: String$1,
|
|
2769
|
+
member: String$1,
|
|
2770
|
+
message: String$1,
|
|
2771
|
+
platform: optionalKey(Literal(true))
|
|
2772
|
+
}) {};
|
|
2773
|
+
// ../effect/src/contract/client/invalid-request.errors.ts
|
|
2774
|
+
var InvalidRequestError = class extends TaggedError()("InvalidRequestError", {
|
|
2775
|
+
actor: String$1,
|
|
2776
|
+
message: String$1
|
|
2777
|
+
}) {};
|
|
2778
|
+
// ../effect/src/contract/spend/billing-unavailable.errors.ts
|
|
2779
|
+
/**
|
|
2780
|
+
* Akter Cloud couldn't tell whether new spend fits under the caps for too long to admit it safely, so it
|
|
2781
|
+
* refused the call. Nothing ran. Retry after `retryAfterSeconds`.
|
|
2782
|
+
*/
|
|
2783
|
+
var BillingUnavailableError = class extends TaggedError()("BillingUnavailableError", { retryAfterSeconds: Int }) {};
|
|
2784
|
+
// ../effect/src/contract/spend/spend-cap-reached.errors.ts
|
|
2785
|
+
/**
|
|
2786
|
+
* Akter Cloud refused new spend because a spend cap is reached. `scope` says whose cap: the
|
|
2787
|
+
* organization's, or the calling API key's. A person raises it in the Cloud API; work already
|
|
2788
|
+
* running is not stopped. Amounts are US dollars for the calendar month `period` (`YYYY-MM`), and
|
|
2789
|
+
* `spentUsd` includes spend that may still be on its way.
|
|
2790
|
+
*/
|
|
2791
|
+
var SpendCapReachedError = class extends TaggedError()("SpendCapReachedError", {
|
|
2792
|
+
capUsd: Finite,
|
|
2793
|
+
period: String$1,
|
|
2794
|
+
scope: Literals(["organization", "apiKey"]),
|
|
2795
|
+
spentUsd: Finite
|
|
2796
|
+
}) {};
|
|
2797
|
+
// ../effect/src/contract/client/storage-limit.errors.ts
|
|
2798
|
+
/**
|
|
2799
|
+
* Akter Cloud refused a write because the app environment's stored data reached its ceiling: `dataBytes` of
|
|
2800
|
+
* `ceilingBytes`, as read from storage at `readAt` (epoch milliseconds). Nothing ran. Queries and downloads still
|
|
2801
|
+
* work; a write succeeds again once data is removed or the ceiling is raised.
|
|
2802
|
+
*/
|
|
2803
|
+
var StorageLimitError = class extends TaggedError()("StorageLimitError", {
|
|
2804
|
+
actor: String$1,
|
|
2805
|
+
ceilingBytes: Finite,
|
|
2806
|
+
dataBytes: Finite,
|
|
2807
|
+
readAt: Int
|
|
2808
|
+
}) {};
|
|
2809
|
+
// ../effect/src/contract/file/blob-transfer.errors.ts
|
|
2810
|
+
var BlobTransferError = class extends TaggedError()("BlobTransferError", {
|
|
2811
|
+
blob: String$1,
|
|
2812
|
+
message: String$1
|
|
2813
|
+
}) {};
|
|
2814
|
+
TaggedError()("CheckpointExpiredError", { computer: String$1 });
|
|
2815
|
+
// ../effect/src/contract/computer/computer-held.errors.ts
|
|
2816
|
+
/**
|
|
2817
|
+
* A fork holds the computer paused. Nothing but that fork's resume, carrying the same hold, may run or resume it;
|
|
2818
|
+
* try again once the fork ends.
|
|
2819
|
+
*/
|
|
2820
|
+
var ComputerHeldError = class extends TaggedError()("ComputerHeldError", {
|
|
2821
|
+
computer: String$1,
|
|
2822
|
+
hold: String$1
|
|
2823
|
+
}) {};
|
|
2824
|
+
// ../effect/src/contract/computer/computer-limit.errors.ts
|
|
2825
|
+
/**
|
|
2826
|
+
* A new computer would pass a limit, so none was made: `store`, the computers one app environment may keep, or
|
|
2827
|
+
* `account`, the sandboxes the platform's provider account may run at once. Remove a computer, or try again once
|
|
2828
|
+
* one is gone. Nothing waits for room.
|
|
2829
|
+
*/
|
|
2830
|
+
var ComputerLimitError = class extends TaggedError()("ComputerLimitError", {
|
|
2831
|
+
computer: String$1,
|
|
2832
|
+
limit: Literals(["store", "account"]),
|
|
2833
|
+
maximum: Int
|
|
2834
|
+
}) {};
|
|
2835
|
+
// ../effect/src/contract/computer/computer-lost.errors.ts
|
|
2836
|
+
/**
|
|
2837
|
+
* The computer's disk no longer exists, so it can't be resumed or run in. It is not recreated empty under the same
|
|
2838
|
+
* name; remove it and ensure it again to start over.
|
|
2839
|
+
*/
|
|
2840
|
+
var ComputerLostError = class extends TaggedError()("ComputerLostError", { computer: String$1 }) {};
|
|
2841
|
+
// ../effect/src/contract/computer/computer-not-found.errors.ts
|
|
2842
|
+
/** The actor has no computer of that name. */
|
|
2843
|
+
var ComputerNotFoundError = class extends TaggedError()("ComputerNotFoundError", { computer: String$1 }) {};
|
|
2844
|
+
// ../effect/src/contract/computer/computers-unavailable.errors.ts
|
|
2845
|
+
/** This engine runs no computers, or their provider didn't answer. */
|
|
2846
|
+
var ComputersUnavailableError = class extends TaggedError()("ComputersUnavailableError", { message: String$1 }) {};
|
|
2847
|
+
// ../effect/src/contract/computer/step/step-not-found.errors.ts
|
|
2848
|
+
/** The actor's journal holds no durable step with that key. */
|
|
2849
|
+
var StepNotFoundError = class extends TaggedError()("StepNotFoundError", { step: String$1 }) {};
|
|
2850
|
+
// ../effect/src/contract/file/access/file-access-denied.errors.ts
|
|
2851
|
+
/** The actor's `files.authorize` rule refused this caller's file call. */
|
|
2852
|
+
var FileAccessDeniedError = class extends TaggedError()("FileAccessDeniedError", {
|
|
2853
|
+
access: Literals(["read", "write"]),
|
|
2854
|
+
message: String$1,
|
|
2855
|
+
path: String$1
|
|
2856
|
+
}) {};
|
|
2857
|
+
// ../effect/src/contract/file/file-not-found.errors.ts
|
|
2858
|
+
var FileNotFoundError = class extends TaggedError()("FileNotFoundError", { path: String$1 }) {};
|
|
2859
|
+
// ../effect/src/contract/file/rpc/file-too-large.errors.ts
|
|
2860
|
+
/**
|
|
2861
|
+
* An upload would pass the largest file the server accepts, `maximumBytes`, so the chunk was refused and the upload
|
|
2862
|
+
* dropped. Nothing was attached. Split the content into smaller files.
|
|
2863
|
+
*/
|
|
2864
|
+
var FileTooLargeError = class extends TaggedError()("FileTooLargeError", {
|
|
2865
|
+
actor: String$1,
|
|
2866
|
+
maximumBytes: Int
|
|
2867
|
+
}) {};
|
|
2868
|
+
// ../effect/src/contract/file/files-unavailable.errors.ts
|
|
2869
|
+
var FilesUnavailableError = class extends TaggedError()("FilesUnavailableError", { message: String$1 }) {};
|
|
2870
|
+
// ../effect/src/contract/file/invalid-file-request.errors.ts
|
|
2871
|
+
var InvalidFileRequestError = class extends TaggedError()("InvalidFileRequestError", {
|
|
2872
|
+
message: String$1,
|
|
2873
|
+
path: String$1
|
|
2874
|
+
}) {};
|
|
2875
|
+
// ../effect/src/contract/secret/invalid-secret-name.errors.ts
|
|
2876
|
+
/** An actor declared a secret whose name isn't a `SecretName`, so no environment could ever set it. */
|
|
2877
|
+
var InvalidSecretNameError = class extends TaggedError()("InvalidSecretNameError", {
|
|
2878
|
+
actor: String$1,
|
|
2879
|
+
secret: String$1
|
|
2880
|
+
}) {};
|
|
2881
|
+
// ../effect/src/contract/secret/secret.schema.ts
|
|
2882
|
+
const secretNamePattern = /^[A-Z][A-Z0-9_]{0,127}$/u;
|
|
2883
|
+
const headerPattern = /^[A-Za-z0-9-]+$/u;
|
|
2884
|
+
const printablePattern = /^[\t -~]*$/u;
|
|
2885
|
+
/**
|
|
2886
|
+
* A secret's name, as Akter Cloud stores it for an environment and as an environment variable: an uppercase letter,
|
|
2887
|
+
* then up to 127 uppercase letters, digits or underscores.
|
|
2888
|
+
*/
|
|
2889
|
+
const SecretName = String$1.check(isPattern(secretNamePattern)).annotate({ description: "A secret's name, as an environment variable." });
|
|
2890
|
+
/**
|
|
2891
|
+
* Why a secret could not be read:
|
|
2892
|
+
*
|
|
2893
|
+
* - `undeclared`: the actor doesn't list it in its `secrets`, so it may not read it.
|
|
2894
|
+
* - `unset`: the actor declares it, but the environment has no value for it.
|
|
2895
|
+
* - `unavailable`: this engine delivers no secrets, or couldn't open them just now.
|
|
2896
|
+
* - `command`: a command, query, create or result handler asked; secrets are read in job activities.
|
|
2897
|
+
*/
|
|
2898
|
+
const SecretRefusal = Literals([
|
|
2899
|
+
"undeclared",
|
|
2900
|
+
"unset",
|
|
2901
|
+
"unavailable",
|
|
2902
|
+
"command"
|
|
2903
|
+
]);
|
|
2904
|
+
/** What the platform writes before a credential's value, such as `Bearer `: printable ASCII only. */
|
|
2905
|
+
const HeaderPrefix = String$1.check(isPattern(printablePattern));
|
|
2906
|
+
/** A computer's credential: the secret the platform adds as `header` to its requests to `host`, after `prefix`. */
|
|
2907
|
+
const ComputerSecret = Struct({
|
|
2908
|
+
header: String$1.check(isPattern(headerPattern)),
|
|
2909
|
+
host: String$1,
|
|
2910
|
+
prefix: optionalKey(HeaderPrefix),
|
|
2911
|
+
secret: SecretName
|
|
2912
|
+
}).annotate({ description: "A credential the platform adds to the computer's requests to one allowed host. The computer never sees its value." });
|
|
2913
|
+
// ../effect/src/contract/secret/secret-unavailable.errors.ts
|
|
2914
|
+
/** An actor's secret could not be read; `reason` says why (`SecretRefusal`). */
|
|
2915
|
+
var SecretUnavailableError = class extends TaggedError()("SecretUnavailableError", {
|
|
2916
|
+
actor: String$1,
|
|
2917
|
+
reason: SecretRefusal,
|
|
2918
|
+
secret: String$1
|
|
2919
|
+
}) {};
|
|
2920
|
+
// ../effect/src/contract/hosted/hosted-failure.schema.ts
|
|
2921
|
+
/**
|
|
2922
|
+
* The failures any hosted member can answer besides its declared ones. Akter Cloud's gateway also answers
|
|
2923
|
+
* `SpendCapReachedError` and `BillingUnavailableError` when it refuses new spend, and its hosts answer
|
|
2924
|
+
* `StorageLimitError` when a write would grow storage past its ceiling, so clients decode those typed.
|
|
2925
|
+
*/
|
|
2926
|
+
const HostedFailure = Union([
|
|
2927
|
+
ActorErasedError,
|
|
2928
|
+
ActorNotCreatedError,
|
|
2929
|
+
ActorUnavailableError,
|
|
2930
|
+
BillingUnavailableError,
|
|
2931
|
+
CallerNotAllowedError,
|
|
2932
|
+
CommandIdExpiredError,
|
|
2933
|
+
HandlerFailedError,
|
|
2934
|
+
InvalidRequestError,
|
|
2935
|
+
SpendCapReachedError,
|
|
2936
|
+
StorageLimitError
|
|
2937
|
+
]);
|
|
2938
|
+
// ../effect/src/contract/file/rpc/file-rpc.contract.ts
|
|
2939
|
+
/** The largest chunk a download stream sends, and the largest one an upload may append. */
|
|
2940
|
+
const fileChunkBytes = 262144;
|
|
2941
|
+
const uploadChunkBytes = 1048576;
|
|
2942
|
+
const FileRpcFailure = Union([
|
|
2943
|
+
HostedFailure,
|
|
2944
|
+
BlobTransferError,
|
|
2945
|
+
FileAccessDeniedError,
|
|
2946
|
+
FileNotFoundError,
|
|
2947
|
+
FilesUnavailableError,
|
|
2948
|
+
FileTooLargeError,
|
|
2949
|
+
InvalidFileRequestError
|
|
2950
|
+
]);
|
|
2951
|
+
const WireFileRef = Struct({
|
|
2952
|
+
bytes: Int,
|
|
2953
|
+
path: String$1,
|
|
2954
|
+
sha256: String$1,
|
|
2955
|
+
writtenAt: Int
|
|
2956
|
+
});
|
|
2957
|
+
const WireFilePage = Struct({
|
|
2958
|
+
cursor: OptionFromNullOr(String$1),
|
|
2959
|
+
entries: ArraySchema(WireFileRef)
|
|
2960
|
+
});
|
|
2961
|
+
const WireFileUsagePage = Struct({
|
|
2962
|
+
...WireFilePage.fields,
|
|
2963
|
+
bytes: BigIntFromString
|
|
2964
|
+
});
|
|
2965
|
+
const Listing = {
|
|
2966
|
+
cursor: optionalKey(String$1),
|
|
2967
|
+
key: String$1,
|
|
2968
|
+
limit: optionalKey(Int),
|
|
2969
|
+
prefix: optionalKey(String$1)
|
|
2970
|
+
};
|
|
2971
|
+
const Chunk = Uint8ArrayFromBase64;
|
|
2972
|
+
const fileTag = ({ actor, operation }) => `${actor}/files/${operation}`;
|
|
2973
|
+
/**
|
|
2974
|
+
* The file streams of one actor, under the tags docs/adr/0016 reserves: `<Actor>/files/<operation>`. Every payload
|
|
2975
|
+
* carries the actor's encoded key as a string, as the actor's other RPCs do on the wire. Effect RPC has no client
|
|
2976
|
+
* streams, so an upload is a short session: `upload/open` returns an id, `upload/append` sends chunks of at most
|
|
2977
|
+
* 1 MiB in order and is idempotent by offset, and `upload/close` checks the length and returns the receipt a command
|
|
2978
|
+
* attaches. A download streams chunks of at most 256 KiB.
|
|
2979
|
+
*/
|
|
2980
|
+
const fileRpcsOf = (actor) => [
|
|
2981
|
+
make$2(fileTag({
|
|
2982
|
+
actor,
|
|
2983
|
+
operation: "list"
|
|
2984
|
+
}), {
|
|
2985
|
+
error: FileRpcFailure,
|
|
2986
|
+
payload: Listing,
|
|
2987
|
+
success: WireFilePage
|
|
2988
|
+
}),
|
|
2989
|
+
make$2(fileTag({
|
|
2990
|
+
actor,
|
|
2991
|
+
operation: "usage"
|
|
2992
|
+
}), {
|
|
2993
|
+
error: FileRpcFailure,
|
|
2994
|
+
payload: Listing,
|
|
2995
|
+
success: WireFileUsagePage
|
|
2996
|
+
}),
|
|
2997
|
+
make$2(fileTag({
|
|
2998
|
+
actor,
|
|
2999
|
+
operation: "download"
|
|
3000
|
+
}), {
|
|
3001
|
+
error: FileRpcFailure,
|
|
3002
|
+
payload: {
|
|
3003
|
+
key: String$1,
|
|
3004
|
+
length: optionalKey(Int),
|
|
3005
|
+
offset: optionalKey(Int),
|
|
3006
|
+
path: String$1
|
|
3007
|
+
},
|
|
3008
|
+
stream: true,
|
|
3009
|
+
success: Chunk
|
|
3010
|
+
}),
|
|
3011
|
+
make$2(fileTag({
|
|
3012
|
+
actor,
|
|
3013
|
+
operation: "upload/open"
|
|
3014
|
+
}), {
|
|
3015
|
+
error: FileRpcFailure,
|
|
3016
|
+
payload: { key: String$1 },
|
|
3017
|
+
success: Struct({ upload: String$1 })
|
|
3018
|
+
}),
|
|
3019
|
+
make$2(fileTag({
|
|
3020
|
+
actor,
|
|
3021
|
+
operation: "upload/append"
|
|
3022
|
+
}), {
|
|
3023
|
+
error: FileRpcFailure,
|
|
3024
|
+
payload: {
|
|
3025
|
+
bytes: Chunk,
|
|
3026
|
+
key: String$1,
|
|
3027
|
+
offset: Int,
|
|
3028
|
+
upload: String$1
|
|
3029
|
+
},
|
|
3030
|
+
success: Struct({ received: Int })
|
|
3031
|
+
}),
|
|
3032
|
+
make$2(fileTag({
|
|
3033
|
+
actor,
|
|
3034
|
+
operation: "upload/close"
|
|
3035
|
+
}), {
|
|
3036
|
+
error: FileRpcFailure,
|
|
3037
|
+
payload: {
|
|
3038
|
+
bytes: Int,
|
|
3039
|
+
key: String$1,
|
|
3040
|
+
upload: String$1
|
|
3041
|
+
},
|
|
3042
|
+
success: Struct({ receipt: String$1 })
|
|
3043
|
+
})
|
|
3044
|
+
];
|
|
3045
|
+
// ../effect/src/contract/command/command-id.schema.ts
|
|
3046
|
+
const CommandId = String$1.pipe(brand("CommandId"));
|
|
3047
|
+
// ../effect/src/contract/fork/fork-rpc.contract.ts
|
|
3048
|
+
/** What a fork answers: the parent's commit version at the cut the child was copied from. */
|
|
3049
|
+
const Forked = Struct({ version: Int });
|
|
3050
|
+
const ForkFailure = Union([HostedFailure, ActorAlreadyExistsError]);
|
|
3051
|
+
const forkTag = (actor) => `${actor}/fork`;
|
|
3052
|
+
/**
|
|
3053
|
+
* Forks one actor under the tag docs/adr/0016 reserves: `<Actor>/fork` copies the actor at `key`, at one cut between
|
|
3054
|
+
* two of its commands, into a new actor of the same kind at `into` (ADR 0017, ADR 0018). The copy starts quiet, with
|
|
3055
|
+
* its own key, and nothing reads it before it is whole. `commandId` names the fork, so a retry with it answers the
|
|
3056
|
+
* same fork instead of making a second copy.
|
|
3057
|
+
*/
|
|
3058
|
+
const forkRpcOf = ({ actor, key }) => make$2(forkTag(actor), {
|
|
3059
|
+
error: ForkFailure,
|
|
3060
|
+
payload: {
|
|
3061
|
+
commandId: CommandId,
|
|
3062
|
+
into: key,
|
|
3063
|
+
key
|
|
3064
|
+
},
|
|
3065
|
+
success: Forked
|
|
3066
|
+
});
|
|
3067
|
+
// ../effect/src/contract/computer/files/computer-files.schema.ts
|
|
3068
|
+
/** One file per call, bounded before crossing the host/control link. Paths are relative to the computer's files directory. */
|
|
3069
|
+
const computerFileBytes = 1048576;
|
|
3070
|
+
const ComputerFileRequest = TaggedUnion({
|
|
3071
|
+
Read: { path: String$1 },
|
|
3072
|
+
Write: {
|
|
3073
|
+
content: Uint8ArrayFromBase64,
|
|
3074
|
+
path: String$1
|
|
3075
|
+
}
|
|
3076
|
+
});
|
|
3077
|
+
const ComputerCopy = Struct({
|
|
3078
|
+
computer: String$1,
|
|
3079
|
+
computerPath: String$1,
|
|
3080
|
+
direction: Literals(["toComputer", "fromComputer"]),
|
|
3081
|
+
key: String$1,
|
|
3082
|
+
path: String$1
|
|
3083
|
+
});
|
|
3084
|
+
/** Copy-back returns an upload receipt; only an actor command can attach it to an actor path. */
|
|
3085
|
+
const ComputerCopyResult = Struct({
|
|
3086
|
+
bytes: Int,
|
|
3087
|
+
receipt: optionalKey(String$1)
|
|
3088
|
+
});
|
|
3089
|
+
// ../effect/src/contract/computer/computer.schema.ts
|
|
3090
|
+
const kib = 1024;
|
|
3091
|
+
const mib = kib * kib;
|
|
3092
|
+
const inputKib = 100;
|
|
3093
|
+
const outputMib = 4;
|
|
3094
|
+
const smallest$1 = 1;
|
|
3095
|
+
const nothing = 0;
|
|
3096
|
+
/**
|
|
3097
|
+
* Archil's serverless exec limits, applied to every exec step so a step behaves the same in any engine: five
|
|
3098
|
+
* minutes, 100 KiB of command and standard input together, and 4 MiB of each output stream returned. Longer work
|
|
3099
|
+
* runs as a process in the computer; longer output belongs in files.
|
|
3100
|
+
*/
|
|
3101
|
+
const execLimits = {
|
|
3102
|
+
inputBytes: inputKib * kib,
|
|
3103
|
+
outputBytes: outputMib * mib,
|
|
3104
|
+
seconds: 300
|
|
3105
|
+
};
|
|
3106
|
+
const encoder = new globalThis.TextEncoder();
|
|
3107
|
+
/** One of an actor's computers. Lowercase letters, digits and hyphens, starting with a letter. */
|
|
3108
|
+
const ComputerName = String$1.check(isPattern(new RegExp(`^[a-z][a-z0-9-]{0,62}$`, "u"))).pipe(brand("ComputerName")).annotate({ description: "A computer's name, unique among its actor's computers." });
|
|
3109
|
+
const Seconds = Int.check(isBetween({
|
|
3110
|
+
maximum: execLimits.seconds,
|
|
3111
|
+
minimum: smallest$1
|
|
3112
|
+
}));
|
|
3113
|
+
const Positive = Int.check(isGreaterThanOrEqualTo(smallest$1));
|
|
3114
|
+
const ComputerSize = Struct({
|
|
3115
|
+
memoryMib: Positive,
|
|
3116
|
+
vcpu: Positive
|
|
3117
|
+
});
|
|
3118
|
+
/**
|
|
3119
|
+
* A computer to keep: its image, its size and the hosts it may reach. `egress` lists hosts or rules, never
|
|
3120
|
+
* credentials. `secrets` names the credentials the platform adds to an allowed host's requests on the way out, from
|
|
3121
|
+
* the actor's declared secrets, so no value ever reaches the computer.
|
|
3122
|
+
*/
|
|
3123
|
+
const ComputerSpec = Struct({
|
|
3124
|
+
egress: ArraySchema(String$1),
|
|
3125
|
+
image: String$1,
|
|
3126
|
+
name: ComputerName,
|
|
3127
|
+
secrets: optionalKey(ArraySchema(ComputerSecret)),
|
|
3128
|
+
size: ComputerSize
|
|
3129
|
+
});
|
|
3130
|
+
/**
|
|
3131
|
+
* Where a computer is. `paused` keeps its memory, processes and files; `stopped` and `failed` keep only its files;
|
|
3132
|
+
* `gone` means its disk no longer exists, so it is never recreated empty under the same name by accident.
|
|
3133
|
+
*/
|
|
3134
|
+
const ComputerState = Literals([
|
|
3135
|
+
"starting",
|
|
3136
|
+
"running",
|
|
3137
|
+
"paused",
|
|
3138
|
+
"stopped",
|
|
3139
|
+
"failed",
|
|
3140
|
+
"gone"
|
|
3141
|
+
]);
|
|
3142
|
+
const Computer = Struct({
|
|
3143
|
+
...ComputerSpec.fields,
|
|
3144
|
+
state: ComputerState
|
|
3145
|
+
});
|
|
3146
|
+
const withinInput = makeFilter((request) => encoder.encode(request.command).byteLength + (request.stdin?.byteLength ?? nothing) <= execLimits.inputBytes, { expected: `a command and standard input of at most ${execLimits.inputBytes} bytes together` });
|
|
3147
|
+
/**
|
|
3148
|
+
* One exec step. `key` is the step's stable logical-operation key, such as `Activity.idempotencyKey(name)`: the
|
|
3149
|
+
* computer records the outcome under it, so the same step sent again reads that outcome back instead of running.
|
|
3150
|
+
*/
|
|
3151
|
+
const ExecRequest = Struct({
|
|
3152
|
+
command: String$1,
|
|
3153
|
+
cwd: optionalKey(String$1),
|
|
3154
|
+
key: String$1.check(isMinLength(smallest$1)),
|
|
3155
|
+
stdin: optionalKey(Uint8Array$1),
|
|
3156
|
+
timeoutSeconds: optionalKey(Seconds)
|
|
3157
|
+
}).check(withinInput);
|
|
3158
|
+
/**
|
|
3159
|
+
* The step ran to an end, or its recorded outcome was read back; the two look the same. `exitCode` is absent when
|
|
3160
|
+
* the process was ended without one, such as at the time limit. Past 4 MiB a stream, output is not returned and
|
|
3161
|
+
* `truncated` is set; the whole of each stream stays in the step's directory on the computer.
|
|
3162
|
+
*/
|
|
3163
|
+
const ExecRan = TaggedStruct("Ran", {
|
|
3164
|
+
exitCode: optionalKey(Int),
|
|
3165
|
+
stderr: String$1,
|
|
3166
|
+
stdout: String$1,
|
|
3167
|
+
truncated: Boolean
|
|
3168
|
+
});
|
|
3169
|
+
/**
|
|
3170
|
+
* The step started once but no outcome was recorded: the computer lost power, or the step is still running. It is
|
|
3171
|
+
* not run again, because whatever it did outside the computer may already have happened. Reconcile with the
|
|
3172
|
+
* outside system by the step's key.
|
|
3173
|
+
*/
|
|
3174
|
+
const ExecUnknown = TaggedStruct("Unknown", {});
|
|
3175
|
+
const ExecResult = Union([ExecRan, ExecUnknown]);
|
|
3176
|
+
/** How much a log page returns at most, and when a request names no limit. */
|
|
3177
|
+
const logPageLines = 1e3;
|
|
3178
|
+
/**
|
|
3179
|
+
* One line of a computer's log, oldest first: what the platform did to it (made, paused, resumed, stopped, forked,
|
|
3180
|
+
* deleted) and each exec step's key and outcome. `seq` rises by one per line of the computer, so a reader passes the
|
|
3181
|
+
* last `seq` it saw as `after` to read on.
|
|
3182
|
+
*/
|
|
3183
|
+
const ComputerLogLine = Struct({
|
|
3184
|
+
at: Int,
|
|
3185
|
+
level: Literals([
|
|
3186
|
+
"info",
|
|
3187
|
+
"warn",
|
|
3188
|
+
"error"
|
|
3189
|
+
]),
|
|
3190
|
+
message: String$1,
|
|
3191
|
+
seq: Int
|
|
3192
|
+
});
|
|
3193
|
+
const LogLimit = Int.check(isBetween({
|
|
3194
|
+
maximum: logPageLines,
|
|
3195
|
+
minimum: smallest$1
|
|
3196
|
+
}));
|
|
3197
|
+
/** A page of a computer's log: the lines after `after`, at most `limit` (1 to 1,000; 1,000 when absent). */
|
|
3198
|
+
const ComputerLogPage = Struct({
|
|
3199
|
+
after: optionalKey(Int),
|
|
3200
|
+
limit: optionalKey(LogLimit)
|
|
3201
|
+
});
|
|
3202
|
+
// ../effect/src/contract/computer/step/computer-step.schema.ts
|
|
3203
|
+
const smallest = 1;
|
|
3204
|
+
const largestPage = 1e3;
|
|
3205
|
+
/** A step's name, unique among its job's steps: lowercase letters, digits, dots, underscores and hyphens. */
|
|
3206
|
+
const StepName = String$1.check(isPattern(new RegExp(`^[a-z0-9][a-z0-9._-]{0,62}$`, "u"))).annotate({ description: "A step's name, unique among its job's steps." });
|
|
3207
|
+
const { command, cwd, stdin, timeoutSeconds } = ExecRequest.fields;
|
|
3208
|
+
/**
|
|
3209
|
+
* One durable step of a job (`step` on an actor's computers): the exec request without its key, which the step derives from its job and
|
|
3210
|
+
* name, so the same step in a replayed job sends the same key.
|
|
3211
|
+
*/
|
|
3212
|
+
const StepRequest = Struct({
|
|
3213
|
+
command,
|
|
3214
|
+
cwd,
|
|
3215
|
+
name: StepName,
|
|
3216
|
+
stdin,
|
|
3217
|
+
timeoutSeconds
|
|
3218
|
+
});
|
|
3219
|
+
/** What a step journals before it sends anything: where it runs, its key, and when it first started. */
|
|
3220
|
+
const StepStart = Struct({
|
|
3221
|
+
command: String$1,
|
|
3222
|
+
computer: String$1,
|
|
3223
|
+
key: String$1,
|
|
3224
|
+
startedAt: Int,
|
|
3225
|
+
timeoutSeconds: Int
|
|
3226
|
+
});
|
|
3227
|
+
/** What a step journals once it settles: its outcome, and when it settled. */
|
|
3228
|
+
const StepEnd = Struct({
|
|
3229
|
+
endedAt: Int,
|
|
3230
|
+
outcome: ExecResult
|
|
3231
|
+
});
|
|
3232
|
+
/**
|
|
3233
|
+
* Where a step is. `running` has no outcome yet; `ran` ended with its exit code and output; `unknown` started and has no
|
|
3234
|
+
* recorded outcome, so it may or may not have done its work, and is never run again; `failed` could not run, such as on
|
|
3235
|
+
* a lost computer.
|
|
3236
|
+
*/
|
|
3237
|
+
const StepState = Literals([
|
|
3238
|
+
"running",
|
|
3239
|
+
"ran",
|
|
3240
|
+
"unknown",
|
|
3241
|
+
"failed"
|
|
3242
|
+
]);
|
|
3243
|
+
/**
|
|
3244
|
+
* One step as the actor's journal holds it. `step` is its key, the id a reader asks for it by and the key an outside
|
|
3245
|
+
* system reconciles an `unknown` step with. Output is only in a single step's read.
|
|
3246
|
+
*/
|
|
3247
|
+
const ComputerStep = Struct({
|
|
3248
|
+
command: String$1,
|
|
3249
|
+
computer: String$1,
|
|
3250
|
+
endedAt: optionalKey(Int),
|
|
3251
|
+
exitCode: optionalKey(Int),
|
|
3252
|
+
failure: optionalKey(String$1),
|
|
3253
|
+
job: String$1,
|
|
3254
|
+
name: String$1,
|
|
3255
|
+
startedAt: Int,
|
|
3256
|
+
state: StepState,
|
|
3257
|
+
stderr: optionalKey(String$1),
|
|
3258
|
+
stdout: optionalKey(String$1),
|
|
3259
|
+
step: String$1,
|
|
3260
|
+
timeoutSeconds: Int,
|
|
3261
|
+
truncated: optionalKey(Boolean)
|
|
3262
|
+
});
|
|
3263
|
+
const StepLimit = Int.check(isBetween({
|
|
3264
|
+
maximum: largestPage,
|
|
3265
|
+
minimum: smallest
|
|
3266
|
+
}));
|
|
3267
|
+
/** A page of an actor's steps, newest first: at most `limit` (1 to 1,000; 100 when absent). */
|
|
3268
|
+
const StepPage = Struct({ limit: optionalKey(StepLimit) });
|
|
3269
|
+
// ../effect/src/contract/computer/rpc/computer-rpc.contract.ts
|
|
3270
|
+
const ComputerRpcFailure = Union([
|
|
3271
|
+
HostedFailure,
|
|
3272
|
+
ComputerHeldError,
|
|
3273
|
+
ComputerLostError,
|
|
3274
|
+
ComputerNotFoundError,
|
|
3275
|
+
ComputersUnavailableError,
|
|
3276
|
+
StepNotFoundError
|
|
3277
|
+
]);
|
|
3278
|
+
/** The actor's encoded key, as every actor RPC carries it. */
|
|
3279
|
+
const Keyed = { key: String$1 };
|
|
3280
|
+
/** One computer of the actor, by name. */
|
|
3281
|
+
const Named = {
|
|
3282
|
+
computer: String$1,
|
|
3283
|
+
key: String$1
|
|
3284
|
+
};
|
|
3285
|
+
const Logs = {
|
|
3286
|
+
...Named,
|
|
3287
|
+
...ComputerLogPage.fields
|
|
3288
|
+
};
|
|
3289
|
+
/** A page of the actor's durable steps. */
|
|
3290
|
+
const Paged = {
|
|
3291
|
+
...Keyed,
|
|
3292
|
+
...StepPage.fields
|
|
3293
|
+
};
|
|
3294
|
+
/** One durable step of the actor, by its key. */
|
|
3295
|
+
const Stepped = {
|
|
3296
|
+
key: String$1,
|
|
3297
|
+
step: String$1
|
|
3298
|
+
};
|
|
3299
|
+
const Computers = ArraySchema(Computer);
|
|
3300
|
+
const Steps = ArraySchema(ComputerStep);
|
|
3301
|
+
const LogLines = ArraySchema(ComputerLogLine);
|
|
3302
|
+
const computerTag = ({ actor, operation }) => `${actor}/computer/${operation}`;
|
|
3303
|
+
const named = (actor, operation) => make$2(computerTag({
|
|
3304
|
+
actor,
|
|
3305
|
+
operation
|
|
3306
|
+
}), {
|
|
3307
|
+
error: ComputerRpcFailure,
|
|
3308
|
+
payload: Named,
|
|
3309
|
+
success: Computer
|
|
3310
|
+
});
|
|
3311
|
+
/**
|
|
3312
|
+
* An actor's computers as seen from outside the actor, under the tags docs/adr/0016 reserves:
|
|
3313
|
+
* `<Actor>/computer/<operation>`. Every payload carries the actor's encoded key. `list` and `get` answer computers as
|
|
3314
|
+
* they are; `pause`, `resume` and `stop` drive one there and answer it, and a `resume` of a computer a fork holds
|
|
3315
|
+
* fails with `ComputerHeldError`; `delete` removes one with its disk and answers nothing, so a client confirms it
|
|
3316
|
+
* first; `logs` reads a page of its log. There is no outside `exec` and no `ensure`: only the actor makes and runs
|
|
3317
|
+
* its computers. `steps` reads a page of the actor's durable steps, newest first, and `step` one step by its key with its
|
|
3318
|
+
* output (`StepNotFoundError` when the journal has none); both read the actor's own journal, not a computer.
|
|
3319
|
+
*/
|
|
3320
|
+
const computerRpcsOf = (actor) => [
|
|
3321
|
+
make$2(computerTag({
|
|
3322
|
+
actor,
|
|
3323
|
+
operation: "files"
|
|
3324
|
+
}), {
|
|
3325
|
+
error: ComputerRpcFailure,
|
|
3326
|
+
payload: ComputerCopy,
|
|
3327
|
+
success: ComputerCopyResult
|
|
3328
|
+
}),
|
|
3329
|
+
make$2(computerTag({
|
|
3330
|
+
actor,
|
|
3331
|
+
operation: "list"
|
|
3332
|
+
}), {
|
|
3333
|
+
error: ComputerRpcFailure,
|
|
3334
|
+
payload: Keyed,
|
|
3335
|
+
success: Computers
|
|
3336
|
+
}),
|
|
3337
|
+
named(actor, "get"),
|
|
3338
|
+
named(actor, "pause"),
|
|
3339
|
+
named(actor, "resume"),
|
|
3340
|
+
named(actor, "stop"),
|
|
3341
|
+
make$2(computerTag({
|
|
3342
|
+
actor,
|
|
3343
|
+
operation: "delete"
|
|
3344
|
+
}), {
|
|
3345
|
+
error: ComputerRpcFailure,
|
|
3346
|
+
payload: Named,
|
|
3347
|
+
success: Void
|
|
3348
|
+
}),
|
|
3349
|
+
make$2(computerTag({
|
|
3350
|
+
actor,
|
|
3351
|
+
operation: "logs"
|
|
3352
|
+
}), {
|
|
3353
|
+
error: ComputerRpcFailure,
|
|
3354
|
+
payload: Logs,
|
|
3355
|
+
success: LogLines
|
|
3356
|
+
}),
|
|
3357
|
+
make$2(computerTag({
|
|
3358
|
+
actor,
|
|
3359
|
+
operation: "steps"
|
|
3360
|
+
}), {
|
|
3361
|
+
error: ComputerRpcFailure,
|
|
3362
|
+
payload: Paged,
|
|
3363
|
+
success: Steps
|
|
3364
|
+
}),
|
|
3365
|
+
make$2(computerTag({
|
|
3366
|
+
actor,
|
|
3367
|
+
operation: "step"
|
|
3368
|
+
}), {
|
|
3369
|
+
error: ComputerRpcFailure,
|
|
3370
|
+
payload: Stepped,
|
|
3371
|
+
success: ComputerStep
|
|
3372
|
+
})
|
|
3373
|
+
];
|
|
3374
|
+
// ../effect/src/contract/client/actor-rpc.contract.ts
|
|
3375
|
+
const creationModes = ["create", "ensure"];
|
|
3376
|
+
const creationErrors = {
|
|
3377
|
+
create: ActorAlreadyExistsError,
|
|
3378
|
+
ensure: Never
|
|
3379
|
+
};
|
|
3380
|
+
const creationModesOf = (create) => {
|
|
3381
|
+
if (isNever(create.ast)) return [];
|
|
3382
|
+
return creationModes;
|
|
3383
|
+
};
|
|
3384
|
+
// ../effect/src/contract/caller/authentication.api.ts
|
|
3385
|
+
var Authentication = class extends Service()("@akterjs/effect/contract/caller/authentication.api/Authentication", { error: UnauthenticatedError }) {};
|
|
3386
|
+
// ../effect/src/contract/computer/step/step-failure.schema.ts
|
|
3387
|
+
/** Every failure a computer client can answer, as a schema, so a step journals the one it settled with. */
|
|
3388
|
+
const StepFailure = Union([
|
|
3389
|
+
ActorUnavailableError,
|
|
3390
|
+
CallerNotAllowedError,
|
|
3391
|
+
ComputerHeldError,
|
|
3392
|
+
ComputerLimitError,
|
|
3393
|
+
ComputerLostError,
|
|
3394
|
+
ComputerNotFoundError,
|
|
3395
|
+
ComputersUnavailableError,
|
|
3396
|
+
InvalidRequestError,
|
|
3397
|
+
UnauthenticatedError
|
|
3398
|
+
]);
|
|
3399
|
+
// ../effect/src/contract/computer/step/computer-step.contract.ts
|
|
3400
|
+
/**
|
|
3401
|
+
* How long past its own time limit a step keeps asking for its outcome, measured from when it was first journaled: the
|
|
3402
|
+
* time between journaling and the computer starting the command, which a lost reply or a restart can stretch.
|
|
3403
|
+
*/
|
|
3404
|
+
const graceSeconds = 10;
|
|
3405
|
+
/** How often a step asks again while its computer is unreachable or its command has no outcome yet. */
|
|
3406
|
+
const askEverySeconds = 2;
|
|
3407
|
+
const millis = 1e3;
|
|
3408
|
+
const none = 0;
|
|
3409
|
+
/** The step was sent before and its command has no recorded outcome yet: it may still be running. */
|
|
3410
|
+
var NoOutcomeYetError = class extends TaggedError()("NoOutcomeYetError", {}) {};
|
|
3411
|
+
/** Failures that say nothing about the step: the engine or control plane between the job and the computer is away. */
|
|
3412
|
+
const isPassing = is(Union([
|
|
3413
|
+
ActorUnavailableError,
|
|
3414
|
+
ComputersUnavailableError,
|
|
3415
|
+
NoOutcomeYetError
|
|
3416
|
+
]));
|
|
3417
|
+
const isRan = is(ExecRan);
|
|
3418
|
+
const sentOnce = (client, request, start) => {
|
|
3419
|
+
const sent = client.exec(start.computer, {
|
|
3420
|
+
...omit(request, ["name"]),
|
|
3421
|
+
key: start.key,
|
|
3422
|
+
timeoutSeconds: start.timeoutSeconds
|
|
3423
|
+
});
|
|
3424
|
+
return filterOrFail(sent, isRan, () => NoOutcomeYetError.make({}));
|
|
3425
|
+
};
|
|
3426
|
+
/**
|
|
3427
|
+
* Sends the step under its key until it has an outcome, asking again while its computer is unreachable or its command
|
|
3428
|
+
* runs on past a lost reply, until its time limit and the grace have passed since it was first journaled. The key
|
|
3429
|
+
* makes every send after the first read the command's outcome back instead of running it again. Past the deadline with
|
|
3430
|
+
* no outcome the step is `Unknown`: it may have done its work, and it never runs again.
|
|
3431
|
+
*/
|
|
3432
|
+
const settled = (client, request, start) => gen(function* settledStep() {
|
|
3433
|
+
const now = yield* currentTimeMillis;
|
|
3434
|
+
const deadline = start.startedAt + (start.timeoutSeconds + graceSeconds) * millis;
|
|
3435
|
+
const remaining = millis$1(Math.max(none, deadline - now));
|
|
3436
|
+
const asking = spaced(seconds(askEverySeconds)).pipe(upTo({ duration: remaining }));
|
|
3437
|
+
const outcome = yield* sentOnce(client, request, start).pipe(retry({
|
|
3438
|
+
schedule: asking,
|
|
3439
|
+
while: isPassing
|
|
3440
|
+
}), catchIf(isPassing, () => succeed(ExecUnknown.make({}))));
|
|
3441
|
+
return {
|
|
3442
|
+
endedAt: yield* currentTimeMillis,
|
|
3443
|
+
outcome
|
|
3444
|
+
};
|
|
3445
|
+
});
|
|
3446
|
+
const started = (computer, request) => gen(function* startedStep() {
|
|
3447
|
+
const key = yield* idempotencyKey(`step/${request.name}`);
|
|
3448
|
+
const startedAt = yield* currentTimeMillis;
|
|
3449
|
+
const timeoutSeconds = request.timeoutSeconds ?? execLimits.seconds;
|
|
3450
|
+
return {
|
|
3451
|
+
command: request.command,
|
|
3452
|
+
computer,
|
|
3453
|
+
key,
|
|
3454
|
+
startedAt,
|
|
3455
|
+
timeoutSeconds
|
|
3456
|
+
};
|
|
3457
|
+
});
|
|
3458
|
+
/**
|
|
3459
|
+
* Runs one command in one of the actor's computers as a durable step of the job that calls it, and answers its
|
|
3460
|
+
* outcome. The step journals where it runs, its key and when it started before it sends anything, then its outcome,
|
|
3461
|
+
* so `akter steps` reads it from the actor. A job replayed after a host or control plane restart reads both back: a
|
|
3462
|
+
* settled step answers its journaled outcome without reaching the computer, and a step cut off mid-flight sends the
|
|
3463
|
+
* same key again, which reads the command's own recorded outcome back and never runs it a second time. A command whose
|
|
3464
|
+
* outcome no send could read before its deadline answers `Unknown`; reconcile it with the outside system by its key.
|
|
3465
|
+
* Call it from a job, never from inside an activity, and give each step of a job its own name.
|
|
3466
|
+
*/
|
|
3467
|
+
const step = ({ client, computer, request }) => gen(function* durableStep() {
|
|
3468
|
+
const start = yield* make$4({
|
|
3469
|
+
execute: started(computer, request),
|
|
3470
|
+
name: `step-start/${request.name}`,
|
|
3471
|
+
success: StepStart
|
|
3472
|
+
});
|
|
3473
|
+
return (yield* make$4({
|
|
3474
|
+
error: StepFailure,
|
|
3475
|
+
execute: settled(client, request, start),
|
|
3476
|
+
name: `step/${request.name}`,
|
|
3477
|
+
success: StepEnd
|
|
3478
|
+
})).outcome;
|
|
3479
|
+
});
|
|
3480
|
+
// ../effect/src/contract/computer/computer-client.adapter.ts
|
|
3481
|
+
const checked = (schema, actor) => {
|
|
3482
|
+
const decode = decodeUnknownEffect(schema);
|
|
3483
|
+
return (value) => mapError(decode(value), (invalid) => InvalidRequestError.make({
|
|
3484
|
+
actor,
|
|
3485
|
+
message: invalid.message
|
|
3486
|
+
}));
|
|
3487
|
+
};
|
|
3488
|
+
/** A spec binds only secrets the actor declares, so a computer never gets a credential its actor may not read. */
|
|
3489
|
+
const declared = ({ definition, name }) => (spec) => {
|
|
3490
|
+
const undeclared = findFirst(spec.secrets ?? [], ({ secret }) => !contains(definition.secrets, secret));
|
|
3491
|
+
return match(undeclared, {
|
|
3492
|
+
onNone: () => succeed(spec),
|
|
3493
|
+
onSome: ({ secret }) => fail(SecretUnavailableError.make({
|
|
3494
|
+
actor: name,
|
|
3495
|
+
reason: "undeclared",
|
|
3496
|
+
secret
|
|
3497
|
+
}))
|
|
3498
|
+
});
|
|
3499
|
+
};
|
|
3500
|
+
/**
|
|
3501
|
+
* Checks every spec and exec request against the contract, so an engine never sees one past the limits, and every
|
|
3502
|
+
* secret a spec binds against the actor's declaration.
|
|
3503
|
+
*/
|
|
3504
|
+
const bounded = (client, source) => {
|
|
3505
|
+
const spec = checked(ComputerSpec, source.name);
|
|
3506
|
+
const request = checked(ExecRequest, source.name);
|
|
3507
|
+
const allowed = declared(source);
|
|
3508
|
+
const stepRequest = checked(StepRequest, source.name);
|
|
3509
|
+
const checkedClient = {
|
|
3510
|
+
...client,
|
|
3511
|
+
ensure: (wanted) => flatMap(flatMap(spec(wanted), allowed), client.ensure),
|
|
3512
|
+
exec: (computer, wanted) => flatMap(request(wanted), (valid) => client.exec(computer, valid))
|
|
3513
|
+
};
|
|
3514
|
+
return {
|
|
3515
|
+
...checkedClient,
|
|
3516
|
+
step: (computer, wanted) => flatMap(stepRequest(wanted), (valid) => step({
|
|
3517
|
+
client: checkedClient,
|
|
3518
|
+
computer,
|
|
3519
|
+
request: valid
|
|
3520
|
+
}))
|
|
3521
|
+
};
|
|
3522
|
+
};
|
|
3523
|
+
var ActorComputerClients = class ActorComputerClients extends Service$1()("@akterjs/effect/contract/computer/computer-client.adapter/ActorComputerClients") {
|
|
3524
|
+
static clientOf({ definition, name }) {
|
|
3525
|
+
return (key) => gen(function* connectComputers() {
|
|
3526
|
+
const clients = yield* serviceOption(ActorComputerClients);
|
|
3527
|
+
if (isNone(clients)) return yield* ComputersUnavailableError.make({ message: "computers aren't available on this host" });
|
|
3528
|
+
const encoded = yield* encodeEffect(definition.key)(key).pipe(mapError(() => InvalidRequestError.make({
|
|
3529
|
+
actor: name,
|
|
3530
|
+
message: "the actor key is invalid"
|
|
3531
|
+
})));
|
|
3532
|
+
return bounded(clients.value.connect({
|
|
3533
|
+
actor: name,
|
|
3534
|
+
key: encoded
|
|
3535
|
+
}), {
|
|
3536
|
+
definition,
|
|
3537
|
+
name
|
|
3538
|
+
});
|
|
3539
|
+
});
|
|
3540
|
+
}
|
|
3541
|
+
};
|
|
3542
|
+
// ../effect/src/contract/state/actor-state.service.ts
|
|
3543
|
+
var ActorState = class ActorState extends Service$1()("@akterjs/effect/contract/state/actor-state.service/ActorState") {
|
|
3544
|
+
static files({ files, now }) {
|
|
3545
|
+
return {
|
|
3546
|
+
attach: (path, receipt) => ActorState.use((state) => flatMap(now, (at) => state.attachFile({
|
|
3547
|
+
now: at,
|
|
3548
|
+
path,
|
|
3549
|
+
receipt
|
|
3550
|
+
}))),
|
|
3551
|
+
fileUsage: files.fileUsage,
|
|
3552
|
+
list: files.list,
|
|
3553
|
+
read: files.read,
|
|
3554
|
+
remove: (path) => ActorState.use((state) => state.removeFile(path))
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
};
|
|
3558
|
+
// ../effect/src/contract/secret/actor-secrets.adapter.ts
|
|
3559
|
+
const refused = (reason) => ({ actor, secret }) => SecretUnavailableError.make({
|
|
3560
|
+
actor,
|
|
3561
|
+
reason,
|
|
3562
|
+
secret
|
|
3563
|
+
});
|
|
3564
|
+
/** Reads each secret by its own name through `provider`: the process environment by default. */
|
|
3565
|
+
const fromProvider = (provider) => (request) => option(Redacted(request.secret)).pipe(provideService(ConfigProvider, provider), mapError(() => refused("unavailable")(request)), flatMap((found) => mapError(fromOption(found), () => refused("unset")(request))));
|
|
3566
|
+
/**
|
|
3567
|
+
* Where an engine's actors read their secrets. A host provides it to the app's job runtime, so job activities reach
|
|
3568
|
+
* it through `Actor.secret(name)`. Nothing else asks it directly: `Actor.secret` checks the declaration first.
|
|
3569
|
+
*/
|
|
3570
|
+
var ActorSecrets = class ActorSecrets extends Service$1()("@akterjs/effect/contract/secret/actor-secrets.adapter/ActorSecrets") {
|
|
3571
|
+
/**
|
|
3572
|
+
* Secrets from the `ConfigProvider` current when it is built, each under its own name. `Akter.jobs` and `Story.run`
|
|
3573
|
+
* provide it, so `akter dev` and scripts read the process environment (Bun loads `.env`), and a test builds them
|
|
3574
|
+
* under a `ConfigProvider` of its own.
|
|
3575
|
+
*/
|
|
3576
|
+
static fromConfig = effect(this, map$1(ConfigProvider, (provider) => ({ read: fromProvider(provider) })));
|
|
3577
|
+
static secretOf({ name, secrets: declared }) {
|
|
3578
|
+
return (secret) => gen(function* readSecret() {
|
|
3579
|
+
const request = {
|
|
3580
|
+
actor: name,
|
|
3581
|
+
secret
|
|
3582
|
+
};
|
|
3583
|
+
if (!contains(declared, secret)) return yield* refused("undeclared")(request);
|
|
3584
|
+
const handler = yield* serviceOption(ActorState);
|
|
3585
|
+
if (isSome(handler)) return yield* refused("command")(request);
|
|
3586
|
+
const secrets = yield* serviceOption(ActorSecrets);
|
|
3587
|
+
if (isNone(secrets)) return yield* refused("unavailable")(request);
|
|
3588
|
+
return yield* secrets.value.read(request);
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3591
|
+
};
|
|
3592
|
+
// ../effect/src/contract/file/file-client.adapter.ts
|
|
3593
|
+
var ActorFileClients = class ActorFileClients extends Service$1()("@akterjs/effect/contract/file/file-client.adapter/ActorFileClients") {
|
|
3594
|
+
static clientOf({ definition, name }) {
|
|
3595
|
+
return (key) => gen(function* connectFiles() {
|
|
3596
|
+
const clients = yield* serviceOption(ActorFileClients);
|
|
3597
|
+
if (isNone(clients)) return yield* FilesUnavailableError.make({ message: "files aren't available on this host" });
|
|
3598
|
+
const encoded = yield* encodeEffect(definition.key)(key).pipe(mapError(() => InvalidRequestError.make({
|
|
3599
|
+
actor: name,
|
|
3600
|
+
message: "the actor key is invalid"
|
|
3601
|
+
})));
|
|
3602
|
+
return clients.value.connect({
|
|
3603
|
+
actor: name,
|
|
3604
|
+
key: encoded
|
|
3605
|
+
});
|
|
3606
|
+
});
|
|
3607
|
+
}
|
|
3608
|
+
};
|
|
3609
|
+
// ../effect/src/contract/client/actor-client.adapter.ts
|
|
3610
|
+
const retryMillis = 50;
|
|
3611
|
+
const retryLimit = 5;
|
|
3612
|
+
const resumeCapMillis = 5e3;
|
|
3613
|
+
const noVersion = -1;
|
|
3614
|
+
const isTransportFailure = (failure) => isTagged(failure, "RpcClientError");
|
|
3615
|
+
const resubscribing = min([exponential(millis$1(retryMillis)), spaced(millis$1(resumeCapMillis))]).pipe(while_(({ input }) => isTransportFailure(input)));
|
|
3616
|
+
const resumed = (updates) => updates.pipe(retry$1(resubscribing), mapAccum(() => noVersion, (last, update) => {
|
|
3617
|
+
if (update.version > last) return [update.version, [update]];
|
|
3618
|
+
return [last, []];
|
|
3619
|
+
}));
|
|
3620
|
+
function wireSenders(rpcs) {
|
|
3621
|
+
return map$1(make(rpcs, { flatten: true }), (client) => ({
|
|
3622
|
+
send: client,
|
|
3623
|
+
watch: client
|
|
3624
|
+
}));
|
|
3625
|
+
}
|
|
3626
|
+
const sendOnce = ({ random, senders }, tag, request) => flatMap(random.uuidV7(), (commandId) => retry(senders.send(tag, {
|
|
3627
|
+
...request,
|
|
3628
|
+
commandId
|
|
3629
|
+
}), {
|
|
3630
|
+
schedule: exponential(millis$1(retryMillis)),
|
|
3631
|
+
times: retryLimit,
|
|
3632
|
+
while: isTransportFailure
|
|
3633
|
+
}));
|
|
3634
|
+
const queriesOf = ({ senders, source }, key) => map$3(source.definition.queries, (_declaration, member) => {
|
|
3635
|
+
const call = (payload) => senders.send(`${source.name}/${member}`, {
|
|
3636
|
+
key,
|
|
3637
|
+
payload
|
|
3638
|
+
});
|
|
3639
|
+
return Object.assign(call, { subscribe: (payload) => resumed(senders.watch(`${source.name}/${member}/subscribe`, {
|
|
3640
|
+
key,
|
|
3641
|
+
payload
|
|
3642
|
+
})) });
|
|
3643
|
+
});
|
|
3644
|
+
const wireClient = (wiring, key) => {
|
|
3645
|
+
const { definition, name } = wiring.source;
|
|
3646
|
+
const { send, watch } = wiring.senders;
|
|
3647
|
+
const command = (tag) => (payload) => sendOnce(wiring, tag, {
|
|
3648
|
+
key,
|
|
3649
|
+
payload
|
|
3650
|
+
});
|
|
3651
|
+
const creation = fromEntries(map$2(creationModesOf(definition.create), (mode) => [mode, command(`${name}/${mode}`)]));
|
|
3652
|
+
const fork = (into) => as(sendOnce(wiring, `${name}/fork`, {
|
|
3653
|
+
into,
|
|
3654
|
+
key
|
|
3655
|
+
}), wireClient(wiring, into));
|
|
3656
|
+
return {
|
|
3657
|
+
...map$3(definition.commands, (_declaration, member) => command(`${name}/${member}`)),
|
|
3658
|
+
...creation,
|
|
3659
|
+
...queriesOf(wiring, key),
|
|
3660
|
+
fork,
|
|
3661
|
+
state: resumed(watch(`${name}/state/subscribe`, { key })),
|
|
3662
|
+
warm: send(`${name}/warm`, { key })
|
|
3663
|
+
};
|
|
3664
|
+
};
|
|
3665
|
+
var ActorClients = class ActorClients extends Service$1()("@akterjs/effect/contract/client/actor-client.adapter/ActorClients") {
|
|
3666
|
+
static computerOf(source) {
|
|
3667
|
+
return ActorComputerClients.clientOf(source);
|
|
3668
|
+
}
|
|
3669
|
+
static filesOf(source) {
|
|
3670
|
+
return ActorFileClients.clientOf(source);
|
|
3671
|
+
}
|
|
3672
|
+
/** The actor's declared secrets, read in its job activities (`ActorSecrets`). */
|
|
3673
|
+
static secretOf(source) {
|
|
3674
|
+
return ActorSecrets.secretOf({
|
|
3675
|
+
name: source.name,
|
|
3676
|
+
secrets: source.definition.secrets
|
|
3677
|
+
});
|
|
3678
|
+
}
|
|
3679
|
+
static layer = effect(ActorClients, gen(function* makeActorClients() {
|
|
3680
|
+
const random = yield* SecureRandom;
|
|
3681
|
+
return { connect: (source, key) => map$1(wireSenders(source.rpcs), (senders) => wireClient({
|
|
3682
|
+
random,
|
|
3683
|
+
senders,
|
|
3684
|
+
source
|
|
3685
|
+
}, key)) };
|
|
3686
|
+
}));
|
|
3687
|
+
static clientOf(source) {
|
|
3688
|
+
return (key) => ActorClients.use((clients) => clients.connect(source, key));
|
|
3689
|
+
}
|
|
3690
|
+
};
|
|
3691
|
+
export { ActorAlreadyExistsError as $, SecretName as A, SuspendOnFailure as At, ComputerLostError as B, CommandId as C, isWrapper as Ct, uploadChunkBytes as D, isStreamSchema as Dt, fileTag as E, getStreamSchemas as Et, FileNotFoundError as F, wrapActivityResult as Ft, InvalidRequestError as G, ComputerHeldError as H, FileAccessDeniedError as I, make$6 as It, UnauthenticatedError as J, HandlerFailedError as K, StepNotFoundError as L, remove as Lt, InvalidFileRequestError as M, intoResult as Mt, FilesUnavailableError as N, make$5 as Nt, HostedFailure as O, fromWebSocket as Ot, FileTooLargeError as P, suspend as Pt, ActorErasedError as Q, ComputersUnavailableError as R, run as Rt, forkRpcOf as S, exitSchema as St, fileRpcsOf as T, ClientAbort as Tt, BlobTransferError as U, ComputerLimitError as V, StorageLimitError as W, ActorUnavailableError as X, CallerNotAllowedError as Y, ActorNotCreatedError as Z, ExecUnknown as _, Collector as _t, ActorComputerClients as a, json as at, ComputerFileRequest as b, ParseOptions as bt, creationModesOf as c, ResponseDefectEncoded as ct, StepEnd as d, constPong as dt, Protocol as et, StepStart as f, isTerminalResponse as ft, ExecRan as g, spanName as gt, ComputerSpec as h, spanAttributes as ht, ActorState as i, RpcSerialization as it, InvalidSecretNameError as j, Suspended as jt, SecretUnavailableError as k, Complete as kt, computerRpcsOf as l, constEof as lt, ComputerLogLine as m, RpcClientError as mt, ActorFileClients as n, makeProtocolHttp as nt, Authentication as o, layerNdjson as ot, largestPage as p, RpcClientDefect as pt, CommandIdExpiredError as q, ActorSecrets as r, withRun as rt, creationErrors as s, RequestId as st, ActorClients as t, make as tt, computerTag as u, constPing as ut, execLimits as v, makeCollectorUnsafe as vt, fileChunkBytes as w, make$2 as wt, computerFileBytes as x, ServerClient as xt, logPageLines as y, make$1 as yt, ComputerNotFoundError as z };
|