@demlik/tea 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -7
- package/dist/agent/index.d.ts +49 -37
- package/dist/agent/index.js +12 -8
- package/dist/chunk-4LPY67E4.js +18 -0
- package/dist/chunk-4LPY67E4.js.map +1 -0
- package/dist/chunk-5XU6ZJO2.js +533 -0
- package/dist/chunk-5XU6ZJO2.js.map +1 -0
- package/dist/{chunk-AYS5N6WY.js → chunk-6NG4V5SB.js} +62 -172
- package/dist/chunk-6NG4V5SB.js.map +1 -0
- package/dist/{chunk-3B5X7SBB.js → chunk-7MGXQZPW.js} +11 -9
- package/dist/chunk-7MGXQZPW.js.map +1 -0
- package/dist/{chunk-V46HSVCK.js → chunk-BCTEOVOU.js} +3 -3
- package/dist/{chunk-V46HSVCK.js.map → chunk-BCTEOVOU.js.map} +1 -1
- package/dist/chunk-CH5KTOEZ.js +710 -0
- package/dist/chunk-CH5KTOEZ.js.map +1 -0
- package/dist/chunk-CIHSHLQX.js +64 -0
- package/dist/chunk-CIHSHLQX.js.map +1 -0
- package/dist/{chunk-TCLBCERH.js → chunk-EHUDXAKC.js} +238 -212
- package/dist/chunk-EHUDXAKC.js.map +1 -0
- package/dist/chunk-GOX2CYIM.js +380 -0
- package/dist/chunk-GOX2CYIM.js.map +1 -0
- package/dist/{chunk-22POWGFA.js → chunk-IVJP3GKJ.js} +46 -20
- package/dist/chunk-IVJP3GKJ.js.map +1 -0
- package/dist/{chunk-QPEVCJ5Q.js → chunk-MVZS5FDM.js} +13 -6
- package/dist/chunk-MVZS5FDM.js.map +1 -0
- package/dist/{chunk-VTQI2NHP.js → chunk-MYNLY3HP.js} +9 -8
- package/dist/chunk-MYNLY3HP.js.map +1 -0
- package/dist/{chunk-Q5CQTBFA.js → chunk-NSIAORRY.js} +20 -30
- package/dist/chunk-NSIAORRY.js.map +1 -0
- package/dist/{chunk-MYXFNWAJ.js → chunk-QNGYQMZB.js} +4 -4
- package/dist/chunk-QNGYQMZB.js.map +1 -0
- package/dist/chunk-WT5PBPLB.js +98 -0
- package/dist/chunk-WT5PBPLB.js.map +1 -0
- package/dist/{core-DnzqWy6u.d.ts → core-BbgtiXdg.d.ts} +231 -139
- package/dist/do/index.d.ts +37 -33
- package/dist/do/index.js +21 -14
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-CWzA-o2B.d.ts → durable-effects-7MTK_jnj.d.ts} +1 -1
- package/dist/effect/index.d.ts +151 -0
- package/dist/effect/index.js +98 -0
- package/dist/effect/index.js.map +1 -0
- package/dist/extension/index.d.ts +6 -7
- package/dist/extension/index.js +3 -2
- package/dist/extension/index.js.map +1 -1
- package/dist/flow/index.d.ts +68 -59
- package/dist/flow/index.js +32 -27
- package/dist/flow/index.js.map +1 -1
- package/dist/idempotency/index.d.ts +6 -7
- package/dist/idempotency/index.js +4 -2
- package/dist/{index-CSyMYDAB.d.ts → index-7vV8xmsD.d.ts} +1 -1
- package/dist/{index-KXqTRJyb.d.ts → index-Bz5Rh9Ga.d.ts} +19 -96
- package/dist/index-CjFDUBeq.d.ts +207 -0
- package/dist/{index-CuNO9m8i.d.ts → index-CkFYA9Y6.d.ts} +14 -16
- package/dist/{index-CA_7I5g9.d.ts → index-Cou86-GX.d.ts} +137 -246
- package/dist/{index-DrIRb_Ch.d.ts → index-DU6JpQ8G.d.ts} +1 -1
- package/dist/{index-HSYgG2Yt.d.ts → index-Xufl55W8.d.ts} +247 -211
- package/dist/{index-C2DwkjlP.d.ts → index-_dOR3xqA.d.ts} +57 -45
- package/dist/index.d.ts +121 -385
- package/dist/index.js +2 -1
- package/dist/jev/index.d.ts +133 -97
- package/dist/jev/index.js +205 -161
- package/dist/jev/index.js.map +1 -1
- package/dist/{machine-DGlPWCWI.d.ts → machine-BQzTV8On.d.ts} +171 -288
- package/dist/machine-viz/index.d.ts +5 -5
- package/dist/machine-viz/index.js +8 -4
- package/dist/machine-viz/index.js.map +1 -1
- package/dist/mem/index.d.ts +3 -4
- package/dist/mem/index.js +2 -1
- package/dist/mem/index.js.map +1 -1
- package/dist/node/index.d.ts +119 -78
- package/dist/node/index.js +52 -38
- package/dist/node/index.js.map +1 -1
- package/dist/paginate/index.d.ts +27 -22
- package/dist/paginate/index.js +6 -4
- package/dist/parity/index.d.ts +4 -5
- package/dist/parity/index.js +3 -2
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/index.d.ts +2 -2
- package/dist/pbt/index.js +2 -1
- package/dist/pbt/index.js.map +1 -1
- package/dist/persistence/index.d.ts +6 -7
- package/dist/persistence/index.js +5 -3
- package/dist/promise/index.d.ts +186 -0
- package/dist/promise/index.js +5 -0
- package/dist/promise/index.js.map +1 -0
- package/dist/{protocol-D8VbH-VH.d.ts → protocol-ClRZBhHQ.d.ts} +7 -8
- package/dist/react/index.d.ts +36 -17
- package/dist/react/index.js +27 -4
- package/dist/react/index.js.map +1 -1
- package/dist/resilience/index.d.ts +63 -456
- package/dist/resilience/index.js +37 -483
- package/dist/resilience/index.js.map +1 -1
- package/dist/{runtime-types-CMF13BBh.d.ts → runtime-types-CiVpC0HN.d.ts} +131 -388
- package/dist/testing/index.d.ts +22 -16
- package/dist/testing/index.js +15 -7
- package/dist/testing/index.js.map +1 -1
- package/dist/timing/index.d.ts +25 -22
- package/dist/timing/index.js +4 -3
- package/dist/timing/index.js.map +1 -1
- package/dist/{types-BseNPIhr.d.ts → types-LxZxGYda.d.ts} +2 -2
- package/dist/work-queue/index.d.ts +5 -6
- package/package.json +18 -5
- package/dist/chunk-22POWGFA.js.map +0 -1
- package/dist/chunk-3B5X7SBB.js.map +0 -1
- package/dist/chunk-66PY5WYF.js +0 -1816
- package/dist/chunk-66PY5WYF.js.map +0 -1
- package/dist/chunk-AYS5N6WY.js.map +0 -1
- package/dist/chunk-L3TND7LA.js +0 -97
- package/dist/chunk-L3TND7LA.js.map +0 -1
- package/dist/chunk-MYXFNWAJ.js.map +0 -1
- package/dist/chunk-Q5CQTBFA.js.map +0 -1
- package/dist/chunk-QPEVCJ5Q.js.map +0 -1
- package/dist/chunk-TCLBCERH.js.map +0 -1
- package/dist/chunk-VTQI2NHP.js.map +0 -1
- package/dist/index-ZCMhnVKN.d.ts +0 -272
package/dist/resilience/index.js
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { DEFAULT_RESILIENT_NAME, canPass, createResilientCall, defaultCircuitPolicy, initBucket, initCircuit, initWindow, liftResilience,
|
|
1
|
+
import { createResilientCall } from '../chunk-6NG4V5SB.js';
|
|
2
|
+
export { DEFAULT_RESILIENT_NAME, canPass, createResilientCall, defaultCircuitPolicy, initBucket, initCircuit, initWindow, liftResilience, onFailure, onSuccess, record, refill, remaining, runCmdDef, tryConsume } from '../chunk-6NG4V5SB.js';
|
|
3
3
|
import { defaultRng, initRetry, recordFailure, shouldRetry, nextDelayMs } from '../chunk-VBDU4JL6.js';
|
|
4
|
-
import {
|
|
5
|
-
export { cacheEvictMsg, cacheEvictionSub, cacheEvictionSubscribe, deadlineExceeded, deadlineMsgType, deadlineSub, evictExpired, get, has, initCache, remove, set, setTimeoutArmTimer, subscribeDeadline, subscribeWith } from '../chunk-
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
4
|
+
import { unchecked } from '../chunk-4LPY67E4.js';
|
|
5
|
+
export { cacheEvictMsg, cacheEvictionSub, cacheEvictionSubscribe, deadlineExceeded, deadlineMsgType, deadlineSub, deadlines, deadlinesSub, evictExpired, get, has, initCache, nextTimer, remove, set, setTimeoutArmTimer, subscribeDeadline, subscribeWith } from '../chunk-IVJP3GKJ.js';
|
|
6
|
+
import '../chunk-GOX2CYIM.js';
|
|
7
|
+
import { Cmd, without } from '../chunk-CH5KTOEZ.js';
|
|
8
8
|
|
|
9
|
+
// src/internal/resilience/token-refresh/index.ts
|
|
9
10
|
function initTokenRefresh() {
|
|
10
11
|
return { token: null, stale: false };
|
|
11
12
|
}
|
|
12
13
|
var refreshToken = Cmd.define("refresh_token", {
|
|
13
|
-
input:
|
|
14
|
-
ok:
|
|
14
|
+
input: unchecked(),
|
|
15
|
+
ok: unchecked(),
|
|
15
16
|
err: ["token_refresh_failed"]
|
|
16
17
|
});
|
|
17
18
|
function refreshTokenCmd() {
|
|
18
19
|
return refreshToken({});
|
|
19
20
|
}
|
|
20
|
-
function tokenRefreshedMsg(token) {
|
|
21
|
-
return { type: MsgType.TokenRefreshed, token };
|
|
22
|
-
}
|
|
23
|
-
function tokenRefreshFailedMsg(error) {
|
|
24
|
-
return { type: MsgType.TokenRefreshFailed, error };
|
|
25
|
-
}
|
|
26
21
|
function createTokenRefresh(config = {}) {
|
|
27
22
|
const skewMs = config.skewMs !== void 0 && config.skewMs > 0 ? config.skewMs : 0;
|
|
28
23
|
function needsRefresh(state, at) {
|
|
@@ -45,28 +40,20 @@ function createTokenRefresh(config = {}) {
|
|
|
45
40
|
}
|
|
46
41
|
return [state, []];
|
|
47
42
|
}
|
|
48
|
-
function handlers(ports) {
|
|
49
|
-
return {
|
|
50
|
-
refresh_token: tryInterpret(
|
|
51
|
-
() => ports.refresh(),
|
|
52
|
-
(token) => tokenRefreshedMsg(token),
|
|
53
|
-
(error) => tokenRefreshFailedMsg(error)
|
|
54
|
-
)
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
43
|
return {
|
|
44
|
+
/** The `refresh_token` Cmd def — list it in the machine's `cmds`. */
|
|
45
|
+
run: refreshToken,
|
|
58
46
|
/** The slice initializer — spread into the consumer's `init`. */
|
|
59
47
|
init: initTokenRefresh,
|
|
60
48
|
needsRefresh,
|
|
61
49
|
on401,
|
|
62
50
|
refreshed,
|
|
63
|
-
ensureFresh
|
|
64
|
-
handlers
|
|
51
|
+
ensureFresh
|
|
65
52
|
};
|
|
66
53
|
}
|
|
67
54
|
|
|
68
55
|
// src/internal/resilience/authed-call/index.ts
|
|
69
|
-
function createAuthedCall(config, rng = Math.random) {
|
|
56
|
+
function createAuthedCall(config = {}, rng = Math.random) {
|
|
70
57
|
const rc = createResilientCall(config, rng);
|
|
71
58
|
const tr = createTokenRefresh({ skewMs: config.skewMs });
|
|
72
59
|
function init() {
|
|
@@ -94,13 +81,18 @@ function createAuthedCall(config, rng = Math.random) {
|
|
|
94
81
|
rc.attempt(cleared.resilience, key, input, at)
|
|
95
82
|
);
|
|
96
83
|
}
|
|
97
|
-
function succeed(s,
|
|
98
|
-
const settled = clearAuthKey(s, key);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
84
|
+
function succeed(s, msg) {
|
|
85
|
+
const settled = clearAuthKey(s, msg.cmd.key);
|
|
86
|
+
const { call, cmds } = rc.settle(settled.resilience, msg);
|
|
87
|
+
return liftResilient(settled, [call, cmds]);
|
|
88
|
+
}
|
|
89
|
+
function fail(s, msg) {
|
|
90
|
+
const { call: resilience, cmds } = rc.settle(s.resilience, msg);
|
|
91
|
+
const next = settleAuthIfDone(
|
|
92
|
+
{ ...s, resilience },
|
|
93
|
+
msg.cmd.key,
|
|
94
|
+
resilience
|
|
95
|
+
);
|
|
104
96
|
return [next, cmds];
|
|
105
97
|
}
|
|
106
98
|
function on401(s, key, at) {
|
|
@@ -109,7 +101,7 @@ function createAuthedCall(config, rng = Math.random) {
|
|
|
109
101
|
const input = call?.phase === "running" || call?.phase === "waiting_retry" ? call.input : void 0;
|
|
110
102
|
if (spent >= 1 || input === void 0) {
|
|
111
103
|
const error = { _tag: "unauthorized", key };
|
|
112
|
-
const [settled] = rc.settleFailed(s.resilience, key, error);
|
|
104
|
+
const [settled] = rc.settleFailed(s.resilience, key, error, at);
|
|
113
105
|
return [{ ...clearAuthKey(s, key), resilience: settled }, []];
|
|
114
106
|
}
|
|
115
107
|
return [
|
|
@@ -153,17 +145,17 @@ function createAuthedCall(config, rng = Math.random) {
|
|
|
153
145
|
}
|
|
154
146
|
return next;
|
|
155
147
|
}
|
|
156
|
-
function
|
|
157
|
-
return rc.
|
|
148
|
+
function deadlines2(s) {
|
|
149
|
+
return rc.deadlines(s.resilience);
|
|
158
150
|
}
|
|
159
|
-
function
|
|
160
|
-
|
|
161
|
-
return {
|
|
162
|
-
...rc.handlers({ run: ports.run }),
|
|
163
|
-
...tr.handlers(trPorts)
|
|
164
|
-
};
|
|
151
|
+
function timer(s) {
|
|
152
|
+
return rc.timer(s.resilience);
|
|
165
153
|
}
|
|
166
154
|
return {
|
|
155
|
+
/** The call's `Cmd.define`d run Cmd — list it in `cmds`. */
|
|
156
|
+
run: rc.run,
|
|
157
|
+
/** token-refresh's `refresh_token` Cmd def — list it in `cmds`. */
|
|
158
|
+
refresh: tr.run,
|
|
167
159
|
init,
|
|
168
160
|
attempt,
|
|
169
161
|
succeed,
|
|
@@ -174,8 +166,8 @@ function createAuthedCall(config, rng = Math.random) {
|
|
|
174
166
|
onTimer,
|
|
175
167
|
/** token-refresh's call-boundary verb, re-exposed for proactive expiry refresh. */
|
|
176
168
|
needsRefresh: (s, at) => tr.needsRefresh(s.auth, at),
|
|
177
|
-
|
|
178
|
-
|
|
169
|
+
deadlines: deadlines2,
|
|
170
|
+
timer
|
|
179
171
|
};
|
|
180
172
|
}
|
|
181
173
|
function liftAuthed(state, [slice, cmds]) {
|
|
@@ -213,445 +205,7 @@ async function retryToSuccess(port, policy, opts = {}) {
|
|
|
213
205
|
}
|
|
214
206
|
}
|
|
215
207
|
}
|
|
216
|
-
function deadlineExceededMsg(seq) {
|
|
217
|
-
return { type: "$deadline:exceeded", seq };
|
|
218
|
-
}
|
|
219
|
-
var deadlineDecision = Cmd.define("$deadline:decision", {
|
|
220
|
-
input: z.object({
|
|
221
|
-
decision: z.enum(["rearm", "expire", "idle"]),
|
|
222
|
-
/** The slice `seq` AFTER this transition (the re-arm generation now armed). */
|
|
223
|
-
seq: z.number()
|
|
224
|
-
}),
|
|
225
|
-
ok: z.void(),
|
|
226
|
-
err: []
|
|
227
|
-
});
|
|
228
|
-
function withDeadline(base, config) {
|
|
229
|
-
const windowMs = config.ms;
|
|
230
|
-
const isProgress = config.progress;
|
|
231
|
-
const update = {};
|
|
232
|
-
const baseMsgKeys = msgKeysOf(base);
|
|
233
|
-
for (const key of baseMsgKeys) {
|
|
234
|
-
if (key.startsWith("$deadline:")) {
|
|
235
|
-
throw new Error(
|
|
236
|
-
`withDeadline: the base machine declares a reserved "${key}" update cell \u2014 the wrapper owns the "$deadline:" Msg namespace. Rename the base Msg.`
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
for (const key of baseMsgKeys) {
|
|
241
|
-
update[key] = (state, msg) => {
|
|
242
|
-
const [nextBase, baseCmds] = applyCell(
|
|
243
|
-
base,
|
|
244
|
-
state.base,
|
|
245
|
-
msg
|
|
246
|
-
);
|
|
247
|
-
const armed = state.$deadline.phase === "armed";
|
|
248
|
-
const counts = armed && (isProgress === void 0 || isProgress(msg));
|
|
249
|
-
const $deadline = counts ? { phase: "armed", seq: state.$deadline.seq + 1 } : state.$deadline;
|
|
250
|
-
const next = { base: nextBase, $deadline };
|
|
251
|
-
const decision = deadlineDecision({
|
|
252
|
-
decision: counts ? "rearm" : "idle",
|
|
253
|
-
seq: $deadline.seq
|
|
254
|
-
});
|
|
255
|
-
return [next, [...baseCmds, decision]];
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
update["$deadline:exceeded"] = (state, msg) => {
|
|
259
|
-
const m = msg;
|
|
260
|
-
const fires = state.$deadline.phase === "armed" && m.seq === state.$deadline.seq;
|
|
261
|
-
const $deadline = fires ? { phase: "exceeded", seq: state.$deadline.seq } : state.$deadline;
|
|
262
|
-
const next = { base: state.base, $deadline };
|
|
263
|
-
const decision = deadlineDecision({
|
|
264
|
-
decision: fires ? "expire" : "idle",
|
|
265
|
-
seq: $deadline.seq
|
|
266
|
-
});
|
|
267
|
-
return [next, [decision]];
|
|
268
|
-
};
|
|
269
|
-
const baseInterpret = base.interpret ?? {};
|
|
270
|
-
if (Object.hasOwn(baseInterpret, "$deadline:decision")) {
|
|
271
|
-
throw new Error(
|
|
272
|
-
'withDeadline: the base machine declares a reserved "$deadline:decision" interpret handler \u2014 the wrapper owns the "$deadline:" Cmd namespace. Rename the base handler.'
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
const interpret = {
|
|
276
|
-
...baseInterpret,
|
|
277
|
-
"$deadline:decision": async () => {
|
|
278
|
-
}
|
|
279
|
-
};
|
|
280
|
-
const baseSubscriptions = base.subscriptions;
|
|
281
|
-
const subscriptions = (state) => {
|
|
282
|
-
const baseSubs = baseSubscriptions ? baseSubscriptions(state.base) : [];
|
|
283
|
-
if (state.$deadline.phase !== "armed") return baseSubs;
|
|
284
|
-
const timeout = {
|
|
285
|
-
id: subId(`$deadline:timeout:${state.$deadline.seq}`),
|
|
286
|
-
type: "$deadline:timeout",
|
|
287
|
-
delayMs: windowMs
|
|
288
|
-
};
|
|
289
|
-
return [...baseSubs, timeout];
|
|
290
|
-
};
|
|
291
|
-
const baseSubscribe = base.subscribe ?? {};
|
|
292
|
-
if (Object.hasOwn(baseSubscribe, "$deadline:timeout")) {
|
|
293
|
-
throw new Error(
|
|
294
|
-
'withDeadline: the base machine declares a reserved "$deadline:timeout" subscribe handler \u2014 the wrapper owns the "$deadline:" Sub namespace. Rename the base handler.'
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
const timeoutCell = fromTimeout(
|
|
298
|
-
(sub) => {
|
|
299
|
-
const seq = Number(sub.id.slice(sub.id.lastIndexOf(":") + 1));
|
|
300
|
-
return deadlineExceededMsg(seq);
|
|
301
|
-
}
|
|
302
|
-
);
|
|
303
|
-
const subscribe = {
|
|
304
|
-
...baseSubscribe,
|
|
305
|
-
"$deadline:timeout": timeoutCell
|
|
306
|
-
};
|
|
307
|
-
return {
|
|
308
|
-
init: (loaded, ctx) => {
|
|
309
|
-
if (loaded !== null) {
|
|
310
|
-
return [loaded, []];
|
|
311
|
-
}
|
|
312
|
-
const [base0, cmds] = base.init(null, ctx);
|
|
313
|
-
const model = {
|
|
314
|
-
base: base0,
|
|
315
|
-
$deadline: { phase: "armed", seq: 0 }
|
|
316
|
-
};
|
|
317
|
-
return [model, cmds];
|
|
318
|
-
},
|
|
319
|
-
update,
|
|
320
|
-
subscriptions,
|
|
321
|
-
subscribe,
|
|
322
|
-
interpret,
|
|
323
|
-
// The base's `Cmd.define` list rides through so `run`'s interpret edge
|
|
324
|
-
// still parses / stamps the base's settled Msgs behind the wrap (#66).
|
|
325
|
-
...base.cmds ? { cmds: base.cmds } : {}
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
function resilienceRunCmdDef() {
|
|
329
|
-
return Cmd.define("$resilience:run", {
|
|
330
|
-
input: z.custom(),
|
|
331
|
-
// The carried result is the base interpret handler's resolution (`M | void`).
|
|
332
|
-
// biome-ignore lint/suspicious/noConfusingVoidType: mirrors `Interpret`'s own `Promise<M | void>`
|
|
333
|
-
ok: z.custom(),
|
|
334
|
-
err: ["base_rejected", "deadline_exceeded"]
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
var RC_RETRY_PREFIX = "resilient:retry:";
|
|
338
|
-
var RC_DEADLINE_PREFIX = "resilient:deadline:";
|
|
339
|
-
var WX_RETRY_PREFIX = "$resilience:retry:";
|
|
340
|
-
var WX_DEADLINE_PREFIX = "$resilience:deadline:";
|
|
341
|
-
function toWrapperTimerId(rcId) {
|
|
342
|
-
if (rcId.startsWith(RC_RETRY_PREFIX))
|
|
343
|
-
return WX_RETRY_PREFIX + rcId.slice(RC_RETRY_PREFIX.length);
|
|
344
|
-
if (rcId.startsWith(RC_DEADLINE_PREFIX))
|
|
345
|
-
return WX_DEADLINE_PREFIX + rcId.slice(RC_DEADLINE_PREFIX.length);
|
|
346
|
-
return rcId;
|
|
347
|
-
}
|
|
348
|
-
function toRcTimerId(wxId) {
|
|
349
|
-
if (wxId.startsWith(WX_RETRY_PREFIX))
|
|
350
|
-
return RC_RETRY_PREFIX + wxId.slice(WX_RETRY_PREFIX.length);
|
|
351
|
-
if (wxId.startsWith(WX_DEADLINE_PREFIX))
|
|
352
|
-
return RC_DEADLINE_PREFIX + wxId.slice(WX_DEADLINE_PREFIX.length);
|
|
353
|
-
return wxId;
|
|
354
|
-
}
|
|
355
|
-
function updateDeclaresMsgKey(machine, key) {
|
|
356
|
-
if (formOf(machine) === "reducer") {
|
|
357
|
-
return Object.hasOwn(machine.update, key);
|
|
358
|
-
}
|
|
359
|
-
for (const innerTable of Object.values(machine.update)) {
|
|
360
|
-
if (innerTable !== null && (typeof innerTable === "object" || typeof innerTable === "function") && Object.hasOwn(innerTable, key)) {
|
|
361
|
-
return true;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
function withResilience(base, config, rng = Math.random) {
|
|
367
|
-
const { target } = config;
|
|
368
|
-
const keyOf = config.keyOf ?? (() => target);
|
|
369
|
-
const runCmd = resilienceRunCmdDef();
|
|
370
|
-
const timeSensitiveBrick = config.circuit !== void 0 || config.rateLimit !== void 0 || config.cache !== void 0 || config.deadline !== void 0;
|
|
371
|
-
if (timeSensitiveBrick && config.at === void 0) {
|
|
372
|
-
throw new Error(
|
|
373
|
-
"withResilience: a time-sensitive brick (circuit / rateLimit / cache / deadline) is configured but `config.at` is missing. The cold-attempt gate needs the REAL wall time the triggering base Msg carries as data (time-as-data) \u2014 without it the gate would fabricate `at = 0`, so a cold attempt after a real-time breaker trip computes a negative cooldown and the breaker NEVER recovers (and a deadline brick fires immediately). Provide `at: (msg) => msg.<wallTimeField>`."
|
|
374
|
-
);
|
|
375
|
-
}
|
|
376
|
-
const atOf = config.at ?? (() => 0);
|
|
377
|
-
const rc = createResilientCall(config, rng);
|
|
378
|
-
const update = {};
|
|
379
|
-
function isBaseMsg(result) {
|
|
380
|
-
return typeof result === "object" && result !== null && "type" in result;
|
|
381
|
-
}
|
|
382
|
-
function foldBase(state, msg, delivering = /* @__PURE__ */ new Set()) {
|
|
383
|
-
const [nextBase, baseCmds] = applyCell(base, state.base, msg);
|
|
384
|
-
let next = { base: nextBase, $resilience: state.$resilience };
|
|
385
|
-
const outCmds = [];
|
|
386
|
-
const at = atOf(msg);
|
|
387
|
-
for (const cmd of baseCmds) {
|
|
388
|
-
if (cmd.type !== target) {
|
|
389
|
-
outCmds.push(cmd);
|
|
390
|
-
continue;
|
|
391
|
-
}
|
|
392
|
-
const callKey = keyOf(cmd);
|
|
393
|
-
const [nextSlice, runCmds] = rc.attempt(
|
|
394
|
-
next.$resilience,
|
|
395
|
-
callKey,
|
|
396
|
-
cmd,
|
|
397
|
-
at
|
|
398
|
-
);
|
|
399
|
-
next = { ...next, $resilience: nextSlice };
|
|
400
|
-
outCmds.push(...renameRunCmds(runCmds));
|
|
401
|
-
if (runCmds.length === 0 && !delivering.has(callKey)) {
|
|
402
|
-
const call = nextSlice.calls[callKey];
|
|
403
|
-
if (call?.phase === "succeeded" && isBaseMsg(call.result)) {
|
|
404
|
-
const [delivered, moreCmds] = foldBase(
|
|
405
|
-
next,
|
|
406
|
-
call.result,
|
|
407
|
-
/* @__PURE__ */ new Set([...delivering, callKey])
|
|
408
|
-
);
|
|
409
|
-
next = delivered;
|
|
410
|
-
outCmds.push(...moreCmds);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
return [next, outCmds];
|
|
415
|
-
}
|
|
416
|
-
for (const key of msgKeysOf(base)) {
|
|
417
|
-
update[key] = (state, msg) => foldBase(state, msg);
|
|
418
|
-
}
|
|
419
|
-
update["$resilience:ok"] = (state, msg) => {
|
|
420
|
-
const m = msg;
|
|
421
|
-
const [slice, runCmds] = rc.succeed(state.$resilience, m.key, {
|
|
422
|
-
type: MsgType.ResilientOk,
|
|
423
|
-
key: m.key,
|
|
424
|
-
result: m.result,
|
|
425
|
-
at: m.at
|
|
426
|
-
});
|
|
427
|
-
const settled = { ...state, $resilience: slice };
|
|
428
|
-
const settleCmds = renameRunCmds(runCmds);
|
|
429
|
-
if (!isBaseMsg(m.result)) return [settled, settleCmds];
|
|
430
|
-
const [next, followCmds] = foldBase(settled, m.result, /* @__PURE__ */ new Set([m.key]));
|
|
431
|
-
return [next, [...settleCmds, ...followCmds]];
|
|
432
|
-
};
|
|
433
|
-
update["$resilience:err"] = (state, msg) => {
|
|
434
|
-
const m = msg;
|
|
435
|
-
const [slice, runCmds] = rc.fail(state.$resilience, m.key, {
|
|
436
|
-
type: MsgType.ResilientErr,
|
|
437
|
-
key: m.key,
|
|
438
|
-
error: m.error,
|
|
439
|
-
at: m.at
|
|
440
|
-
});
|
|
441
|
-
return [{ ...state, $resilience: slice }, renameRunCmds(runCmds)];
|
|
442
|
-
};
|
|
443
|
-
update["$resilience:timer"] = (state, msg) => {
|
|
444
|
-
const m = msg;
|
|
445
|
-
const [slice, runCmds] = rc.onTimer(state.$resilience, {
|
|
446
|
-
type: "deadline_exceeded",
|
|
447
|
-
id: toRcTimerId(m.id),
|
|
448
|
-
atMs: m.atMs
|
|
449
|
-
});
|
|
450
|
-
return [{ ...state, $resilience: slice }, renameRunCmds(runCmds)];
|
|
451
|
-
};
|
|
452
|
-
function renameRunCmds(runCmds) {
|
|
453
|
-
return runCmds.map((r) => runCmd({ key: r.key, input: r.input }));
|
|
454
|
-
}
|
|
455
|
-
const baseSubscriptions = base.subscriptions;
|
|
456
|
-
const baseSubscribe = base.subscribe;
|
|
457
|
-
function subscriptions(state) {
|
|
458
|
-
const baseSubs = baseSubscriptions ? baseSubscriptions(state.base) : [];
|
|
459
|
-
const rcSubs = rc.subs(state.$resilience);
|
|
460
|
-
const timerSubs = rcSubs.map((s) => ({
|
|
461
|
-
id: subId(toWrapperTimerId(s.id)),
|
|
462
|
-
type: "$resilience:timer",
|
|
463
|
-
atMs: s.atMs
|
|
464
|
-
}));
|
|
465
|
-
return [...baseSubs, ...timerSubs];
|
|
466
|
-
}
|
|
467
|
-
const baseInterpret = base.interpret ?? {};
|
|
468
|
-
const RESERVED = [
|
|
469
|
-
"$resilience:run",
|
|
470
|
-
"$resilience:ok",
|
|
471
|
-
"$resilience:err",
|
|
472
|
-
"$resilience:timer"
|
|
473
|
-
];
|
|
474
|
-
const surfaces = [
|
|
475
|
-
{
|
|
476
|
-
name: "update",
|
|
477
|
-
declares: (reserved) => updateDeclaresMsgKey(base, reserved)
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
name: "interpret",
|
|
481
|
-
declares: (reserved) => Object.hasOwn(baseInterpret, reserved)
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
name: "subscribe",
|
|
485
|
-
declares: (reserved) => Object.hasOwn(baseSubscribe ?? {}, reserved)
|
|
486
|
-
}
|
|
487
|
-
];
|
|
488
|
-
for (const reserved of RESERVED) {
|
|
489
|
-
for (const surface of surfaces) {
|
|
490
|
-
if (surface.declares(reserved)) {
|
|
491
|
-
throw new Error(
|
|
492
|
-
`withResilience: the base machine declares a reserved "${reserved}" ${surface.name} key \u2014 the wrapper owns the "$resilience:" namespace ($resilience:run / :ok / :err / :timer across update, interpret, and subscribe). Rename the base key.`
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
if (!Object.hasOwn(baseInterpret, target)) {
|
|
498
|
-
throw new Error(
|
|
499
|
-
`withResilience: no base interpret handler for target Cmd "${target}" \u2014 the resilient effect has nothing to perform. The base machine must declare an interpret handler for its target Cmd type.`
|
|
500
|
-
);
|
|
501
|
-
}
|
|
502
|
-
const runHandler = tryInterpret(
|
|
503
|
-
async (cmd, ctx) => {
|
|
504
|
-
const inner = cmd.input;
|
|
505
|
-
const handler = baseInterpret[inner.type];
|
|
506
|
-
if (handler === void 0) {
|
|
507
|
-
throw new Error(
|
|
508
|
-
`withResilience: no base interpret handler for target Cmd "${inner.type}" \u2014 the resilient effect has nothing to perform.`
|
|
509
|
-
);
|
|
510
|
-
}
|
|
511
|
-
return cmdEdgeOf(ctx)(
|
|
512
|
-
inner,
|
|
513
|
-
await handler(inner, ctx)
|
|
514
|
-
);
|
|
515
|
-
},
|
|
516
|
-
(result, cmd) => ({
|
|
517
|
-
type: "$resilience:ok",
|
|
518
|
-
key: cmd.key,
|
|
519
|
-
result,
|
|
520
|
-
at: Date.now()
|
|
521
|
-
}),
|
|
522
|
-
(error, cmd) => ({
|
|
523
|
-
type: "$resilience:err",
|
|
524
|
-
key: cmd.key,
|
|
525
|
-
error,
|
|
526
|
-
at: Date.now()
|
|
527
|
-
})
|
|
528
|
-
);
|
|
529
|
-
const interpret = {
|
|
530
|
-
...baseInterpret,
|
|
531
|
-
"$resilience:run": runHandler
|
|
532
|
-
};
|
|
533
|
-
const subscribeMap = {
|
|
534
|
-
...baseSubscribe ?? {},
|
|
535
|
-
"$resilience:timer": (sub, ctx, dispatch) => (
|
|
536
|
-
// Reuse the deadline subscribe cell wholesale: it arms a one-shot timer
|
|
537
|
-
// for `max(0, atMs - Date.now())` and fires when the wall clock crosses
|
|
538
|
-
// `atMs`. We hand it a `DeadlineSub` shape and translate its
|
|
539
|
-
// `deadline_exceeded` Msg into the wrapper's `$resilience:timer` Msg.
|
|
540
|
-
subscribeDeadline(
|
|
541
|
-
{ id: sub.id, type: "deadline", atMs: sub.atMs },
|
|
542
|
-
ctx,
|
|
543
|
-
(dl) => dispatch({ type: "$resilience:timer", id: dl.id, atMs: dl.atMs })
|
|
544
|
-
)
|
|
545
|
-
)
|
|
546
|
-
};
|
|
547
|
-
return {
|
|
548
|
-
init: (loaded, ctx) => {
|
|
549
|
-
if (loaded !== null) {
|
|
550
|
-
return [loaded, []];
|
|
551
|
-
}
|
|
552
|
-
const [base0, baseCmds] = base.init(null, ctx);
|
|
553
|
-
let resilience = rc.init();
|
|
554
|
-
const initCmds = [];
|
|
555
|
-
for (const cmd of baseCmds) {
|
|
556
|
-
if (cmd.type !== target) {
|
|
557
|
-
initCmds.push(cmd);
|
|
558
|
-
continue;
|
|
559
|
-
}
|
|
560
|
-
if (config.deadline !== void 0) {
|
|
561
|
-
throw new Error(
|
|
562
|
-
`withResilience: base.init emits the target Cmd "${target}" while a deadline brick is configured. The boot cold attempt has no real wall time (boot is gated at at=0), so the deadline would anchor at 0 + ${config.deadline.ms}ms and its $resilience:deadline Sub would fire IMMEDIATELY (max(0, atMs - now) === 0), failing the boot call instantly. Move the boot effect out of base.init and into a boot Msg dispatched after run() (where the triggering Msg carries a real at via config.at), so the deadline anchors at a real instant. (Boot effects belong in a boot Msg, not init Cmds.)`
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
const callKey = keyOf(cmd);
|
|
566
|
-
const [nextSlice, runCmds] = rc.attempt(resilience, callKey, cmd, 0);
|
|
567
|
-
resilience = nextSlice;
|
|
568
|
-
initCmds.push(...renameRunCmds(runCmds));
|
|
569
|
-
}
|
|
570
|
-
const model = { base: base0, $resilience: resilience };
|
|
571
|
-
return [model, initCmds];
|
|
572
|
-
},
|
|
573
|
-
update,
|
|
574
|
-
subscriptions,
|
|
575
|
-
subscribe: subscribeMap,
|
|
576
|
-
interpret,
|
|
577
|
-
// The base's `Cmd.define` list rides through so `run`'s interpret edge
|
|
578
|
-
// still parses / stamps the base's NON-target settled Msgs behind the
|
|
579
|
-
// wrap; the target's settle through the carrier above (#66).
|
|
580
|
-
...base.cmds ? { cmds: base.cmds } : {}
|
|
581
|
-
};
|
|
582
|
-
}
|
|
583
|
-
var telemetryEmit = Cmd.define("$telemetry:emit", {
|
|
584
|
-
input: z.object({ event: z.custom() }),
|
|
585
|
-
ok: z.void(),
|
|
586
|
-
err: [],
|
|
587
|
-
requirements: Cmd.requirements()
|
|
588
|
-
});
|
|
589
|
-
function withTelemetry(base, config = {}) {
|
|
590
|
-
const project = config.event;
|
|
591
|
-
const msgKeys = msgKeysOf(base);
|
|
592
|
-
const update = {};
|
|
593
|
-
for (const key of msgKeys) {
|
|
594
|
-
update[key] = (state, msg) => {
|
|
595
|
-
const [nextBase, baseCmds] = applyCell(base, state.base, msg);
|
|
596
|
-
const $telemetry = { seq: state.$telemetry.seq + 1 };
|
|
597
|
-
const next = { base: nextBase, $telemetry };
|
|
598
|
-
const event = project ? project(msg, state, next) : { seq: $telemetry.seq, msgType: msg.type };
|
|
599
|
-
const emit = telemetryEmit({ event });
|
|
600
|
-
return [next, [...baseCmds, emit]];
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
-
const baseInterpret = base.interpret ?? {};
|
|
604
|
-
if (Object.hasOwn(baseInterpret, "$telemetry:emit")) {
|
|
605
|
-
throw new Error(
|
|
606
|
-
'withTelemetry: the base machine declares a reserved "$telemetry:emit" interpret handler \u2014 the wrapper owns the "$telemetry:" Cmd namespace. Rename the base handler.'
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
const interpret = {
|
|
610
|
-
...baseInterpret,
|
|
611
|
-
// OBSERVE-ONLY at the boundary: the sink is fire-and-forget. The runtime
|
|
612
|
-
// `await`s every interpret handler in its dispatch loop, so awaiting the
|
|
613
|
-
// sink here would let a SLOW sink backpressure the wrapped machine (its
|
|
614
|
-
// next dispatch waits) and a FAILING sink crash dispatch (the throw would
|
|
615
|
-
// propagate out of the transition). Both violate the contract: telemetry
|
|
616
|
-
// must never affect base behavior OR latency. So we DO NOT await — we hand
|
|
617
|
-
// the event to the sink, normalize its result to a Promise, swallow any
|
|
618
|
-
// rejection/throw, and return immediately. The handler resolves in the same
|
|
619
|
-
// microtask the dispatch loop reaches it; the machine never waits on the
|
|
620
|
-
// sink, and a rejected sink can never become an unhandled rejection.
|
|
621
|
-
"$telemetry:emit": (cmd, ctx) => {
|
|
622
|
-
const event = cmd.event.at === void 0 && ctx.clock !== void 0 ? { ...cmd.event, at: ctx.clock() } : cmd.event;
|
|
623
|
-
try {
|
|
624
|
-
Promise.resolve(ctx.telemetrySink(event)).catch(() => {
|
|
625
|
-
});
|
|
626
|
-
} catch {
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
};
|
|
630
|
-
const baseSubscriptions = base.subscriptions;
|
|
631
|
-
const baseSubscribe = base.subscribe;
|
|
632
|
-
return {
|
|
633
|
-
init: (loaded, ctx) => {
|
|
634
|
-
if (loaded !== null) {
|
|
635
|
-
return [loaded, []];
|
|
636
|
-
}
|
|
637
|
-
const [base0, cmds] = base.init(null, ctx);
|
|
638
|
-
const model = { base: base0, $telemetry: { seq: 0 } };
|
|
639
|
-
return [model, cmds];
|
|
640
|
-
},
|
|
641
|
-
update,
|
|
642
|
-
// Subs merge to the base's, verbatim — telemetry owns no timers. The base
|
|
643
|
-
// subscribes against its own nested slice.
|
|
644
|
-
...baseSubscriptions ? {
|
|
645
|
-
subscriptions: (state) => baseSubscriptions(state.base)
|
|
646
|
-
} : {},
|
|
647
|
-
...baseSubscribe ? { subscribe: baseSubscribe } : {},
|
|
648
|
-
interpret,
|
|
649
|
-
// The base's `Cmd.define` list rides through so `run`'s interpret edge
|
|
650
|
-
// still parses / stamps the base's settled Msgs behind the wrap (#66).
|
|
651
|
-
...base.cmds ? { cmds: base.cmds } : {}
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
208
|
|
|
655
|
-
export { RetryExhaustedError, createAuthedCall, createTokenRefresh,
|
|
209
|
+
export { RetryExhaustedError, createAuthedCall, createTokenRefresh, initTokenRefresh, liftAuthed, refreshToken, refreshTokenCmd, retryToSuccess };
|
|
656
210
|
//# sourceMappingURL=index.js.map
|
|
657
211
|
//# sourceMappingURL=index.js.map
|