aifsmjs 0.5.5 → 0.5.8
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 +44 -513
- package/README_ZHTW.md +44 -505
- package/dist/chunk-2MME5V4F.cjs +384 -0
- package/dist/chunk-2MME5V4F.cjs.map +1 -0
- package/dist/chunk-3B2USJ3H.cjs +18 -0
- package/dist/chunk-3B2USJ3H.cjs.map +1 -0
- package/dist/chunk-A7U7QQL5.js +52 -0
- package/dist/chunk-A7U7QQL5.js.map +1 -0
- package/dist/chunk-CDK25FTD.cjs +59 -0
- package/dist/chunk-CDK25FTD.cjs.map +1 -0
- package/dist/chunk-FHTQ7LSQ.cjs +21 -0
- package/dist/chunk-FHTQ7LSQ.cjs.map +1 -0
- package/dist/chunk-I354FONA.cjs +153 -0
- package/dist/chunk-I354FONA.cjs.map +1 -0
- package/dist/chunk-JKZAOPQC.js +16 -0
- package/dist/chunk-JKZAOPQC.js.map +1 -0
- package/dist/chunk-NEJYZAKR.js +19 -0
- package/dist/chunk-NEJYZAKR.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +9 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-Q7SFCCGT.cjs +11 -0
- package/dist/chunk-Q7SFCCGT.cjs.map +1 -0
- package/dist/chunk-VZCSHTOI.js +374 -0
- package/dist/chunk-VZCSHTOI.js.map +1 -0
- package/dist/chunk-ZLQ7HZCE.js +142 -0
- package/dist/chunk-ZLQ7HZCE.js.map +1 -0
- package/dist/effects/index.cjs +8 -14
- package/dist/effects/index.cjs.map +1 -1
- package/dist/effects/index.js +5 -14
- package/dist/effects/index.js.map +1 -1
- package/dist/guards/index.cjs +9 -13
- package/dist/guards/index.cjs.map +1 -1
- package/dist/guards/index.js +8 -12
- package/dist/guards/index.js.map +1 -1
- package/dist/index.cjs +101 -591
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -571
- package/dist/index.js.map +1 -1
- package/dist/inspect/index.cjs +2 -0
- package/dist/inspect/index.cjs.map +1 -1
- package/dist/inspect/index.js +2 -0
- package/dist/inspect/index.js.map +1 -1
- package/dist/pbt/index.cjs +26 -525
- package/dist/pbt/index.cjs.map +1 -1
- package/dist/pbt/index.d.cts +7 -3
- package/dist/pbt/index.d.ts +7 -3
- package/dist/pbt/index.js +12 -511
- package/dist/pbt/index.js.map +1 -1
- package/dist/replay/index.cjs +9 -195
- package/dist/replay/index.cjs.map +1 -1
- package/dist/replay/index.js +5 -198
- package/dist/replay/index.js.map +1 -1
- package/dist/timer/index.cjs +30 -9
- package/dist/timer/index.cjs.map +1 -1
- package/dist/timer/index.js +30 -9
- package/dist/timer/index.js.map +1 -1
- package/llms-full.txt +107 -932
- package/llms.txt +8 -35
- package/package.json +5 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkI354FONA_cjs = require('./chunk-I354FONA.cjs');
|
|
4
|
+
|
|
5
|
+
// src/replay/index.ts
|
|
6
|
+
function replay(initial, events, def, impl) {
|
|
7
|
+
let snapshot = initial;
|
|
8
|
+
const effects = [];
|
|
9
|
+
for (const event of events) {
|
|
10
|
+
const r = chunkI354FONA_cjs.step(def, snapshot, event, impl);
|
|
11
|
+
snapshot = r.snapshot;
|
|
12
|
+
if (r.effects.length > 0) {
|
|
13
|
+
for (const eff of r.effects) effects.push(eff);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
exports.replay = replay;
|
|
20
|
+
//# sourceMappingURL=chunk-FHTQ7LSQ.cjs.map
|
|
21
|
+
//# sourceMappingURL=chunk-FHTQ7LSQ.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/replay/index.ts"],"names":["step"],"mappings":";;;;;AAiBO,SAAS,MAAA,CACd,OAAA,EACA,MAAA,EACA,GAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,IAAI,QAAA,GAAW,OAAA;AACf,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,CAAA,GAAIA,sBAAA,CAAK,GAAA,EAAK,QAAA,EAAU,OAAO,IAAI,CAAA;AACzC,IAAA,QAAA,GAAW,CAAA,CAAE,QAAA;AACb,IAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACxB,MAAA,KAAA,MAAW,GAAA,IAAO,CAAA,CAAE,OAAA,EAAS,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,QAAA,EAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,CAAA;AAC5E","file":"chunk-FHTQ7LSQ.cjs","sourcesContent":["import { step } from \"../fsm/lifecycle.js\";\nimport type { Effect, Implementations, MachineDef, Snapshot } from \"../fsm/types.js\";\n\nexport type ReplayResult<Ctx, States extends string> = Readonly<{\n snapshot: Snapshot<Ctx, States>;\n effects: readonly Effect[];\n}>;\n\n/**\n * Fold an event log into a final snapshot via `step()`. Effects are collected\n * but never dispatched — this is a pure function, suitable for PBT, time\n * travel, and incident reproduction.\n *\n * Equivalent to:\n * events.reduce((s, e) => step(def, s, e, impl).snapshot, initial)\n * but also accumulates the effects across all events.\n */\nexport function replay<Ctx, Evt extends { type: string }, States extends string>(\n initial: Snapshot<Ctx, States>,\n events: readonly Evt[],\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n): ReplayResult<Ctx, States> {\n let snapshot = initial;\n const effects: Effect[] = [];\n for (const event of events) {\n const r = step(def, snapshot, event, impl);\n snapshot = r.snapshot;\n if (r.effects.length > 0) {\n for (const eff of r.effects) effects.push(eff);\n }\n }\n return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });\n}\n"]}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunk3B2USJ3H_cjs = require('./chunk-3B2USJ3H.cjs');
|
|
4
|
+
var chunkCDK25FTD_cjs = require('./chunk-CDK25FTD.cjs');
|
|
5
|
+
|
|
6
|
+
// src/fsm/resolver.ts
|
|
7
|
+
function normalizeTransition(entry) {
|
|
8
|
+
return typeof entry === "string" ? { target: entry } : entry;
|
|
9
|
+
}
|
|
10
|
+
function normalizeTransitions(entry) {
|
|
11
|
+
if (entry === void 0) return [];
|
|
12
|
+
if (Array.isArray(entry)) {
|
|
13
|
+
return entry.some((t) => typeof t === "string") ? entry.map((t) => normalizeTransition(t)) : entry;
|
|
14
|
+
}
|
|
15
|
+
return [normalizeTransition(entry)];
|
|
16
|
+
}
|
|
17
|
+
function resolveTransitions(def, stateValue, eventType) {
|
|
18
|
+
const state = def.states[stateValue];
|
|
19
|
+
if (!state || !state.on) return [];
|
|
20
|
+
return normalizeTransitions(state.on[eventType]);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/fsm/snapshot.ts
|
|
24
|
+
var IS_DEV = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.NODE_ENV !== "production";
|
|
25
|
+
function isPlainObject(value) {
|
|
26
|
+
if (value === null || typeof value !== "object") return false;
|
|
27
|
+
const proto = Object.getPrototypeOf(value);
|
|
28
|
+
return proto === Object.prototype || proto === null;
|
|
29
|
+
}
|
|
30
|
+
function deepFreeze(value) {
|
|
31
|
+
if (value === null || typeof value !== "object") return value;
|
|
32
|
+
if (Object.isFrozen(value)) return value;
|
|
33
|
+
Object.freeze(value);
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
for (const item of value) deepFreeze(item);
|
|
36
|
+
} else if (isPlainObject(value)) {
|
|
37
|
+
for (const key of Object.keys(value)) {
|
|
38
|
+
deepFreeze(value[key]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function freezeSnapshot(snap) {
|
|
44
|
+
return IS_DEV ? deepFreeze(snap) : Object.freeze(snap);
|
|
45
|
+
}
|
|
46
|
+
function createSnapshot(args) {
|
|
47
|
+
return freezeSnapshot({
|
|
48
|
+
value: args.value,
|
|
49
|
+
context: args.context,
|
|
50
|
+
status: args.status ?? "active"
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/fsm/updater.ts
|
|
55
|
+
function isPlainRecord(value) {
|
|
56
|
+
if (value === null || typeof value !== "object") return false;
|
|
57
|
+
const proto = Object.getPrototypeOf(value);
|
|
58
|
+
return proto === Object.prototype || proto === null;
|
|
59
|
+
}
|
|
60
|
+
function assign(updater) {
|
|
61
|
+
return ({ context, event }) => updater({ context, event });
|
|
62
|
+
}
|
|
63
|
+
function mergeContext(current, patch) {
|
|
64
|
+
if (patch === void 0 || patch === null) return current;
|
|
65
|
+
if (isPlainRecord(current) && isPlainRecord(patch)) {
|
|
66
|
+
return { ...current, ...patch };
|
|
67
|
+
}
|
|
68
|
+
return patch;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/fsm/lifecycle.ts
|
|
72
|
+
var UnknownActionError = class extends Error {
|
|
73
|
+
actionName;
|
|
74
|
+
constructor(actionName) {
|
|
75
|
+
super(`aifsmjs: action "${actionName}" not found in implementations.actions`);
|
|
76
|
+
this.name = "UnknownActionError";
|
|
77
|
+
this.actionName = actionName;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
function resolveAction(ref, impl) {
|
|
81
|
+
if (typeof ref === "function") return ref;
|
|
82
|
+
const fn = impl.actions?.[ref];
|
|
83
|
+
if (!fn) throw new UnknownActionError(ref);
|
|
84
|
+
return fn;
|
|
85
|
+
}
|
|
86
|
+
function runActions(refs, ctx, event, impl, effectSink) {
|
|
87
|
+
if (!refs || refs.length === 0) return ctx;
|
|
88
|
+
const enqueue = chunk3B2USJ3H_cjs.createEnqueuer(effectSink);
|
|
89
|
+
let current = ctx;
|
|
90
|
+
for (const ref of refs) {
|
|
91
|
+
const fn = resolveAction(ref, impl);
|
|
92
|
+
const patch = fn({ context: current, event, enqueue });
|
|
93
|
+
current = mergeContext(current, patch);
|
|
94
|
+
}
|
|
95
|
+
return current;
|
|
96
|
+
}
|
|
97
|
+
function pickTransition(candidates, ctx, event, impl, value) {
|
|
98
|
+
for (const t of candidates) {
|
|
99
|
+
if (!t.guard) return t;
|
|
100
|
+
if (chunkCDK25FTD_cjs.evalGuard(t.guard, ctx, event, impl, value)) return t;
|
|
101
|
+
}
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
function step(def, snapshot, event, impl) {
|
|
105
|
+
if (snapshot.status === "final") {
|
|
106
|
+
return Object.freeze({ snapshot, effects: [], changed: false });
|
|
107
|
+
}
|
|
108
|
+
const state = def.states[snapshot.value];
|
|
109
|
+
if (!state) {
|
|
110
|
+
return Object.freeze({ snapshot, effects: [], changed: false });
|
|
111
|
+
}
|
|
112
|
+
const candidateList = normalizeTransitions(state.on?.[event.type]);
|
|
113
|
+
const chosen = pickTransition(candidateList, snapshot.context, event, impl, snapshot.value);
|
|
114
|
+
if (!chosen) {
|
|
115
|
+
return Object.freeze({ snapshot, effects: [], changed: false });
|
|
116
|
+
}
|
|
117
|
+
const isExternal = chosen.target !== void 0;
|
|
118
|
+
const nextStateValue = chosen.target ?? snapshot.value;
|
|
119
|
+
const nextState = def.states[nextStateValue];
|
|
120
|
+
const effectSink = [];
|
|
121
|
+
let ctx = snapshot.context;
|
|
122
|
+
if (isExternal) {
|
|
123
|
+
ctx = runActions(state.exit, ctx, event, impl, effectSink);
|
|
124
|
+
}
|
|
125
|
+
ctx = runActions(chosen.actions, ctx, event, impl, effectSink);
|
|
126
|
+
if (isExternal && nextState) {
|
|
127
|
+
ctx = runActions(nextState.entry, ctx, event, impl, effectSink);
|
|
128
|
+
}
|
|
129
|
+
const status = nextState?.final === true ? "final" : "active";
|
|
130
|
+
const nextSnapshot = freezeSnapshot({
|
|
131
|
+
value: nextStateValue,
|
|
132
|
+
context: ctx,
|
|
133
|
+
status
|
|
134
|
+
});
|
|
135
|
+
return Object.freeze({
|
|
136
|
+
snapshot: nextSnapshot,
|
|
137
|
+
effects: Object.freeze(effectSink.slice()),
|
|
138
|
+
changed: true
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
exports.UnknownActionError = UnknownActionError;
|
|
143
|
+
exports.assign = assign;
|
|
144
|
+
exports.createSnapshot = createSnapshot;
|
|
145
|
+
exports.deepFreeze = deepFreeze;
|
|
146
|
+
exports.freezeSnapshot = freezeSnapshot;
|
|
147
|
+
exports.mergeContext = mergeContext;
|
|
148
|
+
exports.normalizeTransition = normalizeTransition;
|
|
149
|
+
exports.normalizeTransitions = normalizeTransitions;
|
|
150
|
+
exports.resolveTransitions = resolveTransitions;
|
|
151
|
+
exports.step = step;
|
|
152
|
+
//# sourceMappingURL=chunk-I354FONA.cjs.map
|
|
153
|
+
//# sourceMappingURL=chunk-I354FONA.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fsm/resolver.ts","../src/fsm/snapshot.ts","../src/fsm/updater.ts","../src/fsm/lifecycle.ts"],"names":["createEnqueuer","evalGuard"],"mappings":"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","file":"chunk-I354FONA.cjs","sourcesContent":["import type { MachineDef, TransitionConfig, TransitionDef } from \"./types.js\";\n\n/**\n * Normalize a single transition config into its object form. The string\n * shorthand `\"targetState\"` (à la XState) becomes `{ target: \"targetState\" }`;\n * the object form is returned unchanged. Centralised here so every consumer\n * (`step`, `resolveTransitions`, `can`, validation) sees the same shape.\n *\n * @since 0.5.3\n */\nexport function normalizeTransition<Ctx, Evt, States extends string>(\n entry: TransitionConfig<Ctx, Evt, States>,\n): TransitionDef<Ctx, Evt, States> {\n return typeof entry === \"string\" ? ({ target: entry } as TransitionDef<Ctx, Evt, States>) : entry;\n}\n\n/**\n * Normalize the raw `state.on[eventType]` value (object, string shorthand, or\n * an array mixing both) into an ordered list of {@link TransitionDef} objects.\n * Declaration order is preserved.\n *\n * @since 0.5.3\n */\nexport function normalizeTransitions<Ctx, Evt, States extends string>(\n entry:\n | TransitionConfig<Ctx, Evt, States>\n | readonly TransitionConfig<Ctx, Evt, States>[]\n | undefined,\n): readonly TransitionDef<Ctx, Evt, States>[] {\n if (entry === undefined) return [];\n if (Array.isArray(entry)) {\n // Hot path (send/step/can run this per event): when no string shorthand is\n // present, return the original array instead of allocating a normalized copy.\n return entry.some((t) => typeof t === \"string\")\n ? entry.map((t) => normalizeTransition(t))\n : (entry as readonly TransitionDef<Ctx, Evt, States>[]);\n }\n return [normalizeTransition(entry as TransitionConfig<Ctx, Evt, States>)];\n}\n\n/**\n * Return all transition candidates for (state, eventType). Order is preserved\n * from the declaration so that guard fallthrough behaves predictably. String\n * shorthands are normalized to `{ target }` objects.\n *\n * If the event has no entry under the given state, an empty array is returned.\n */\nexport function resolveTransitions<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n stateValue: States,\n eventType: string,\n): readonly TransitionDef<Ctx, Evt, States>[] {\n const state = def.states[stateValue];\n if (!state || !state.on) return [];\n return normalizeTransitions(state.on[eventType]);\n}\n","import type { Snapshot } from \"./types.js\";\n\nconst IS_DEV =\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.NODE_ENV !== \"production\";\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nexport function deepFreeze<T>(value: T): T {\n if (value === null || typeof value !== \"object\") return value;\n if (Object.isFrozen(value)) return value;\n Object.freeze(value);\n if (Array.isArray(value)) {\n for (const item of value) deepFreeze(item);\n } else if (isPlainObject(value)) {\n for (const key of Object.keys(value)) {\n deepFreeze((value as Record<string, unknown>)[key]);\n }\n }\n return value;\n}\n\n/**\n * Wrap a freshly built snapshot. In dev mode the whole tree is deep-frozen so\n * accidental mutation throws immediately. In production only the top object is\n * frozen, keeping the cost negligible.\n */\nexport function freezeSnapshot<C, S extends string>(snap: Snapshot<C, S>): Snapshot<C, S> {\n // IS_DEV is always true in vitest; the production branch (`Object.freeze`)\n // is exercised only when NODE_ENV === \"production\" and is intentionally\n // left out of the coverage threshold.\n return IS_DEV ? deepFreeze(snap) : Object.freeze(snap);\n}\n\nexport function createSnapshot<C, S extends string>(args: {\n value: S;\n context: C;\n status?: \"active\" | \"final\";\n}): Snapshot<C, S> {\n return freezeSnapshot({\n value: args.value,\n context: args.context,\n status: args.status ?? \"active\",\n });\n}\n","import type { Action } from \"./types.js\";\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\n/**\n * Build an Action that returns a Partial<Ctx> from a pure updater.\n * The partial is merged into the current context by `step()`.\n */\nexport function assign<Ctx, Evt>(\n updater: (args: { context: Ctx; event: Evt }) => Partial<Ctx>,\n): Action<Ctx, Evt> {\n return ({ context, event }) => updater({ context, event });\n}\n\n/**\n * Merge a partial context update into the current context. Plain-object\n * contexts get a shallow merge; non-object contexts get replaced wholesale.\n *\n * The function never mutates either argument.\n */\nexport function mergeContext<Ctx>(current: Ctx, patch: Partial<Ctx> | void): Ctx {\n if (patch === undefined || patch === null) return current;\n if (isPlainRecord(current) && isPlainRecord(patch)) {\n return { ...current, ...patch } as Ctx;\n }\n return patch as Ctx;\n}\n","import { createEnqueuer } from \"../effects/enqueuer.js\";\nimport { evalGuard } from \"./evaluator.js\";\nimport { normalizeTransitions } from \"./resolver.js\";\nimport { freezeSnapshot } from \"./snapshot.js\";\nimport type {\n Action,\n ActionRef,\n Effect,\n Implementations,\n MachineDef,\n Snapshot,\n StepResult,\n TransitionDef,\n} from \"./types.js\";\nimport { mergeContext } from \"./updater.js\";\n\nexport class UnknownActionError extends Error {\n readonly actionName: string;\n constructor(actionName: string) {\n super(`aifsmjs: action \"${actionName}\" not found in implementations.actions`);\n this.name = \"UnknownActionError\";\n this.actionName = actionName;\n }\n}\n\nfunction resolveAction<Ctx, Evt>(\n ref: ActionRef<Ctx, Evt>,\n impl: Implementations<Ctx, Evt>,\n): Action<Ctx, Evt> {\n if (typeof ref === \"function\") return ref;\n const fn = impl.actions?.[ref];\n if (!fn) throw new UnknownActionError(ref);\n return fn;\n}\n\nfunction runActions<Ctx, Evt>(\n refs: readonly ActionRef<Ctx, Evt>[] | undefined,\n ctx: Ctx,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n effectSink: Effect[],\n): Ctx {\n if (!refs || refs.length === 0) return ctx;\n const enqueue = createEnqueuer(effectSink as { type: string; payload?: unknown }[]);\n let current = ctx;\n for (const ref of refs) {\n const fn = resolveAction(ref, impl);\n const patch = fn({ context: current, event, enqueue });\n current = mergeContext(current, patch);\n }\n return current;\n}\n\nfunction pickTransition<Ctx, Evt, States extends string>(\n candidates: readonly TransitionDef<Ctx, Evt, States>[],\n ctx: Ctx,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n value: States,\n): TransitionDef<Ctx, Evt, States> | undefined {\n for (const t of candidates) {\n if (!t.guard) return t;\n if (evalGuard(t.guard, ctx, event, impl, value)) return t;\n }\n return undefined;\n}\n\n/**\n * Compute the next snapshot and collected effects from a single event.\n *\n * Order is fixed and uninterruptible:\n * 1. resolve candidate transitions for (state, event.type)\n * 2. evaluate guards in declaration order; pick the first passing one\n * 3. if external (target defined), run exit actions of the old state\n * 4. run transition.actions in declaration order\n * 5. if external, run entry actions of the new state\n * 6. return { snapshot, effects, changed }\n *\n * The function is pure: it never dispatches effects and never mutates inputs.\n */\nexport function step<Ctx, Evt extends { type: string }, States extends string>(\n def: MachineDef<Ctx, Evt, States>,\n snapshot: Snapshot<Ctx, States>,\n event: Evt,\n impl: Implementations<Ctx, Evt>,\n): StepResult<Ctx, States> {\n // Final state is inert: it never reacts to events.\n if (snapshot.status === \"final\") {\n return Object.freeze({ snapshot, effects: [] as readonly Effect[], changed: false });\n }\n\n const state = def.states[snapshot.value];\n /* v8 ignore next 3 — defensive: snapshot.value is always validated against def.states by defineMachine + initialSnapshot. */\n if (!state) {\n return Object.freeze({ snapshot, effects: [] as readonly Effect[], changed: false });\n }\n\n const candidateList = normalizeTransitions(state.on?.[event.type]);\n\n const chosen = pickTransition(candidateList, snapshot.context, event, impl, snapshot.value);\n if (!chosen) {\n return Object.freeze({ snapshot, effects: [] as readonly Effect[], changed: false });\n }\n\n const isExternal = chosen.target !== undefined;\n const nextStateValue = (chosen.target ?? snapshot.value) as States;\n const nextState = def.states[nextStateValue];\n\n const effectSink: Effect[] = [];\n let ctx = snapshot.context;\n\n if (isExternal) {\n ctx = runActions(state.exit, ctx, event, impl, effectSink);\n }\n ctx = runActions(chosen.actions, ctx, event, impl, effectSink);\n if (isExternal && nextState) {\n ctx = runActions(nextState.entry, ctx, event, impl, effectSink);\n }\n\n const status: \"active\" | \"final\" = nextState?.final === true ? \"final\" : \"active\";\n const nextSnapshot = freezeSnapshot({\n value: nextStateValue,\n context: ctx,\n status,\n });\n\n return Object.freeze({\n snapshot: nextSnapshot,\n effects: Object.freeze(effectSink.slice()) as readonly Effect[],\n changed: true,\n });\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// src/effects/enqueuer.ts
|
|
2
|
+
function createEnqueuer(sink) {
|
|
3
|
+
return Object.freeze({
|
|
4
|
+
effect(type, payload) {
|
|
5
|
+
if (payload === void 0) {
|
|
6
|
+
sink.push(Object.freeze({ type }));
|
|
7
|
+
} else {
|
|
8
|
+
sink.push(Object.freeze({ type, payload }));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { createEnqueuer };
|
|
15
|
+
//# sourceMappingURL=chunk-JKZAOPQC.js.map
|
|
16
|
+
//# sourceMappingURL=chunk-JKZAOPQC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/effects/enqueuer.ts"],"names":[],"mappings":";AAUO,SAAS,eAAe,IAAA,EAAuD;AACpF,EAAA,OAAO,OAAO,MAAA,CAAO;AAAA,IACnB,MAAA,CAAO,MAAc,OAAA,EAAmB;AACtC,MAAA,IAAI,YAAY,MAAA,EAAW;AACzB,QAAA,IAAA,CAAK,KAAK,MAAA,CAAO,MAAA,CAAO,EAAE,IAAA,EAAM,CAAC,CAAA;AAAA,MACnC,CAAA,MAAO;AACL,QAAA,IAAA,CAAK,KAAK,MAAA,CAAO,MAAA,CAAO,EAAE,IAAA,EAAM,OAAA,EAAS,CAAC,CAAA;AAAA,MAC5C;AAAA,IACF;AAAA,GACD,CAAA;AACH","file":"chunk-JKZAOPQC.js","sourcesContent":["import type { Enqueuer } from \"../fsm/types.js\";\n\n/**\n * Build a closure-based Enqueuer that pushes effects into the supplied sink.\n * Each `step()` invocation creates one such enqueuer and discards it\n * afterwards; the sink is the effects array later returned to the caller.\n *\n * Lives in `effects/` because the Enqueuer concept is the effects-domain API\n * — `step()` imports it from here.\n */\nexport function createEnqueuer(sink: { type: string; payload?: unknown }[]): Enqueuer {\n return Object.freeze({\n effect(type: string, payload?: unknown) {\n if (payload === undefined) {\n sink.push(Object.freeze({ type }));\n } else {\n sink.push(Object.freeze({ type, payload }));\n }\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { step } from './chunk-ZLQ7HZCE.js';
|
|
2
|
+
|
|
3
|
+
// src/replay/index.ts
|
|
4
|
+
function replay(initial, events, def, impl) {
|
|
5
|
+
let snapshot = initial;
|
|
6
|
+
const effects = [];
|
|
7
|
+
for (const event of events) {
|
|
8
|
+
const r = step(def, snapshot, event, impl);
|
|
9
|
+
snapshot = r.snapshot;
|
|
10
|
+
if (r.effects.length > 0) {
|
|
11
|
+
for (const eff of r.effects) effects.push(eff);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export { replay };
|
|
18
|
+
//# sourceMappingURL=chunk-NEJYZAKR.js.map
|
|
19
|
+
//# sourceMappingURL=chunk-NEJYZAKR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/replay/index.ts"],"names":[],"mappings":";;;AAiBO,SAAS,MAAA,CACd,OAAA,EACA,MAAA,EACA,GAAA,EACA,IAAA,EAC2B;AAC3B,EAAA,IAAI,QAAA,GAAW,OAAA;AACf,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,EAAK,QAAA,EAAU,OAAO,IAAI,CAAA;AACzC,IAAA,QAAA,GAAW,CAAA,CAAE,QAAA;AACb,IAAA,IAAI,CAAA,CAAE,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACxB,MAAA,KAAA,MAAW,GAAA,IAAO,CAAA,CAAE,OAAA,EAAS,OAAA,CAAQ,KAAK,GAAG,CAAA;AAAA,IAC/C;AAAA,EACF;AACA,EAAA,OAAO,MAAA,CAAO,MAAA,CAAO,EAAE,QAAA,EAAU,OAAA,EAAS,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAA,EAAG,CAAA;AAC5E","file":"chunk-NEJYZAKR.js","sourcesContent":["import { step } from \"../fsm/lifecycle.js\";\nimport type { Effect, Implementations, MachineDef, Snapshot } from \"../fsm/types.js\";\n\nexport type ReplayResult<Ctx, States extends string> = Readonly<{\n snapshot: Snapshot<Ctx, States>;\n effects: readonly Effect[];\n}>;\n\n/**\n * Fold an event log into a final snapshot via `step()`. Effects are collected\n * but never dispatched — this is a pure function, suitable for PBT, time\n * travel, and incident reproduction.\n *\n * Equivalent to:\n * events.reduce((s, e) => step(def, s, e, impl).snapshot, initial)\n * but also accumulates the effects across all events.\n */\nexport function replay<Ctx, Evt extends { type: string }, States extends string>(\n initial: Snapshot<Ctx, States>,\n events: readonly Evt[],\n def: MachineDef<Ctx, Evt, States>,\n impl: Implementations<Ctx, Evt>,\n): ReplayResult<Ctx, States> {\n let snapshot = initial;\n const effects: Effect[] = [];\n for (const event of events) {\n const r = step(def, snapshot, event, impl);\n snapshot = r.snapshot;\n if (r.effects.length > 0) {\n for (const eff of r.effects) effects.push(eff);\n }\n }\n return Object.freeze({ snapshot, effects: Object.freeze(effects.slice()) });\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export { __export };
|
|
8
|
+
//# sourceMappingURL=chunk-PZ5AY32C.js.map
|
|
9
|
+
//# sourceMappingURL=chunk-PZ5AY32C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-PZ5AY32C.js"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __export = (target, all) => {
|
|
5
|
+
for (var name in all)
|
|
6
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
exports.__export = __export;
|
|
10
|
+
//# sourceMappingURL=chunk-Q7SFCCGT.cjs.map
|
|
11
|
+
//# sourceMappingURL=chunk-Q7SFCCGT.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chunk-Q7SFCCGT.cjs"}
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import { freezeSnapshot, step, normalizeTransitions, deepFreeze } from './chunk-ZLQ7HZCE.js';
|
|
2
|
+
import { evalGuard, isAsyncGuardFn, isThenable } from './chunk-A7U7QQL5.js';
|
|
3
|
+
|
|
4
|
+
// src/fsm/types.ts
|
|
5
|
+
var RESET_EVENT_TYPE = "@@aifsmjs/RESET";
|
|
6
|
+
|
|
7
|
+
// src/fsm/definition.ts
|
|
8
|
+
var InvalidDefinitionError = class extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(`aifsmjs: ${message}`);
|
|
11
|
+
this.name = "InvalidDefinitionError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function validateDefinition(def) {
|
|
15
|
+
if (!def.id || typeof def.id !== "string") {
|
|
16
|
+
throw new InvalidDefinitionError("definition must have a non-empty string `id`");
|
|
17
|
+
}
|
|
18
|
+
if (!def.states || typeof def.states !== "object") {
|
|
19
|
+
throw new InvalidDefinitionError("definition must have a `states` object");
|
|
20
|
+
}
|
|
21
|
+
const stateKeys = Object.keys(def.states);
|
|
22
|
+
if (stateKeys.length === 0) {
|
|
23
|
+
throw new InvalidDefinitionError("`states` must declare at least one state");
|
|
24
|
+
}
|
|
25
|
+
if (!def.initial || !stateKeys.includes(def.initial)) {
|
|
26
|
+
throw new InvalidDefinitionError(
|
|
27
|
+
`\`initial\` "${String(def.initial)}" is not declared in states (${stateKeys.join(", ")})`
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
for (const [stateName, stateDef] of Object.entries(def.states)) {
|
|
31
|
+
if (stateDef.sub !== void 0) {
|
|
32
|
+
const sub = stateDef.sub;
|
|
33
|
+
const subStates = sub.states;
|
|
34
|
+
const subInitial = sub.initial;
|
|
35
|
+
if (typeof sub !== "object" || sub === null || typeof subStates !== "object" || subStates === null || typeof subInitial !== "string" || // initial must name one of the sub's own states — otherwise the child
|
|
36
|
+
// boots pointing at a non-existent state and no-ops forever (FSM-S-02).
|
|
37
|
+
!Object.hasOwn(subStates, subInitial)) {
|
|
38
|
+
throw new InvalidDefinitionError(
|
|
39
|
+
`state "${stateName}".sub is not a valid sub-machine definition (missing states or initial)`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (!stateDef.on) continue;
|
|
44
|
+
for (const [evtType, entry] of Object.entries(stateDef.on)) {
|
|
45
|
+
const transitions = normalizeTransitions(entry);
|
|
46
|
+
for (const t of transitions) {
|
|
47
|
+
if (t.target !== void 0 && !stateKeys.includes(t.target)) {
|
|
48
|
+
throw new InvalidDefinitionError(
|
|
49
|
+
`transition ${stateName} -[${evtType}]-> "${String(t.target)}" targets an unknown state`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (t.guard !== void 0 && isAsyncGuardFn(t.guard)) {
|
|
53
|
+
throw new InvalidDefinitionError(
|
|
54
|
+
`transition ${stateName} -[${evtType}]-> uses an async guard. Guards must be sync; move I/O into an effect.`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function defineMachine(def) {
|
|
62
|
+
const normalized = !("context" in def) ? { ...def, context: {} } : def;
|
|
63
|
+
validateDefinition(normalized);
|
|
64
|
+
return normalized;
|
|
65
|
+
}
|
|
66
|
+
function setup() {
|
|
67
|
+
return {
|
|
68
|
+
defineMachine: (def) => {
|
|
69
|
+
const cast = !("context" in def) ? { ...def, context: {} } : def;
|
|
70
|
+
validateDefinition(cast);
|
|
71
|
+
return cast;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function initialSnapshot(def) {
|
|
76
|
+
const isFinal = def.states[def.initial]?.final === true;
|
|
77
|
+
return freezeSnapshot({
|
|
78
|
+
value: def.initial,
|
|
79
|
+
context: def.context,
|
|
80
|
+
status: isFinal ? "final" : "active"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function createMachine(def, impl, opts) {
|
|
84
|
+
return createRuntime(defineMachine(def), impl, opts ?? {});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/fsm/runtime.ts
|
|
88
|
+
var RuntimeDisposedError = class extends Error {
|
|
89
|
+
constructor() {
|
|
90
|
+
super("aifsmjs: runtime has been disposed; send()/reset() are not allowed");
|
|
91
|
+
this.name = "RuntimeDisposedError";
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
var SubMachineError = class extends Error {
|
|
95
|
+
parentState;
|
|
96
|
+
phase;
|
|
97
|
+
cause;
|
|
98
|
+
constructor(parentState, phase, cause) {
|
|
99
|
+
super(`aifsmjs: sub-machine ${phase} failed at parent state "${parentState}"`, { cause });
|
|
100
|
+
this.name = "SubMachineError";
|
|
101
|
+
this.parentState = parentState;
|
|
102
|
+
this.phase = phase;
|
|
103
|
+
this.cause = cause;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var RESET_EVENT = Object.freeze({ type: RESET_EVENT_TYPE });
|
|
107
|
+
function composeMiddleware(middleware) {
|
|
108
|
+
return (ctx, finalNext) => {
|
|
109
|
+
let index = -1;
|
|
110
|
+
const dispatch = (i) => {
|
|
111
|
+
if (i <= index) throw new Error("aifsmjs: next() called multiple times in middleware");
|
|
112
|
+
index = i;
|
|
113
|
+
const fn = middleware[i];
|
|
114
|
+
if (!fn) {
|
|
115
|
+
finalNext();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
fn(ctx, () => dispatch(i + 1));
|
|
119
|
+
};
|
|
120
|
+
dispatch(0);
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
function createRuntime(def, impl, opts = {}) {
|
|
124
|
+
let snapshot = initialSnapshot(def);
|
|
125
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
126
|
+
const middlewareChain = opts.middleware && opts.middleware.length > 0 ? composeMiddleware(opts.middleware) : void 0;
|
|
127
|
+
const shouldDispatch = opts.dispatchEffects !== false;
|
|
128
|
+
const controller = new AbortController();
|
|
129
|
+
let disposed = false;
|
|
130
|
+
let childRuntime;
|
|
131
|
+
let childAbortCleanup;
|
|
132
|
+
const eventListeners = {
|
|
133
|
+
transition: /* @__PURE__ */ new Set(),
|
|
134
|
+
error: /* @__PURE__ */ new Set(),
|
|
135
|
+
dispose: /* @__PURE__ */ new Set()
|
|
136
|
+
};
|
|
137
|
+
const externalAbortCleanups = /* @__PURE__ */ new Set();
|
|
138
|
+
function emit(type, payload) {
|
|
139
|
+
for (const fn of Array.from(eventListeners[type])) fn(payload);
|
|
140
|
+
}
|
|
141
|
+
function notify(committed) {
|
|
142
|
+
const captured = committed ?? snapshot;
|
|
143
|
+
for (const l of Array.from(listeners)) l(captured);
|
|
144
|
+
}
|
|
145
|
+
function runMiddleware(prev, event, effects, changed) {
|
|
146
|
+
if (!middlewareChain) return;
|
|
147
|
+
middlewareChain(deepFreeze({ prev, next: snapshot, event, effects, changed }), () => {
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function dispatchEffects(effects, context, event) {
|
|
151
|
+
if (!impl.effects || effects.length === 0) return;
|
|
152
|
+
for (const eff of effects) {
|
|
153
|
+
const handler = impl.effects[eff.type];
|
|
154
|
+
if (!handler) continue;
|
|
155
|
+
const r = handler(eff, { context, event, signal: controller.signal });
|
|
156
|
+
if (isThenable(r)) {
|
|
157
|
+
Promise.resolve(r).catch((err) => {
|
|
158
|
+
emit("error", { error: err, event });
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function wireChildAbort(child) {
|
|
164
|
+
if (controller.signal.aborted) {
|
|
165
|
+
try {
|
|
166
|
+
child.dispose();
|
|
167
|
+
} catch {
|
|
168
|
+
}
|
|
169
|
+
return () => {
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const onAbort = () => {
|
|
173
|
+
try {
|
|
174
|
+
child.dispose();
|
|
175
|
+
} catch {
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
controller.signal.addEventListener("abort", onAbort, { once: true });
|
|
179
|
+
return () => controller.signal.removeEventListener("abort", onAbort);
|
|
180
|
+
}
|
|
181
|
+
function initChildFor(stateValue) {
|
|
182
|
+
const stateDef = def.states[stateValue];
|
|
183
|
+
const sub = stateDef?.sub;
|
|
184
|
+
if (sub === void 0) return;
|
|
185
|
+
let newChild;
|
|
186
|
+
try {
|
|
187
|
+
newChild = createRuntime(sub, stateDef.subImpl ?? {});
|
|
188
|
+
} catch (cause) {
|
|
189
|
+
throw new SubMachineError(stateValue, "init", cause);
|
|
190
|
+
}
|
|
191
|
+
childRuntime = newChild;
|
|
192
|
+
childAbortCleanup = wireChildAbort(newChild);
|
|
193
|
+
}
|
|
194
|
+
function findChosenIsExternal(value, event, context) {
|
|
195
|
+
const state = def.states[value];
|
|
196
|
+
if (!state?.on) return false;
|
|
197
|
+
const list = normalizeTransitions(state.on[event.type]);
|
|
198
|
+
if (list.length === 0) return false;
|
|
199
|
+
for (const t of list) {
|
|
200
|
+
if (!t.guard || evalGuard(t.guard, context, event, impl, value)) {
|
|
201
|
+
return t.target !== void 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
function applySubLifecycle(prevValue, nextValue) {
|
|
207
|
+
const prevStateDef = def.states[prevValue];
|
|
208
|
+
const nextStateDef = def.states[nextValue];
|
|
209
|
+
if (prevStateDef?.sub !== void 0 && childRuntime !== void 0) {
|
|
210
|
+
const child = childRuntime;
|
|
211
|
+
childRuntime = void 0;
|
|
212
|
+
childAbortCleanup?.();
|
|
213
|
+
childAbortCleanup = void 0;
|
|
214
|
+
try {
|
|
215
|
+
child.dispose();
|
|
216
|
+
} catch (cause) {
|
|
217
|
+
throw new SubMachineError(prevValue, "dispose", cause);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (nextStateDef?.sub !== void 0) {
|
|
221
|
+
initChildFor(nextValue);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function send(event) {
|
|
225
|
+
if (disposed) throw new RuntimeDisposedError();
|
|
226
|
+
const prev = snapshot;
|
|
227
|
+
const result = step(def, prev, event, impl);
|
|
228
|
+
const isExternal = result.changed && (prev.value !== result.snapshot.value || findChosenIsExternal(prev.value, event, prev.context));
|
|
229
|
+
if (result.changed && isExternal) applySubLifecycle(prev.value, result.snapshot.value);
|
|
230
|
+
snapshot = result.snapshot;
|
|
231
|
+
const committed = result.snapshot;
|
|
232
|
+
runMiddleware(prev, event, result.effects, result.changed);
|
|
233
|
+
if (shouldDispatch) dispatchEffects(result.effects, committed.context, event);
|
|
234
|
+
if (result.changed) {
|
|
235
|
+
notify(committed);
|
|
236
|
+
emit("transition", {
|
|
237
|
+
prev,
|
|
238
|
+
next: committed,
|
|
239
|
+
event,
|
|
240
|
+
effects: result.effects,
|
|
241
|
+
changed: true
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return snapshot;
|
|
245
|
+
}
|
|
246
|
+
function reset(event) {
|
|
247
|
+
if (disposed) throw new RuntimeDisposedError();
|
|
248
|
+
const prev = snapshot;
|
|
249
|
+
const nextSnap = initialSnapshot(def);
|
|
250
|
+
const changed = prev.value !== nextSnap.value;
|
|
251
|
+
if (childRuntime) {
|
|
252
|
+
const child = childRuntime;
|
|
253
|
+
childRuntime = void 0;
|
|
254
|
+
childAbortCleanup?.();
|
|
255
|
+
childAbortCleanup = void 0;
|
|
256
|
+
try {
|
|
257
|
+
child.dispose();
|
|
258
|
+
} catch (cause) {
|
|
259
|
+
throw new SubMachineError(prev.value, "dispose", cause);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const initStateDef = def.states[nextSnap.value];
|
|
263
|
+
if (initStateDef?.sub) {
|
|
264
|
+
initChildFor(nextSnap.value);
|
|
265
|
+
}
|
|
266
|
+
snapshot = nextSnap;
|
|
267
|
+
const committed = nextSnap;
|
|
268
|
+
const triggerEvent = event ?? RESET_EVENT;
|
|
269
|
+
runMiddleware(prev, triggerEvent, [], changed);
|
|
270
|
+
if (changed) {
|
|
271
|
+
notify(committed);
|
|
272
|
+
emit("transition", {
|
|
273
|
+
prev,
|
|
274
|
+
next: committed,
|
|
275
|
+
event: triggerEvent,
|
|
276
|
+
effects: [],
|
|
277
|
+
changed: true
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return snapshot;
|
|
281
|
+
}
|
|
282
|
+
function can(event) {
|
|
283
|
+
if (disposed || snapshot.status === "final") return false;
|
|
284
|
+
const state = def.states[snapshot.value];
|
|
285
|
+
if (!state) return false;
|
|
286
|
+
const list = normalizeTransitions(state.on?.[event.type]);
|
|
287
|
+
if (list.length === 0) return false;
|
|
288
|
+
for (const t of list) {
|
|
289
|
+
if (!t.guard) return true;
|
|
290
|
+
if (evalGuard(t.guard, snapshot.context, event, impl, snapshot.value)) return true;
|
|
291
|
+
}
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
function on(type, listener, options) {
|
|
295
|
+
if (disposed || options?.signal?.aborted) return () => {
|
|
296
|
+
};
|
|
297
|
+
const target = eventListeners[type];
|
|
298
|
+
let detachAbort;
|
|
299
|
+
const cleanup = () => {
|
|
300
|
+
target.delete(wrapped);
|
|
301
|
+
if (detachAbort) {
|
|
302
|
+
detachAbort();
|
|
303
|
+
externalAbortCleanups.delete(detachAbort);
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
let wrapped = listener;
|
|
307
|
+
if (options?.once) {
|
|
308
|
+
wrapped = (payload) => {
|
|
309
|
+
cleanup();
|
|
310
|
+
listener(payload);
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
target.add(wrapped);
|
|
314
|
+
const signal = options?.signal;
|
|
315
|
+
if (signal) {
|
|
316
|
+
const onAbort = () => cleanup();
|
|
317
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
318
|
+
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
319
|
+
externalAbortCleanups.add(detachAbort);
|
|
320
|
+
}
|
|
321
|
+
return cleanup;
|
|
322
|
+
}
|
|
323
|
+
function dispose() {
|
|
324
|
+
if (disposed) return;
|
|
325
|
+
disposed = true;
|
|
326
|
+
if (childRuntime) {
|
|
327
|
+
childAbortCleanup?.();
|
|
328
|
+
childAbortCleanup = void 0;
|
|
329
|
+
try {
|
|
330
|
+
childRuntime.dispose();
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
childRuntime = void 0;
|
|
334
|
+
}
|
|
335
|
+
controller.abort();
|
|
336
|
+
listeners.clear();
|
|
337
|
+
emit("dispose", void 0);
|
|
338
|
+
for (const set of Object.values(eventListeners)) set.clear();
|
|
339
|
+
for (const cleanup of externalAbortCleanups) cleanup();
|
|
340
|
+
externalAbortCleanups.clear();
|
|
341
|
+
}
|
|
342
|
+
const runtime = {
|
|
343
|
+
getSnapshot: () => snapshot,
|
|
344
|
+
snapshot: () => snapshot,
|
|
345
|
+
send,
|
|
346
|
+
can,
|
|
347
|
+
reset,
|
|
348
|
+
dispose,
|
|
349
|
+
on,
|
|
350
|
+
get disposed() {
|
|
351
|
+
return disposed;
|
|
352
|
+
},
|
|
353
|
+
get signal() {
|
|
354
|
+
return controller.signal;
|
|
355
|
+
},
|
|
356
|
+
subscribe(listener) {
|
|
357
|
+
if (disposed) return () => {
|
|
358
|
+
};
|
|
359
|
+
listeners.add(listener);
|
|
360
|
+
return () => listeners.delete(listener);
|
|
361
|
+
},
|
|
362
|
+
subRuntime: () => childRuntime,
|
|
363
|
+
onTransition: (handler, options) => on("transition", handler, options)
|
|
364
|
+
};
|
|
365
|
+
const bootStateDef = def.states[snapshot.value];
|
|
366
|
+
if (bootStateDef?.sub) {
|
|
367
|
+
initChildFor(snapshot.value);
|
|
368
|
+
}
|
|
369
|
+
return runtime;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export { InvalidDefinitionError, RESET_EVENT_TYPE, RuntimeDisposedError, SubMachineError, createMachine, createRuntime, defineMachine, initialSnapshot, setup };
|
|
373
|
+
//# sourceMappingURL=chunk-VZCSHTOI.js.map
|
|
374
|
+
//# sourceMappingURL=chunk-VZCSHTOI.js.map
|