@demlik/tea 0.2.0 → 0.4.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 +49 -0
- package/dist/agent/index.d.ts +16 -770
- package/dist/agent/index.js +18 -16
- package/dist/authed-call/index.d.ts +3 -3
- package/dist/authed-call/index.js +22 -36
- package/dist/authed-call/index.js.map +1 -1
- package/dist/await-terminal/index.d.ts +2 -2
- package/dist/await-terminal/index.js +2 -2
- package/dist/batch-window/index.d.ts +3 -3
- package/dist/batch-window/index.js +3 -3
- package/dist/cache/index.d.ts +2 -2
- package/dist/cache/index.js +5 -2
- package/dist/{chunk-3545BOYL.js → chunk-25LBDCBC.js} +6 -5
- package/dist/chunk-25LBDCBC.js.map +1 -0
- package/dist/{chunk-IK4S5DJN.js → chunk-2AHAR7CX.js} +7 -14
- package/dist/chunk-2AHAR7CX.js.map +1 -0
- package/dist/{chunk-IN33Q4VJ.js → chunk-2KNLKQVN.js} +3 -3
- package/dist/{chunk-IN33Q4VJ.js.map → chunk-2KNLKQVN.js.map} +1 -1
- package/dist/{chunk-VFGKTGGC.js → chunk-5W7CNAHB.js} +191 -178
- package/dist/chunk-5W7CNAHB.js.map +1 -0
- package/dist/{chunk-6GIGQT6C.js → chunk-B5RAZVXW.js} +12 -11
- package/dist/chunk-B5RAZVXW.js.map +1 -0
- package/dist/{chunk-6VDCTR7N.js → chunk-D4NJBQAH.js} +258 -151
- package/dist/chunk-D4NJBQAH.js.map +1 -0
- package/dist/{chunk-UV6UWGEO.js → chunk-D736QUGF.js} +6 -5
- package/dist/chunk-D736QUGF.js.map +1 -0
- package/dist/{chunk-EGWTT5XJ.js → chunk-ET6QQNSQ.js} +76 -95
- package/dist/chunk-ET6QQNSQ.js.map +1 -0
- package/dist/chunk-EWJP3YYP.js +21 -0
- package/dist/chunk-EWJP3YYP.js.map +1 -0
- package/dist/{chunk-M6UZT7HS.js → chunk-FCKP6N7Y.js} +6 -5
- package/dist/chunk-FCKP6N7Y.js.map +1 -0
- package/dist/{chunk-TGG26XMK.js → chunk-FV3Z5MBE.js} +10 -5
- package/dist/chunk-FV3Z5MBE.js.map +1 -0
- package/dist/chunk-G5E74IJB.js +8 -0
- package/dist/chunk-G5E74IJB.js.map +1 -0
- package/dist/{chunk-G2U7DJHL.js → chunk-JFFVBEDI.js} +3 -3
- package/dist/{chunk-G2U7DJHL.js.map → chunk-JFFVBEDI.js.map} +1 -1
- package/dist/{chunk-FOGL3TC7.js → chunk-JXYYRKD6.js} +8 -10
- package/dist/chunk-JXYYRKD6.js.map +1 -0
- package/dist/{chunk-ZDRN3YCE.js → chunk-LJJV6ZD5.js} +17 -24
- package/dist/chunk-LJJV6ZD5.js.map +1 -0
- package/dist/chunk-LYLDCIPH.js +365 -0
- package/dist/chunk-LYLDCIPH.js.map +1 -0
- package/dist/{chunk-HJO6VNQI.js → chunk-MU6MCIAC.js} +3 -3
- package/dist/{chunk-HJO6VNQI.js.map → chunk-MU6MCIAC.js.map} +1 -1
- package/dist/{chunk-UYWUVEP6.js → chunk-MUUROGIH.js} +2 -2
- package/dist/chunk-MUUROGIH.js.map +1 -0
- package/dist/{chunk-DYRKDCJI.js → chunk-PBDYW2TU.js} +41 -7
- package/dist/chunk-PBDYW2TU.js.map +1 -0
- package/dist/{chunk-5VNWZADP.js → chunk-Q2UM7BXU.js} +18 -7
- package/dist/chunk-Q2UM7BXU.js.map +1 -0
- package/dist/chunk-RMX4EOQK.js +26 -0
- package/dist/chunk-RMX4EOQK.js.map +1 -0
- package/dist/{chunk-2YOE5PIS.js → chunk-S2EGRPCM.js} +8 -6
- package/dist/chunk-S2EGRPCM.js.map +1 -0
- package/dist/{chunk-5KVHID6A.js → chunk-SPWVPIFQ.js} +4 -4
- package/dist/{chunk-5KVHID6A.js.map → chunk-SPWVPIFQ.js.map} +1 -1
- package/dist/chunk-SSHDBOXF.js +71 -0
- package/dist/chunk-SSHDBOXF.js.map +1 -0
- package/dist/{chunk-6OUDPSSG.js → chunk-TWDHNIY6.js} +3 -3
- package/dist/{chunk-6OUDPSSG.js.map → chunk-TWDHNIY6.js.map} +1 -1
- package/dist/{chunk-SC3FAFZN.js → chunk-UF4MZSLT.js} +2 -2
- package/dist/chunk-UF4MZSLT.js.map +1 -0
- package/dist/chunk-ZJ5AOYBH.js +8 -0
- package/dist/chunk-ZJ5AOYBH.js.map +1 -0
- package/dist/{chunk-LEC4U6CX.js → chunk-ZVJZ72HY.js} +3 -3
- package/dist/{chunk-LEC4U6CX.js.map → chunk-ZVJZ72HY.js.map} +1 -1
- package/dist/circuit-breaker/index.d.ts +1 -0
- package/dist/circuit-breaker/index.js +1 -1
- package/dist/{core-BmlJOvxM.d.ts → core-42kapW0n.d.ts} +96 -6
- package/dist/deadline/index.d.ts +77 -11
- package/dist/deadline/index.js +3 -3
- package/dist/devtools/index.js +8 -28
- package/dist/devtools/index.js.map +1 -1
- package/dist/do/index.d.ts +52 -24
- package/dist/do/index.js +94 -92
- package/dist/do/index.js.map +1 -1
- package/dist/{durable-effects-9LxFpmh3.d.ts → durable-effects-CFRngTNA.d.ts} +3 -3
- package/dist/extension/index.d.ts +25 -7
- package/dist/extension/index.js +4 -3
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/react.js +4 -3
- package/dist/extension/react.js.map +1 -1
- package/dist/extension/subs/index.d.ts +2 -2
- package/dist/extension/subs/index.js +7 -10
- package/dist/extension/subs/index.js.map +1 -1
- package/dist/fan-out/index.d.ts +10 -10
- package/dist/fan-out/index.js +3 -3
- package/dist/idempotent-intake/index.d.ts +2 -2
- package/dist/idempotent-intake/index.js +3 -3
- package/dist/index.d.ts +50 -489
- package/dist/index.js +2 -2
- package/dist/llm-call/index.d.ts +3 -2
- package/dist/llm-call/index.js +12 -10
- package/dist/machine-B_BF4jij.d.ts +804 -0
- package/dist/machine-viz/index.d.ts +1 -1
- package/dist/machine-viz/index.js +2 -2
- package/dist/mem/index.d.ts +3 -2
- package/dist/mem/index.js.map +1 -1
- package/dist/monitored-run/index.d.ts +54 -30
- package/dist/monitored-run/index.js +7 -7
- package/dist/node/index.d.ts +3 -2
- package/dist/node/index.js +2 -3
- package/dist/node/index.js.map +1 -1
- package/dist/paginated-walk/index.d.ts +2 -2
- package/dist/paginated-walk/index.js +11 -10
- package/dist/parity/index.d.ts +6 -5
- package/dist/parity/index.js +5 -4
- package/dist/parity/index.js.map +1 -1
- package/dist/pbt/arbitraries/index.d.ts +1 -1
- package/dist/pbt/index.d.ts +1 -1
- package/dist/pbt/index.js +3 -3
- package/dist/pbt/index.js.map +1 -1
- package/dist/pbt/runners/index.d.ts +1 -1
- package/dist/pbt/runners/index.js +3 -3
- package/dist/poller/index.d.ts +59 -17
- package/dist/poller/index.js +56 -20
- package/dist/poller/index.js.map +1 -1
- package/dist/prediction/index.d.ts +1 -1
- package/dist/prediction/index.js +2 -2
- package/dist/pure/index.d.ts +1 -1
- package/dist/pure/index.js +2 -2
- package/dist/rate-limit/index.d.ts +2 -2
- package/dist/rate-limit/index.js +1 -1
- package/dist/react/index.d.ts +10 -3
- package/dist/react/index.js +2 -2
- package/dist/react/index.js.map +1 -1
- package/dist/reconciler/index.d.ts +2 -2
- package/dist/reconciler/index.js +13 -15
- package/dist/reconciler/index.js.map +1 -1
- package/dist/recorder/index.d.ts +20 -20
- package/dist/recorder/index.js +1 -1
- package/dist/resilient-call/index.d.ts +31 -6
- package/dist/resilient-call/index.js +10 -9
- package/dist/retry-backoff/index.d.ts +191 -14
- package/dist/retry-backoff/index.js +1 -1
- package/dist/retry-to-success/index.js +1 -1
- package/dist/runtime-types-CukV8kMX.d.ts +406 -0
- package/dist/saga/index.d.ts +3 -2
- package/dist/saga/index.js +2 -2
- package/dist/saga/index.js.map +1 -1
- package/dist/snapshot/index.d.ts +1 -1
- package/dist/snapshot/index.js +3 -3
- package/dist/subs/index.d.ts +372 -4
- package/dist/subs/index.js +4 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/throttled-input/index.d.ts +2 -2
- package/dist/throttled-input/index.js +14 -13
- package/dist/throttled-input/index.js.map +1 -1
- package/dist/token-refresh/index.d.ts +1 -1
- package/dist/token-refresh/index.js +3 -3
- package/dist/trace-replay/index.d.ts +12 -7
- package/dist/trace-replay/index.js +4 -3
- package/dist/{types-BoUWgwSm.d.ts → types-KbL3W1mj.d.ts} +1 -1
- package/dist/with-deadline/index.d.ts +1 -1
- package/dist/with-deadline/index.js +2 -2
- package/dist/with-resilience/index.d.ts +21 -2
- package/dist/with-resilience/index.js +12 -23
- package/dist/with-resilience/index.js.map +1 -1
- package/dist/with-telemetry/index.d.ts +1 -1
- package/dist/with-telemetry/index.js +2 -2
- package/dist/work-queue/adapter.d.ts +2 -2
- package/dist/work-queue/adapter.js +2 -2
- package/dist/work-queue/index.d.ts +3 -2
- package/dist/work-queue/index.js +1 -1
- package/dist/work-queue/index.js.map +1 -1
- package/dist/work-queue/ops.d.ts +2 -2
- package/dist/work-queue/ops.js +1 -1
- package/dist/workflow/index.d.ts +51 -19
- package/dist/workflow/index.js +71 -52
- package/dist/workflow/index.js.map +1 -1
- package/package.json +4 -1
- package/dist/chunk-2YOE5PIS.js.map +0 -1
- package/dist/chunk-3545BOYL.js.map +0 -1
- package/dist/chunk-5VNWZADP.js.map +0 -1
- package/dist/chunk-6GIGQT6C.js.map +0 -1
- package/dist/chunk-6VDCTR7N.js.map +0 -1
- package/dist/chunk-DYRKDCJI.js.map +0 -1
- package/dist/chunk-EGWTT5XJ.js.map +0 -1
- package/dist/chunk-EMJTPHI7.js +0 -91
- package/dist/chunk-EMJTPHI7.js.map +0 -1
- package/dist/chunk-FOGL3TC7.js.map +0 -1
- package/dist/chunk-IK4S5DJN.js.map +0 -1
- package/dist/chunk-M6UZT7HS.js.map +0 -1
- package/dist/chunk-NSDFA6M6.js +0 -198
- package/dist/chunk-NSDFA6M6.js.map +0 -1
- package/dist/chunk-SC3FAFZN.js.map +0 -1
- package/dist/chunk-SKAMZKTE.js +0 -20
- package/dist/chunk-SKAMZKTE.js.map +0 -1
- package/dist/chunk-TGG26XMK.js.map +0 -1
- package/dist/chunk-UV6UWGEO.js.map +0 -1
- package/dist/chunk-UYWUVEP6.js.map +0 -1
- package/dist/chunk-VFGKTGGC.js.map +0 -1
- package/dist/chunk-ZDRN3YCE.js.map +0 -1
|
@@ -1,6 +1,34 @@
|
|
|
1
|
-
import { detectUpdateForm, foldUpdates,
|
|
1
|
+
import { detectUpdateForm, foldUpdates, structuralHash, applyCellChecked } from './chunk-PBDYW2TU.js';
|
|
2
2
|
import { Result } from 'better-result';
|
|
3
3
|
|
|
4
|
+
// src/observability.ts
|
|
5
|
+
function historyTracker(runtime, size) {
|
|
6
|
+
const buffer = [];
|
|
7
|
+
let stopped = false;
|
|
8
|
+
const push = (entry) => {
|
|
9
|
+
buffer.push(entry);
|
|
10
|
+
if (buffer.length > size) buffer.shift();
|
|
11
|
+
};
|
|
12
|
+
const unobserve = size <= 0 ? () => {
|
|
13
|
+
} : runtime.observe((msg, state) => {
|
|
14
|
+
push({ msg, state });
|
|
15
|
+
});
|
|
16
|
+
const unboot = size <= 0 ? () => {
|
|
17
|
+
} : runtime.onBoot((state) => {
|
|
18
|
+
push({ msg: null, state });
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
snapshot() {
|
|
22
|
+
return buffer.slice();
|
|
23
|
+
},
|
|
24
|
+
stop() {
|
|
25
|
+
if (stopped) return;
|
|
26
|
+
stopped = true;
|
|
27
|
+
unobserve();
|
|
28
|
+
unboot();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
4
32
|
function absurd(x) {
|
|
5
33
|
throw new Error(`unreachable: ${JSON.stringify(x)}`);
|
|
6
34
|
}
|
|
@@ -8,25 +36,25 @@ var noop = (state, _msg) => [state, []];
|
|
|
8
36
|
var definedPortNames = /* @__PURE__ */ new Set();
|
|
9
37
|
var PortNameCollisionError = class extends Error {
|
|
10
38
|
name = "PortNameCollisionError";
|
|
39
|
+
_tag = "PortNameCollisionError";
|
|
11
40
|
constructor(portName) {
|
|
12
41
|
super(
|
|
13
42
|
`definePort: a port named "${portName}" was already defined. Each definePort call must use a unique name. If two modules need the same port, export it from one module and import it.`
|
|
14
43
|
);
|
|
15
44
|
}
|
|
16
45
|
};
|
|
46
|
+
var SubIdCollisionError = class extends Error {
|
|
47
|
+
name = "SubIdCollisionError";
|
|
48
|
+
_tag = "SubIdCollisionError";
|
|
49
|
+
constructor(id, declaredType, conflictingType) {
|
|
50
|
+
super(
|
|
51
|
+
`@demlik/tea: Sub.id collision: id="${id}" declared as type="${declaredType}" and type="${conflictingType}"`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
17
55
|
function __resetPortRegistry() {
|
|
18
56
|
definedPortNames.clear();
|
|
19
57
|
}
|
|
20
|
-
function defaultOnError(error, _context) {
|
|
21
|
-
setTimeout(() => {
|
|
22
|
-
throw error;
|
|
23
|
-
}, 0);
|
|
24
|
-
}
|
|
25
|
-
function normalizeSupervision(supervision) {
|
|
26
|
-
if (supervision === void 0) return { strategy: "stop" };
|
|
27
|
-
if (typeof supervision === "string") return { strategy: supervision };
|
|
28
|
-
return supervision;
|
|
29
|
-
}
|
|
30
58
|
var QuiescenceTimeoutError = class extends Error {
|
|
31
59
|
constructor(iterations) {
|
|
32
60
|
super(
|
|
@@ -35,6 +63,29 @@ var QuiescenceTimeoutError = class extends Error {
|
|
|
35
63
|
this.iterations = iterations;
|
|
36
64
|
}
|
|
37
65
|
name = "QuiescenceTimeoutError";
|
|
66
|
+
_tag = "QuiescenceTimeoutError";
|
|
67
|
+
};
|
|
68
|
+
var RuntimeDiscardNotice = class extends Error {
|
|
69
|
+
};
|
|
70
|
+
var RuntimeDiscardedError = class extends RuntimeDiscardNotice {
|
|
71
|
+
constructor(pendingCmds) {
|
|
72
|
+
super(
|
|
73
|
+
`@demlik/tea: runtime stopped with ${pendingCmds} Cmd(s) in flight \u2014 their results will reach no listener. In React this is usually a ctx-identity change rebuilding useMachine's runtime mid-flight: stabilize the ctx (useMemo / useState) so the runtime outlives the Cmds it started. An intentional teardown (unmount, navigation) can silence this with a run({ onError }) sink that ignores phase: "discard".`
|
|
74
|
+
);
|
|
75
|
+
this.pendingCmds = pendingCmds;
|
|
76
|
+
}
|
|
77
|
+
name = "RuntimeDiscardedError";
|
|
78
|
+
_tag = "RuntimeDiscardedError";
|
|
79
|
+
};
|
|
80
|
+
var DispatchDiscardedError = class extends RuntimeDiscardNotice {
|
|
81
|
+
constructor(msgType) {
|
|
82
|
+
super(
|
|
83
|
+
`@demlik/tea: Msg "${msgType}" arrived while the runtime was stopping and was discarded \u2014 stop() refuses new work so the drain terminates. It is the result of a Cmd that outlived its runtime; keep the runtime alive until the Cmd settles (in React: stabilize useMachine's ctx) if the transition matters.`
|
|
84
|
+
);
|
|
85
|
+
this.msgType = msgType;
|
|
86
|
+
}
|
|
87
|
+
name = "DispatchDiscardedError";
|
|
88
|
+
_tag = "DispatchDiscardedError";
|
|
38
89
|
};
|
|
39
90
|
function definePort(name) {
|
|
40
91
|
let isHmr = false;
|
|
@@ -50,6 +101,18 @@ function definePort(name) {
|
|
|
50
101
|
definedPortNames.add(name);
|
|
51
102
|
return { __brand: "port", name };
|
|
52
103
|
}
|
|
104
|
+
function schemaMigrate(schema, upcast = (raw) => raw) {
|
|
105
|
+
return (raw) => {
|
|
106
|
+
let migrated;
|
|
107
|
+
try {
|
|
108
|
+
migrated = upcast(raw);
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
const parsed = schema.safeParse(migrated);
|
|
113
|
+
return parsed.success ? parsed.data : null;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
53
116
|
function defineMachine(m) {
|
|
54
117
|
if (m.__form === void 0) {
|
|
55
118
|
Object.defineProperty(m, "__form", {
|
|
@@ -64,6 +127,68 @@ function defineMachine(m) {
|
|
|
64
127
|
function asReducer(reducer) {
|
|
65
128
|
return reducer;
|
|
66
129
|
}
|
|
130
|
+
function replay(machine, opts) {
|
|
131
|
+
const loaded = opts.loaded ?? null;
|
|
132
|
+
const [initialState, initCmds] = machine.init(loaded, opts.ctx);
|
|
133
|
+
if (loaded !== null && initCmds.length > 0) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
"TEA contract violation: machine.init must return [state, []] (no Cmds) when `loaded` is non-null. Init's rehydrate branch is a pure state passthrough \u2014 the migration/parse boundary, not the boot-effect hook.\n\nRoutes for boot effects:\n - Stateless infrastructure (e.g. chrome.alarms ensure) \u2192 host module top level, outside TEA.\n - State-conditional resume (e.g. re-attach a session) \u2192 a `boot` Msg dispatched once from the host after `run(...)` returns, handled in update.\n\nSee .patterns/tea/tea-invariants.md (Invariant 2)."
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
const { state, cmds: foldedCmds } = foldUpdates(
|
|
139
|
+
machine,
|
|
140
|
+
initialState,
|
|
141
|
+
opts.msgs
|
|
142
|
+
);
|
|
143
|
+
const cmds = [...initCmds, ...foldedCmds];
|
|
144
|
+
const subs = machine.subscriptions ? [...machine.subscriptions(state)] : [];
|
|
145
|
+
const depSubs = [];
|
|
146
|
+
if (machine.subs) {
|
|
147
|
+
for (const [index, entry] of machine.subs.entries()) {
|
|
148
|
+
const deps = entry.deps(state);
|
|
149
|
+
if (deps !== null) depSubs.push({ index, id: structuralHash(deps) });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { state, cmds, subs, depSubs };
|
|
153
|
+
}
|
|
154
|
+
function wrapDetached(handler) {
|
|
155
|
+
return (cmd, ctx, dispatch) => {
|
|
156
|
+
if (dispatch === void 0) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
"@demlik/tea: a wrapDetached handler was invoked without the injected dispatch. The kernel always supplies it; call the handler through the runtime, not directly."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
return handler(cmd, ctx, dispatch);
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function tryInterpret(work, onOk, onErr) {
|
|
165
|
+
return async (cmd, ctx) => {
|
|
166
|
+
const result = await Result.tryPromise({
|
|
167
|
+
try: () => work(cmd, ctx),
|
|
168
|
+
catch: (error) => error
|
|
169
|
+
});
|
|
170
|
+
return result.match({
|
|
171
|
+
ok: (value) => onOk(value, cmd),
|
|
172
|
+
err: (error) => onErr(error, cmd)
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/run.ts
|
|
178
|
+
function defaultOnError(error, _context) {
|
|
179
|
+
if (error instanceof RuntimeDiscardNotice) {
|
|
180
|
+
console.warn(error);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
throw error;
|
|
185
|
+
}, 0);
|
|
186
|
+
}
|
|
187
|
+
function normalizeSupervision(supervision) {
|
|
188
|
+
if (supervision === void 0) return { strategy: "stop" };
|
|
189
|
+
if (typeof supervision === "string") return { strategy: supervision };
|
|
190
|
+
return supervision;
|
|
191
|
+
}
|
|
67
192
|
function run(machine, opts) {
|
|
68
193
|
const { store } = opts;
|
|
69
194
|
const ctx = opts.ctx ?? {};
|
|
@@ -78,11 +203,22 @@ function run(machine, opts) {
|
|
|
78
203
|
defaultOnError(sinkError);
|
|
79
204
|
}
|
|
80
205
|
};
|
|
206
|
+
function fanout(items, phase, fn) {
|
|
207
|
+
for (const item of items) {
|
|
208
|
+
try {
|
|
209
|
+
fn(item);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
reportError(err, { phase });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
81
215
|
const supervision = normalizeSupervision(opts.supervision);
|
|
82
216
|
let state;
|
|
83
217
|
let bootError = null;
|
|
84
|
-
let
|
|
218
|
+
let gate = "open";
|
|
219
|
+
let inFlightCmds = 0;
|
|
85
220
|
const subRegistry = /* @__PURE__ */ new Map();
|
|
221
|
+
const depSubRegistry = /* @__PURE__ */ new Map();
|
|
86
222
|
const listeners = /* @__PURE__ */ new Set();
|
|
87
223
|
const observers = /* @__PURE__ */ new Set();
|
|
88
224
|
const bootHandlers = /* @__PURE__ */ new Set();
|
|
@@ -93,48 +229,78 @@ function run(machine, opts) {
|
|
|
93
229
|
function portEmit(port, value) {
|
|
94
230
|
const subscribers = portRegistry.get(port);
|
|
95
231
|
if (!subscribers || subscribers.size === 0) return;
|
|
96
|
-
|
|
232
|
+
fanout(subscribers, "port-emit", (listener) => listener(value));
|
|
233
|
+
}
|
|
234
|
+
const augmentedCtx = { ...ctx, emit: portEmit };
|
|
235
|
+
let tail = Promise.resolve();
|
|
236
|
+
function stopSubs(ids) {
|
|
237
|
+
for (const id of ids) {
|
|
238
|
+
const cleanup = subRegistry.get(id);
|
|
239
|
+
if (cleanup === void 0) continue;
|
|
97
240
|
try {
|
|
98
|
-
|
|
241
|
+
cleanup();
|
|
99
242
|
} catch (err) {
|
|
100
|
-
reportError(err, { phase: "
|
|
243
|
+
reportError(err, { phase: "sub-cleanup" });
|
|
101
244
|
}
|
|
245
|
+
subRegistry.delete(id);
|
|
102
246
|
}
|
|
103
247
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
248
|
+
function disposeDepSubs(indices) {
|
|
249
|
+
for (const index of indices) {
|
|
250
|
+
const running = depSubRegistry.get(index);
|
|
251
|
+
if (running === void 0) continue;
|
|
252
|
+
try {
|
|
253
|
+
running.dispose();
|
|
254
|
+
} catch (err) {
|
|
255
|
+
reportError(err, { phase: "sub-cleanup" });
|
|
256
|
+
}
|
|
257
|
+
depSubRegistry.delete(index);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function reconcileDepSubs() {
|
|
261
|
+
let firstError = null;
|
|
262
|
+
const subs = machine.subs;
|
|
263
|
+
if (!subs) return firstError;
|
|
264
|
+
for (const [i, entry] of subs.entries()) {
|
|
265
|
+
const deps = entry.deps(state);
|
|
266
|
+
if (deps === null) {
|
|
267
|
+
disposeDepSubs([i]);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const id = structuralHash(deps);
|
|
271
|
+
const running = depSubRegistry.get(i);
|
|
272
|
+
if (running !== void 0 && running.runningId === id) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
disposeDepSubs([i]);
|
|
276
|
+
try {
|
|
277
|
+
const dispose = entry.source(state, enqueueDispatch, ctx);
|
|
278
|
+
depSubRegistry.set(i, { runningId: id, dispose });
|
|
279
|
+
} catch (err) {
|
|
280
|
+
if (firstError === null) firstError = err;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return firstError;
|
|
110
284
|
}
|
|
111
|
-
let tail = Promise.resolve();
|
|
112
285
|
function reconcileSubs() {
|
|
113
|
-
|
|
286
|
+
const depError = reconcileDepSubs();
|
|
287
|
+
if (!machine.subscriptions) {
|
|
288
|
+
if (depError !== null) throw depError;
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
114
291
|
const desired = machine.subscriptions(state);
|
|
115
292
|
const desiredIds = /* @__PURE__ */ new Set();
|
|
116
293
|
const desiredTypeById = /* @__PURE__ */ new Map();
|
|
117
294
|
for (const sub of desired) {
|
|
118
295
|
const existing = desiredTypeById.get(sub.id);
|
|
119
296
|
if (existing !== void 0 && existing !== sub.type) {
|
|
120
|
-
throw new
|
|
121
|
-
`@demlik/tea: Sub.id collision: id="${sub.id}" declared as type="${existing}" and type="${sub.type}"`
|
|
122
|
-
);
|
|
297
|
+
throw new SubIdCollisionError(sub.id, existing, sub.type);
|
|
123
298
|
}
|
|
124
299
|
desiredTypeById.set(sub.id, sub.type);
|
|
125
300
|
}
|
|
126
301
|
for (const sub of desired) desiredIds.add(sub.id);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
cleanup();
|
|
131
|
-
} catch (err) {
|
|
132
|
-
reportError(err, { phase: "sub-cleanup" });
|
|
133
|
-
}
|
|
134
|
-
subRegistry.delete(id);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
let firstStartError = null;
|
|
302
|
+
stopSubs([...subRegistry.keys()].filter((id) => !desiredIds.has(id)));
|
|
303
|
+
let firstStartError = depError;
|
|
138
304
|
for (const sub of desired) {
|
|
139
305
|
if (subRegistry.has(sub.id)) continue;
|
|
140
306
|
const handler = machine.subscribe?.[sub.type];
|
|
@@ -155,40 +321,43 @@ function run(machine, opts) {
|
|
|
155
321
|
if (firstStartError !== null) throw firstStartError;
|
|
156
322
|
}
|
|
157
323
|
const interpretMap = machine.interpret ?? {};
|
|
324
|
+
const interpretDispatch = (msg) => {
|
|
325
|
+
enqueueDispatch(msg).catch(reportUndelivered);
|
|
326
|
+
};
|
|
327
|
+
function reportUndelivered(error) {
|
|
328
|
+
reportError(error, {
|
|
329
|
+
phase: error instanceof DispatchDiscardedError ? "discard" : "follow-up"
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
function trackInFlight(work) {
|
|
333
|
+
inFlightCmds++;
|
|
334
|
+
return Promise.resolve(work).finally(() => {
|
|
335
|
+
inFlightCmds--;
|
|
336
|
+
});
|
|
337
|
+
}
|
|
158
338
|
async function runInterpret(cmds) {
|
|
159
339
|
for (const cmd of cmds) {
|
|
160
340
|
const handler = interpretMap[cmd.type];
|
|
161
341
|
if (!handler) continue;
|
|
162
|
-
const follow = await
|
|
163
|
-
|
|
164
|
-
|
|
342
|
+
const follow = await trackInFlight(
|
|
343
|
+
handler(
|
|
344
|
+
cmd,
|
|
345
|
+
augmentedCtx,
|
|
346
|
+
interpretDispatch
|
|
347
|
+
)
|
|
165
348
|
);
|
|
166
349
|
if (follow !== void 0 && follow !== null) {
|
|
167
|
-
enqueueDispatch(follow).catch(
|
|
168
|
-
reportError(error, { phase: "follow-up" });
|
|
169
|
-
});
|
|
350
|
+
enqueueDispatch(follow).catch(reportUndelivered);
|
|
170
351
|
}
|
|
171
352
|
}
|
|
172
353
|
}
|
|
173
354
|
function fireListeners() {
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
listener();
|
|
177
|
-
} catch (err) {
|
|
178
|
-
reportError(err, { phase: "listener" });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
355
|
+
fanout(listeners, "listener", (listener) => listener());
|
|
181
356
|
}
|
|
182
357
|
function fireObservers(msg) {
|
|
183
358
|
if (observers.size === 0 || state === void 0) return;
|
|
184
359
|
const snapshot = state;
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
observer(msg, snapshot);
|
|
188
|
-
} catch (err) {
|
|
189
|
-
reportError(err, { phase: "observer" });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
360
|
+
fanout(observers, "observer", (observer) => observer(msg, snapshot));
|
|
192
361
|
}
|
|
193
362
|
function fireEvents(msg) {
|
|
194
363
|
if (eventHandlers.size === 0 || state === void 0) return;
|
|
@@ -202,26 +371,14 @@ function run(machine, opts) {
|
|
|
202
371
|
for (const event of events) {
|
|
203
372
|
const bucket = eventHandlers.get(event.type);
|
|
204
373
|
if (bucket === void 0) continue;
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
handler(event);
|
|
208
|
-
} catch (err) {
|
|
209
|
-
reportError(err, { phase: "event" });
|
|
210
|
-
}
|
|
211
|
-
}
|
|
374
|
+
fanout(bucket, "event", (handler) => handler(event));
|
|
212
375
|
}
|
|
213
376
|
}
|
|
214
377
|
function fireBoot() {
|
|
215
378
|
booted = true;
|
|
216
379
|
if (bootHandlers.size === 0 || state === void 0) return;
|
|
217
380
|
const snapshot = state;
|
|
218
|
-
|
|
219
|
-
try {
|
|
220
|
-
handler(snapshot);
|
|
221
|
-
} catch (err) {
|
|
222
|
-
reportError(err, { phase: "boot" });
|
|
223
|
-
}
|
|
224
|
-
}
|
|
381
|
+
fanout(bootHandlers, "boot", (handler) => handler(snapshot));
|
|
225
382
|
}
|
|
226
383
|
function settleDoneWaiters() {
|
|
227
384
|
if (doneWaiters.size === 0 || state === void 0) return;
|
|
@@ -245,10 +402,19 @@ function run(machine, opts) {
|
|
|
245
402
|
if (state === void 0) {
|
|
246
403
|
throw new Error("@demlik/tea: runtime not booted");
|
|
247
404
|
}
|
|
405
|
+
if (machine.identity !== void 0) {
|
|
406
|
+
const addressed = machine.identity.ofMsg(msg);
|
|
407
|
+
if (addressed !== void 0) {
|
|
408
|
+
const own = machine.identity.ofState(state);
|
|
409
|
+
if (own !== void 0 && structuralHash(addressed) !== structuralHash(own)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
248
414
|
let next;
|
|
249
415
|
let cmds;
|
|
250
416
|
try {
|
|
251
|
-
[next, cmds] =
|
|
417
|
+
[next, cmds] = applyCellChecked(machine, state, msg);
|
|
252
418
|
} catch (reduceError) {
|
|
253
419
|
reportError(reduceError, { phase: "reduce" });
|
|
254
420
|
switch (supervision.strategy) {
|
|
@@ -259,7 +425,7 @@ function run(machine, opts) {
|
|
|
259
425
|
case "escalate":
|
|
260
426
|
throw reduceError;
|
|
261
427
|
default:
|
|
262
|
-
|
|
428
|
+
gate = "closed";
|
|
263
429
|
throw reduceError;
|
|
264
430
|
}
|
|
265
431
|
}
|
|
@@ -287,8 +453,11 @@ function run(machine, opts) {
|
|
|
287
453
|
settleDoneWaiters();
|
|
288
454
|
}
|
|
289
455
|
function enqueueDispatch(msg) {
|
|
290
|
-
if (
|
|
291
|
-
return Promise.reject(
|
|
456
|
+
if (gate !== "open") {
|
|
457
|
+
return Promise.reject(
|
|
458
|
+
gate === "draining" ? new DispatchDiscardedError(msg.type) : new Error("@demlik/tea: runtime stopped")
|
|
459
|
+
);
|
|
460
|
+
}
|
|
292
461
|
const next = tail.then(() => {
|
|
293
462
|
if (bootError !== null) throw bootError;
|
|
294
463
|
return stepDispatch(msg);
|
|
@@ -337,11 +506,8 @@ function run(machine, opts) {
|
|
|
337
506
|
},
|
|
338
507
|
onBoot(handler) {
|
|
339
508
|
if (booted && state !== void 0) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
} catch (err) {
|
|
343
|
-
reportError(err, { phase: "boot" });
|
|
344
|
-
}
|
|
509
|
+
const snapshot = state;
|
|
510
|
+
fanout([handler], "boot", (h) => h(snapshot));
|
|
345
511
|
return () => {
|
|
346
512
|
};
|
|
347
513
|
}
|
|
@@ -384,9 +550,6 @@ function run(machine, opts) {
|
|
|
384
550
|
emitPort(port, value) {
|
|
385
551
|
portEmit(port, value);
|
|
386
552
|
},
|
|
387
|
-
// `ready` is assigned just below (it must resolve to `runtime` itself,
|
|
388
|
-
// which can't be referenced inside its own object literal). See the
|
|
389
|
-
// assignment + rationale after this block.
|
|
390
553
|
ready: readyPromise,
|
|
391
554
|
idle() {
|
|
392
555
|
return drainToQuiescence();
|
|
@@ -403,16 +566,16 @@ function run(machine, opts) {
|
|
|
403
566
|
});
|
|
404
567
|
},
|
|
405
568
|
async stop() {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
} catch (err) {
|
|
412
|
-
reportError(err, { phase: "sub-cleanup" });
|
|
413
|
-
}
|
|
414
|
-
subRegistry.delete(id);
|
|
569
|
+
if (gate === "open") gate = "draining";
|
|
570
|
+
if (inFlightCmds > 0) {
|
|
571
|
+
reportError(new RuntimeDiscardedError(inFlightCmds), {
|
|
572
|
+
phase: "discard"
|
|
573
|
+
});
|
|
415
574
|
}
|
|
575
|
+
await tail;
|
|
576
|
+
gate = "closed";
|
|
577
|
+
stopSubs([...subRegistry.keys()]);
|
|
578
|
+
disposeDepSubs([...depSubRegistry.keys()]);
|
|
416
579
|
if (store && state !== void 0 && bootError === null) {
|
|
417
580
|
try {
|
|
418
581
|
await store.save(state);
|
|
@@ -424,63 +587,7 @@ function run(machine, opts) {
|
|
|
424
587
|
};
|
|
425
588
|
return runtime;
|
|
426
589
|
}
|
|
427
|
-
function historyTracker(runtime, size) {
|
|
428
|
-
const buffer = [];
|
|
429
|
-
let stopped = false;
|
|
430
|
-
const push = (entry) => {
|
|
431
|
-
buffer.push(entry);
|
|
432
|
-
if (buffer.length > size) buffer.shift();
|
|
433
|
-
};
|
|
434
|
-
const unobserve = size <= 0 ? () => {
|
|
435
|
-
} : runtime.observe((msg, state) => {
|
|
436
|
-
push({ msg, state });
|
|
437
|
-
});
|
|
438
|
-
const unboot = size <= 0 ? () => {
|
|
439
|
-
} : runtime.onBoot((state) => {
|
|
440
|
-
push({ msg: null, state });
|
|
441
|
-
});
|
|
442
|
-
return {
|
|
443
|
-
snapshot() {
|
|
444
|
-
return buffer.slice();
|
|
445
|
-
},
|
|
446
|
-
stop() {
|
|
447
|
-
if (stopped) return;
|
|
448
|
-
stopped = true;
|
|
449
|
-
unobserve();
|
|
450
|
-
unboot();
|
|
451
|
-
}
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
function replay(machine, opts) {
|
|
455
|
-
const loaded = opts.loaded ?? null;
|
|
456
|
-
const [initialState, initCmds] = machine.init(loaded, opts.ctx);
|
|
457
|
-
if (loaded !== null && initCmds.length > 0) {
|
|
458
|
-
throw new Error(
|
|
459
|
-
"TEA contract violation: machine.init must return [state, []] (no Cmds) when `loaded` is non-null. Init's rehydrate branch is a pure state passthrough \u2014 the migration/parse boundary, not the boot-effect hook.\n\nRoutes for boot effects:\n - Stateless infrastructure (e.g. chrome.alarms ensure) \u2192 host module top level, outside TEA.\n - State-conditional resume (e.g. re-attach a session) \u2192 a `boot` Msg dispatched once from the host after `run(...)` returns, handled in update.\n\nSee .patterns/tea/tea-invariants.md (Invariant 2)."
|
|
460
|
-
);
|
|
461
|
-
}
|
|
462
|
-
const { state, cmds: foldedCmds } = foldUpdates(
|
|
463
|
-
machine,
|
|
464
|
-
initialState,
|
|
465
|
-
opts.msgs
|
|
466
|
-
);
|
|
467
|
-
const cmds = [...initCmds, ...foldedCmds];
|
|
468
|
-
const subs = machine.subscriptions ? [...machine.subscriptions(state)] : [];
|
|
469
|
-
return { state, cmds, subs };
|
|
470
|
-
}
|
|
471
|
-
function tryInterpret(work, onOk, onErr) {
|
|
472
|
-
return async (cmd, ctx) => {
|
|
473
|
-
const result = await Result.tryPromise({
|
|
474
|
-
try: () => work(cmd, ctx),
|
|
475
|
-
catch: (error) => error
|
|
476
|
-
});
|
|
477
|
-
return result.match({
|
|
478
|
-
ok: (value) => onOk(value, cmd),
|
|
479
|
-
err: (error) => onErr(error, cmd)
|
|
480
|
-
});
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
590
|
|
|
484
|
-
export { PortNameCollisionError, QuiescenceTimeoutError, __resetPortRegistry, absurd, asReducer, defineMachine, definePort, historyTracker, noop, replay, run, tryInterpret };
|
|
485
|
-
//# sourceMappingURL=chunk-
|
|
486
|
-
//# sourceMappingURL=chunk-
|
|
591
|
+
export { DispatchDiscardedError, PortNameCollisionError, QuiescenceTimeoutError, RuntimeDiscardNotice, RuntimeDiscardedError, SubIdCollisionError, __resetPortRegistry, absurd, asReducer, defineMachine, definePort, historyTracker, noop, replay, run, schemaMigrate, tryInterpret, wrapDetached };
|
|
592
|
+
//# sourceMappingURL=chunk-D4NJBQAH.js.map
|
|
593
|
+
//# sourceMappingURL=chunk-D4NJBQAH.js.map
|