@vielzeug/clockwork 1.0.2
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 +220 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_trace.cjs +2 -0
- package/dist/_trace.cjs.map +1 -0
- package/dist/_trace.d.ts +7 -0
- package/dist/_trace.d.ts.map +1 -0
- package/dist/_trace.js +17 -0
- package/dist/_trace.js.map +1 -0
- package/dist/clockwork.cjs +2 -0
- package/dist/clockwork.cjs.map +1 -0
- package/dist/clockwork.iife.js +2 -0
- package/dist/clockwork.iife.js.map +1 -0
- package/dist/clockwork.js +2 -0
- package/dist/clockwork.js.map +1 -0
- package/dist/definition.cjs +2 -0
- package/dist/definition.cjs.map +1 -0
- package/dist/definition.d.ts +16 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +49 -0
- package/dist/definition.js.map +1 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.ts +29 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/devtools.js +36 -0
- package/dist/devtools.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +57 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +64 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/interpret.cjs +2 -0
- package/dist/interpret.cjs.map +1 -0
- package/dist/interpret.d.ts +25 -0
- package/dist/interpret.d.ts.map +1 -0
- package/dist/interpret.js +298 -0
- package/dist/interpret.js.map +1 -0
- package/dist/types.d.ts +277 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# @vielzeug/clockwork
|
|
2
|
+
|
|
3
|
+
> Zero-dependency typed finite state machine for TypeScript
|
|
4
|
+
|
|
5
|
+
[](https://npmjs.com/package/@vielzeug/clockwork)
|
|
6
|
+
[](https://npmjs.com/package/@vielzeug/clockwork)
|
|
7
|
+
[](#)
|
|
8
|
+
|
|
9
|
+
A production-ready finite state machine with typed events, reactive state, async invokes, delayed transitions, hierarchical states, interceptors, persistence, and debugging—built on `@vielzeug/ripple` with zero external dependencies.
|
|
10
|
+
|
|
11
|
+
## Why Clockwork?
|
|
12
|
+
|
|
13
|
+
- **Type-safe** — Discriminated event unions with full TypeScript inference
|
|
14
|
+
- **Reactive** — State and context are `@vielzeug/ripple` signals
|
|
15
|
+
- **Async-first** — Native Promise support with onDone/onError handlers and automatic AbortSignal cancellation
|
|
16
|
+
- **Delayed transitions** — Timer-based `after` transitions with guards and actions
|
|
17
|
+
- **Hierarchical** — Compound states with automatic leaf resolution
|
|
18
|
+
- **Interceptors** — Pure event interceptors, run left-to-right; return `null` to block
|
|
19
|
+
- **Persistent** — Save/load snapshots via pluggable adapters
|
|
20
|
+
- **Debuggable** — Unified discriminated union `onDebug` callback and ring-buffer transition tracing
|
|
21
|
+
- **Validated** — Comprehensive definition validation and context checking
|
|
22
|
+
- **Zero overhead** — Debug features have zero cost when unused
|
|
23
|
+
- **Zero deps** — Depends only on `@vielzeug/ripple`
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { createMachine } from '@vielzeug/clockwork';
|
|
29
|
+
|
|
30
|
+
type Event = { type: 'INC' } | { type: 'RESET' };
|
|
31
|
+
|
|
32
|
+
const m = createMachine({
|
|
33
|
+
context: { count: 0 },
|
|
34
|
+
initial: 'idle',
|
|
35
|
+
states: {
|
|
36
|
+
idle: {
|
|
37
|
+
on: {
|
|
38
|
+
INC: {
|
|
39
|
+
actions: [({ context }) => { context.count += 1; }],
|
|
40
|
+
target: 'idle',
|
|
41
|
+
},
|
|
42
|
+
RESET: {
|
|
43
|
+
actions: [({ context }) => { context.count = 0; }],
|
|
44
|
+
target: 'idle',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}).start();
|
|
50
|
+
|
|
51
|
+
console.log(m.state.value); // 'idle'
|
|
52
|
+
console.log(m.context.value.count); // 0
|
|
53
|
+
|
|
54
|
+
console.log(m.send({ type: 'INC' }).status); // 'transitioned'
|
|
55
|
+
console.log(m.send({ type: 'INC' }).status); // 'transitioned'
|
|
56
|
+
|
|
57
|
+
console.log(m.context.value.count); // 2
|
|
58
|
+
|
|
59
|
+
m[Symbol.dispose](); // cleanup
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Core Concepts
|
|
63
|
+
|
|
64
|
+
### `createMachine()` — definition handle
|
|
65
|
+
|
|
66
|
+
`createMachine(config)` validates and returns a `MachineDefinition` handle. Call `.start(options?)` to create running instances. Calling `.start()` multiple times spawns independent instances:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createMachine } from '@vielzeug/clockwork';
|
|
70
|
+
|
|
71
|
+
const trafficDef = createMachine({ /* config */ });
|
|
72
|
+
|
|
73
|
+
const m1 = trafficDef.start();
|
|
74
|
+
const m2 = trafficDef.start();
|
|
75
|
+
|
|
76
|
+
m1.send({ type: 'NEXT' });
|
|
77
|
+
console.log(m2.state.value); // Unaffected by m1
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### send() and SendResult
|
|
81
|
+
|
|
82
|
+
`send()` returns a `SendResult` object. Check `.status`:
|
|
83
|
+
|
|
84
|
+
| `status` value | Meaning |
|
|
85
|
+
| --- | --- |
|
|
86
|
+
| `'transitioned'` | Transition occurred |
|
|
87
|
+
| `'queued'` | Called re-entrantly from inside an action |
|
|
88
|
+
| `'rejected'` | No match, guard failed, interceptor blocked, or machine is disposed |
|
|
89
|
+
|
|
90
|
+
### Transition Syntax
|
|
91
|
+
|
|
92
|
+
Single transitions use shorthand; multiple guarded alternatives use arrays:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
states: {
|
|
96
|
+
idle: {
|
|
97
|
+
on: {
|
|
98
|
+
GO: { target: 'active' },
|
|
99
|
+
LOAD: [
|
|
100
|
+
{ guard: ({ context }) => context.authorized, target: 'dashboard' },
|
|
101
|
+
{ target: 'unauthorized' },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Async Invokes
|
|
109
|
+
|
|
110
|
+
Run promises when entering states with automatic cancellation on exit. `onDone` and `onError` receive `(result, context)` — context is captured at invoke start:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
states: {
|
|
114
|
+
loading: {
|
|
115
|
+
invoke: [{
|
|
116
|
+
id: 'fetch-data', // optional — surfaced in debug events
|
|
117
|
+
src: async ({ signal }) => fetch('/api/data', { signal }).then(r => r.json()),
|
|
118
|
+
onDone: (result, _ctx) => ({ type: 'DATA_READY', data: result }),
|
|
119
|
+
onError: (error, _ctx) => ({ type: 'DATA_ERROR', error: String(error) }),
|
|
120
|
+
}],
|
|
121
|
+
on: {
|
|
122
|
+
DATA_READY: { target: 'idle' },
|
|
123
|
+
DATA_ERROR: { target: 'error' },
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Delayed Transitions
|
|
130
|
+
|
|
131
|
+
Timer-based transitions with optional guards:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
states: {
|
|
135
|
+
notification: {
|
|
136
|
+
after: [{ delay: 5000, target: 'dismissed' }],
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Interceptors
|
|
142
|
+
|
|
143
|
+
Pure functions that run before event processing. Return the event to allow it, `null` to block:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { createMachine, type InterceptorFn } from '@vielzeug/clockwork';
|
|
147
|
+
|
|
148
|
+
const authGuard: InterceptorFn<State, Ctx, Event> = (event, snap) => {
|
|
149
|
+
if (event.type === 'ADMIN_ACTION' && !snap.context.isAdmin) return null; // block
|
|
150
|
+
return event;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const m = createMachine(config).start({ interceptors: [authGuard] });
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Persistence
|
|
157
|
+
|
|
158
|
+
Save and restore machine state via pluggable adapters:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
const m = createMachine(config).start({
|
|
162
|
+
persistence: {
|
|
163
|
+
load: () => JSON.parse(localStorage.getItem('state') ?? 'null') ?? undefined,
|
|
164
|
+
save: (snapshot) => localStorage.setItem('state', JSON.stringify(snapshot)),
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Key Exports
|
|
170
|
+
|
|
171
|
+
| Export | Purpose |
|
|
172
|
+
| ------------------- | -------------------------------------------------------- |
|
|
173
|
+
| `createMachine()` | Validate config; returns a `MachineDefinition` handle |
|
|
174
|
+
| `.start(options?)` | Start a running instance from the definition handle |
|
|
175
|
+
| `.resolve(input)` | Pure transition resolver for unit-testing transitions |
|
|
176
|
+
| `ClockworkError` | Base class for all validation and runtime failures |
|
|
177
|
+
|
|
178
|
+
## Features
|
|
179
|
+
|
|
180
|
+
| Feature | Details |
|
|
181
|
+
| ------------------- | ------------------------------------------------------- |
|
|
182
|
+
| Typed events | Discriminated unions with TypeScript inference |
|
|
183
|
+
| Reactive state | Signals from `@vielzeug/ripple` |
|
|
184
|
+
| Async tasks | Native Promises with onDone/onError and AbortSignal |
|
|
185
|
+
| Delayed transitions | Timer-based `after` with guards and actions |
|
|
186
|
+
| Hierarchical states | Compound states with automatic leaf resolution |
|
|
187
|
+
| Interceptors | Pure event interceptors — return event or null to block |
|
|
188
|
+
| Persistence | Pluggable adapter for snapshot save/load |
|
|
189
|
+
| Context validation | Type guards at init and every transition |
|
|
190
|
+
| Entry/exit hooks | Lifecycle functions per state |
|
|
191
|
+
| Guards | Conditional transitions based on context and event |
|
|
192
|
+
| Tracing | Ring buffer of last N transitions |
|
|
193
|
+
| Debug events | Discriminated union debug callback |
|
|
194
|
+
| Event queue | FIFO processing with configurable loop guard |
|
|
195
|
+
| Context isolation | Cloned draft before commit; rolled back on failure |
|
|
196
|
+
| Pure resolver | `.resolve()` on `MachineDefinition` — test without side effects |
|
|
197
|
+
| Subscribe | Change-detection subscription without ripple dependency |
|
|
198
|
+
|
|
199
|
+
## Installation
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
pnpm add @vielzeug/clockwork
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`@vielzeug/ripple` is installed automatically as a direct dependency.
|
|
206
|
+
|
|
207
|
+
## Documentation
|
|
208
|
+
|
|
209
|
+
- **[Full Guide](https://vielzeug.dev/clockwork/)** — Overview, concepts, quick start
|
|
210
|
+
- **[Usage Guide](https://vielzeug.dev/clockwork/usage/)** — Common patterns and best practices
|
|
211
|
+
- **[API Reference](https://vielzeug.dev/clockwork/api/)** — All types and function signatures
|
|
212
|
+
- **[Examples](https://vielzeug.dev/clockwork/examples/)** — Real-world integration examples
|
|
213
|
+
|
|
214
|
+
## TypeScript
|
|
215
|
+
|
|
216
|
+
Requires TypeScript 5.0+ with `strict: true`.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT
|
package/dist/_dev.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAAgD,mBAGhE,SAAgB,EAAK,EAAmB,CAClC,GAAO,QAAQ,KAAK,yBAAyB,GAAK,CACxD"}
|
package/dist/_dev.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
|
package/dist/_dev.js
ADDED
package/dist/_dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":";AAAA,IAAM,IAAQ,CAAE,WAAgD;AAGhE,SAAgB,EAAK,GAAmB;CACtC,AAAI,KAAO,QAAQ,KAAK,yBAAyB,GAAK;AACxD"}
|
package/dist/_trace.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_trace.cjs","names":[],"sources":["../src/_trace.ts"],"sourcesContent":["import type { MachineEvent, TransitionTraceEntry } from './types.js';\n\nexport interface TraceBuffer<State extends string, Ev extends MachineEvent> {\n get(): readonly TransitionTraceEntry<State, Ev>[];\n push(entry: TransitionTraceEntry<State, Ev>): void;\n}\n\nexport function createTraceBuffer<State extends string, Ev extends MachineEvent>(\n limit: number,\n): TraceBuffer<State, Ev> | null {\n if (limit <= 0) return null;\n\n const buffer: TransitionTraceEntry<State, Ev>[] = [];\n let head = 0;\n let count = 0;\n\n return {\n get() {\n if (count === 0) return [];\n\n const entries = count < limit ? buffer.slice(0, count) : [...buffer.slice(head), ...buffer.slice(0, head)];\n\n return entries.map((e) => ({ ...e }));\n },\n push(entry) {\n if (count < limit) {\n buffer.push(entry);\n count++;\n } else {\n buffer[head] = entry;\n head = (head + 1) % limit;\n }\n },\n };\n}\n"],"mappings":"AAOA,SAAgB,EACd,EAC+B,CAC/B,GAAI,GAAS,EAAG,OAAO,KAEvB,IAAM,EAA4C,CAAC,EAC/C,EAAO,EACP,EAAQ,EAEZ,MAAO,CACL,KAAM,CAKJ,OAJI,IAAU,EAAU,CAAC,GAET,EAAQ,EAAQ,EAAO,MAAM,EAAG,CAAK,EAAI,CAAC,GAAG,EAAO,MAAM,CAAI,EAAG,GAAG,EAAO,MAAM,EAAG,CAAI,CAAC,EAAA,CAE1F,IAAK,IAAO,CAAE,GAAG,CAAE,EAAE,CACtC,EACA,KAAK,EAAO,CACN,EAAQ,GACV,EAAO,KAAK,CAAK,EACjB,MAEA,EAAO,GAAQ,EACf,GAAQ,EAAO,GAAK,EAExB,CACF,CACF"}
|
package/dist/_trace.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MachineEvent, TransitionTraceEntry } from './types.js';
|
|
2
|
+
export interface TraceBuffer<State extends string, Ev extends MachineEvent> {
|
|
3
|
+
get(): readonly TransitionTraceEntry<State, Ev>[];
|
|
4
|
+
push(entry: TransitionTraceEntry<State, Ev>): void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createTraceBuffer<State extends string, Ev extends MachineEvent>(limit: number): TraceBuffer<State, Ev> | null;
|
|
7
|
+
//# sourceMappingURL=_trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_trace.d.ts","sourceRoot":"","sources":["../src/_trace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAErE,MAAM,WAAW,WAAW,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY;IACxE,GAAG,IAAI,SAAS,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;CACpD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,SAAS,MAAM,EAAE,EAAE,SAAS,YAAY,EAC7E,KAAK,EAAE,MAAM,GACZ,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,IAAI,CAyB/B"}
|
package/dist/_trace.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/_trace.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
if (e <= 0) return null;
|
|
4
|
+
let t = [], n = 0, r = 0;
|
|
5
|
+
return {
|
|
6
|
+
get() {
|
|
7
|
+
return r === 0 ? [] : (r < e ? t.slice(0, r) : [...t.slice(n), ...t.slice(0, n)]).map((e) => ({ ...e }));
|
|
8
|
+
},
|
|
9
|
+
push(i) {
|
|
10
|
+
r < e ? (t.push(i), r++) : (t[n] = i, n = (n + 1) % e);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { e as createTraceBuffer };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=_trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_trace.js","names":[],"sources":["../src/_trace.ts"],"sourcesContent":["import type { MachineEvent, TransitionTraceEntry } from './types.js';\n\nexport interface TraceBuffer<State extends string, Ev extends MachineEvent> {\n get(): readonly TransitionTraceEntry<State, Ev>[];\n push(entry: TransitionTraceEntry<State, Ev>): void;\n}\n\nexport function createTraceBuffer<State extends string, Ev extends MachineEvent>(\n limit: number,\n): TraceBuffer<State, Ev> | null {\n if (limit <= 0) return null;\n\n const buffer: TransitionTraceEntry<State, Ev>[] = [];\n let head = 0;\n let count = 0;\n\n return {\n get() {\n if (count === 0) return [];\n\n const entries = count < limit ? buffer.slice(0, count) : [...buffer.slice(head), ...buffer.slice(0, head)];\n\n return entries.map((e) => ({ ...e }));\n },\n push(entry) {\n if (count < limit) {\n buffer.push(entry);\n count++;\n } else {\n buffer[head] = entry;\n head = (head + 1) % limit;\n }\n },\n };\n}\n"],"mappings":";AAOA,SAAgB,EACd,GAC+B;CAC/B,IAAI,KAAS,GAAG,OAAO;CAEvB,IAAM,IAA4C,CAAC,GAC/C,IAAO,GACP,IAAQ;CAEZ,OAAO;EACL,MAAM;GAKJ,OAJI,MAAU,IAAU,CAAC,KAET,IAAQ,IAAQ,EAAO,MAAM,GAAG,CAAK,IAAI,CAAC,GAAG,EAAO,MAAM,CAAI,GAAG,GAAG,EAAO,MAAM,GAAG,CAAI,CAAC,EAAA,CAE1F,KAAK,OAAO,EAAE,GAAG,EAAE,EAAE;EACtC;EACA,KAAK,GAAO;GACV,AAAI,IAAQ,KACV,EAAO,KAAK,CAAK,GACjB,QAEA,EAAO,KAAQ,GACf,KAAQ,IAAO,KAAK;EAExB;CACF;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@vielzeug/ripple");var t=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},n=class extends t{path;constructor(e,t,n){super(e,n),this.path=t}},r=class extends t{path;initial;constructor(e,t,n,r){super(e,r),this.path=t,this.initial=n}},i=class extends t{path;eventType;constructor(e,t,n,r){super(e,r),this.path=t,this.eventType=n}},a=class extends t{path;target;eventType;constructor(e,t,n,r,i){super(e,i),this.path=t,this.target=n,this.eventType=r}},o=class extends t{path;delay;constructor(e,t,n,r){super(e,r),this.path=t,this.delay=n}},s=class extends t{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},c=class extends t{state;constructor(e,t,n){super(e,n),this.state=t}},l=class extends t{phase;reason;constructor(e,t,n,r){super(e,r),this.phase=t,this.reason=n}},u=class extends t{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},d=!globalThis.__CLOCKWORK_PROD__;function f(e){d&&console.warn(`[@vielzeug/clockwork] ${e}`)}function p(e){if(e<=0)return null;let t=[],n=0,r=0;return{get(){return r===0?[]:(r<e?t.slice(0,r):[...t.slice(n),...t.slice(0,n)]).map(e=>({...e}))},push(i){r<e?(t.push(i),r++):(t[n]=i,n=(n+1)%e)}}}var m=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:void 0,h=(e,t)=>{let n=t.split(`.`),r=m(e,n[0]);if(!r)return t;for(let e=1;e<n.length;e++)if(r=m(r.states,n[e]),!r)return t;let i=t;for(;r?.states&&r.initial;)i=`${i}.${r.initial}`,r=m(r.states,r.initial);return i},g=(e,t)=>{let n=t.split(`.`),r=m(e,n[0]);for(let e=1;e<n.length;e++){if(!r?.states)return;r=m(r.states,n[e])}return r},_=e=>{let t=e.split(`.`),n=[];for(let e=1;e<=t.length;e++)n.push(t.slice(0,e).join(`.`));return n},v=(e,t,s)=>{if(e.states&&!e.initial)throw new n(`compound state "${t}" must have an "initial" property`,t);if(e.initial&&e.states&&!Object.hasOwn(e.states,e.initial))throw new r(`compound state "${t}" initial "${e.initial}" not found in substates`,t,e.initial);for(let[n,r]of Object.entries(e.on??{})){let e=Array.isArray(r)?r:[r];if(e.length===0)throw new i(`state "${t}" event "${n}" must be a non-empty transition or transition array`,t,n);for(let r of e){let e=r.target.split(`.`)[0];if(!Object.hasOwn(s,e))throw new a(`state "${t}" event "${n}" targets unknown state "${r.target}"`,t,r.target,n);if(r.target.includes(`.`)&&!g(s,r.target))throw new a(`state "${t}" event "${n}" targets unknown nested state "${r.target}"`,t,r.target,n)}}if(e.invoke!==void 0&&e.invoke.length===0)throw new i(`state "${t}" invoke must be a non-empty array`,t);for(let n of e.after??[]){if(!Number.isFinite(n.delay)||n.delay<0)throw new o(`state "${t}" after delay must be a finite number >= 0, got ${n.delay}`,t,n.delay);let e=n.target.split(`.`)[0];if(!Object.hasOwn(s,e))throw new a(`state "${t}" after[${n.delay}ms] targets unknown state "${n.target}"`,t,n.target);if(n.target.includes(`.`)&&!g(s,n.target))throw new a(`state "${t}" after[${n.delay}ms] targets unknown nested state "${n.target}"`,t,n.target)}if(e.states)for(let[n,r]of Object.entries(e.states))v(r,`${t}.${n}`,s)},y=e=>{let{states:t}=e;if(!Object.hasOwn(t,e.initial))throw new r(`initial state "${e.initial}" not found in states`,``,e.initial);for(let[e,n]of Object.entries(t))v(n,e,t)},b={type:`$init`},x={type:`$hydrate`},S=(e,t,n)=>{let{context:r,event:i,state:a}=t;if(!i||typeof i.type!=`string`)return;let o=_(a);for(let t=o.length-1;t>=0;t--){let s=g(e.states,o[t]);if(!s?.on)continue;let c=i.type,l=Object.hasOwn(s.on,c)?s.on[c]:void 0;if(!l)continue;let u=Array.isArray(l)?l:[l];for(let e of u){let t=!e.guard||e.guard({context:r,event:i});if(n?.({context:r,event:i,from:a,passed:t,target:e.target}),t)return e}}},C=Object.freeze({status:`transitioned`}),w=Object.freeze({status:`queued`}),T=Object.freeze({status:`rejected`}),E=(t,n={})=>{let r=n.onDebug,i=n.traceLimit??(r?50:0);if(n.maxTransitionsPerFlush!==void 0&&n.maxTransitionsPerFlush<1)throw new s(`maxTransitionsPerFlush must be greater than 0`,n.maxTransitionsPerFlush);let a=n.maxTransitionsPerFlush??1e3,o=n.clone??structuredClone,d=t.states,m=n.interceptors??[],v=n.snapshot??n.persistence?.load();if(v){let e=v.state.split(`.`)[0];if(!(Object.hasOwn(t.states,e)&&(!v.state.includes(`.`)||g(t.states,v.state))))throw new c(`snapshot state "${v.state}" not found in states`,v.state)}let y=(e,n)=>{let r=t.validateContext;if(!r)return;let i=r(e);if(i!==!0)throw new l(`context failed validation during ${n}${i?`: ${i}`:``}`,n,i)},E=v?v.state:h(d,t.initial),D=o(v?v.context:`context`in t?t.context:{});v||y(D,`init`);let O=(0,e.signal)(E),k=(0,e.signal)(D),A=p(i),j=new AbortController,M=!1,N=0,P=new Set,F=e=>{for(let t of P)e&&!e.includes(t.path)||(t.controller.abort(),r?.({context:k.value,event:t.event,invokeId:t.id,state:t.state,type:`invoke-abort`}),P.delete(t))},I=new Set,L=e=>{for(let t of I)e&&!e.includes(t.path)||(clearTimeout(t.timer),I.delete(t))},R=()=>{n.persistence?.save({context:o(k.value),state:O.value})},z=new Set,B=()=>{if(z.size===0)return;let e=Object.freeze({context:k.value,state:O.value});for(let t of z)t(e)},V=[],H=!1,U=(e,t)=>{if(!e.includes(`.`)&&!t.includes(`.`)||e===t)return{entryPaths:[t],exitPaths:[e]};let n=_(e),r=_(t),i=0;for(;i<n.length&&i<r.length&&n[i]===r[i];)i++;return{entryPaths:r.slice(i),exitPaths:n.slice(i).reverse()}},W=(t,n,i,a)=>{let{entryPaths:s,exitPaths:c}=U(t,n),l=o(k.value);for(let e of c)g(d,e)?.exit?.({context:l,event:a});for(let e of i)e({context:l,event:a});for(let e of s)g(d,e)?.entry?.({context:l,event:a});Object.freeze(l),y(l,`transition`),(0,e.batch)(()=>{F(c),L(c),O.value=n,k.value=l}),r?.({event:a,from:t,to:n,type:`transition`}),A?.push({event:a,from:t,timestamp:Date.now(),to:n}),B(),R(),G(a,s),K(s)},G=(e,t)=>{for(let n of t){let t=g(d,n);if(t?.invoke?.length)for(let i of t.invoke){let t=new AbortController,a=i.id??String(++N),o=k.value,s={controller:t,event:e,id:a,path:n,state:O.value};P.add(s),r?.({context:o,event:e,invokeId:a,state:O.value,type:`invoke-start`}),i.src({context:o,entryEvent:e,signal:t.signal}).then(n=>{P.delete(s),!(M||t.signal.aborted||!i.onDone)&&(r?.({context:o,event:e,invokeId:a,result:n,state:O.value,type:`invoke-done`}),V.push({event:i.onDone(n,o),tag:`event`}),H||Y())}).catch(n=>{P.delete(s),!(M||t.signal.aborted||!i.onError)&&(r?.({context:o,error:n,event:e,invokeId:a,state:O.value,type:`invoke-error`}),V.push({event:i.onError(n,o),tag:`event`}),H||Y())})}}},K=e=>{for(let t of e){let e=g(d,t);if(e?.after?.length)for(let n of e.after){let e={path:t,timer:setTimeout(()=>{if(I.delete(e),M||!_(O.value).includes(t))return;let r=O.value,i={delay:n.delay,type:`$after`};if(n.guard&&!n.guard({context:k.value,event:i}))return;let a=h(d,n.target);V.push({actions:n.actions??[],afterEvent:i,from:r,tag:`after`,target:a}),Y()},n.delay)};I.add(e)}}},q=e=>{if(M)return!1;if(e.tag===`after`)return W(e.from,e.target,e.actions,e.afterEvent),!0;let n=O.value,i=S(t,{context:k.value,event:e.event,state:n},r?e=>r({...e,type:`guard`}):void 0);if(!i)return r?.({event:e.event,from:n,type:`transition-skipped`}),!1;let a=h(d,i.target),o=i.actions??[];return W(n,a,o,e.event),!0},J=()=>{let e=0;for(;V.length>0;){if(++e>a)throw new u(`transition queue exceeded maxTransitionsPerFlush`,a);q(V.shift())}},Y=()=>{if(!H){H=!0;try{J()}catch(e){throw V.length=0,e}finally{H=!1}}},X=e=>M?!1:!!S(t,{context:k.value,event:e,state:O.value}),Z=e=>{if(M)return f(`send() called on a disposed machine — event ignored`),T;let t=e;for(let e of m)if(t=e(t,{context:k.value,state:O.value}),t===null)return T;let n=t;if(H)return V.push({event:n,tag:`event`}),w;H=!0;try{let e=q({event:n,tag:`event`});return J(),e?C:T}catch(e){throw V.length=0,e}finally{H=!1}},ee=()=>Object.freeze({context:o(k.value),state:O.value}),te=()=>A?.get()??[],ne=(...e)=>{if(M)return!1;let t=O.value;return e.some(e=>t===e||t.startsWith(`${e}.`))},re=e=>(z.add(e),()=>z.delete(e)),Q=_(E);if(v)G(x,Q),K(Q);else{if(Q.some(e=>g(d,e)?.entry)){let e=o(k.value);for(let t of Q)g(d,t)?.entry?.({context:e,event:b});y(e,`init`),k.value=e}G(b,Q),K(Q),n.persistence&&R()}let $=()=>{M||(M=!0,j.abort(),F(),L(),O.dispose(),k.dispose())};return{can:X,context:(0,e.readonly)(k),get disposalSignal(){return j.signal},dispose:$,get disposed(){return M},getSnapshot:ee,getTrace:te,matches:ne,send:Z,state:(0,e.readonly)(O),subscribe:re,[Symbol.dispose]:$}},D=e=>(y(e),{resolve(t,n){return S(e,t,n?.onGuard)},start(t){return E(e,t)}});exports.ClockworkError=t,exports.ClockworkInvalidAfterDelayError=o,exports.ClockworkInvalidInitialStateError=r,exports.ClockworkInvalidMaxTransitionsError=s,exports.ClockworkInvalidSnapshotStateError=c,exports.ClockworkInvalidTransitionArrayError=i,exports.ClockworkInvalidValidateContextError=l,exports.ClockworkMissingCompoundInitialError=n,exports.ClockworkTransitionLoopGuardError=u,exports.ClockworkUnknownTargetError=a,exports.createMachine=D;
|
|
2
|
+
//# sourceMappingURL=clockwork.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clockwork.cjs","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_trace.ts","../src/definition.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */\nexport class ClockworkError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ClockworkError {\n return err instanceof ClockworkError;\n }\n}\n\n/** Thrown when a compound state does not declare an `initial` substate. */\nexport class ClockworkMissingCompoundInitialError extends ClockworkError {\n readonly path: string;\n constructor(message: string, path: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n }\n}\n\n/** Thrown when a compound state's `initial` value does not match any substate. */\nexport class ClockworkInvalidInitialStateError extends ClockworkError {\n readonly path: string;\n readonly initial: string;\n constructor(message: string, path: string, initial: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.initial = initial;\n }\n}\n\n/** Thrown when a transition definition is empty or not a valid array. */\nexport class ClockworkInvalidTransitionArrayError extends ClockworkError {\n readonly path: string;\n readonly eventType?: string;\n constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when a transition or `after` definition targets an unknown state. */\nexport class ClockworkUnknownTargetError extends ClockworkError {\n readonly path: string;\n readonly target: string;\n readonly eventType?: string;\n constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.target = target;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */\nexport class ClockworkInvalidAfterDelayError extends ClockworkError {\n readonly path: string;\n readonly delay: number;\n constructor(message: string, path: string, delay: number, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.delay = delay;\n }\n}\n\n/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */\nexport class ClockworkInvalidMaxTransitionsError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n\n/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */\nexport class ClockworkInvalidSnapshotStateError extends ClockworkError {\n readonly state: string;\n constructor(message: string, state: string, opts?: ErrorOptions) {\n super(message, opts);\n this.state = state;\n }\n}\n\n/** Thrown when `validateContext` returns a failure reason during init or transition. */\nexport class ClockworkInvalidValidateContextError extends ClockworkError {\n readonly phase: 'init' | 'transition';\n readonly reason: string | true;\n constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions) {\n super(message, opts);\n this.phase = phase;\n this.reason = reason;\n }\n}\n\n/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */\nexport class ClockworkTransitionLoopGuardError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { MachineEvent, TransitionTraceEntry } from './types.js';\n\nexport interface TraceBuffer<State extends string, Ev extends MachineEvent> {\n get(): readonly TransitionTraceEntry<State, Ev>[];\n push(entry: TransitionTraceEntry<State, Ev>): void;\n}\n\nexport function createTraceBuffer<State extends string, Ev extends MachineEvent>(\n limit: number,\n): TraceBuffer<State, Ev> | null {\n if (limit <= 0) return null;\n\n const buffer: TransitionTraceEntry<State, Ev>[] = [];\n let head = 0;\n let count = 0;\n\n return {\n get() {\n if (count === 0) return [];\n\n const entries = count < limit ? buffer.slice(0, count) : [...buffer.slice(head), ...buffer.slice(0, head)];\n\n return entries.map((e) => ({ ...e }));\n },\n push(entry) {\n if (count < limit) {\n buffer.push(entry);\n count++;\n } else {\n buffer[head] = entry;\n head = (head + 1) % limit;\n }\n },\n };\n}\n","import type { MachineConfig, MachineEvent, StateNode, TransitionDef } from './types.js';\n\nimport {\n ClockworkInvalidAfterDelayError,\n ClockworkInvalidInitialStateError,\n ClockworkInvalidTransitionArrayError,\n ClockworkMissingCompoundInitialError,\n ClockworkUnknownTargetError,\n} from './errors.js';\n\n// ── Key safety ────────────────────────────────────────────────────────────────\n\n/**\n * Own-property-only lookup — state paths and event types ultimately come from strings\n * (persisted snapshots, event payloads) that may not be developer-authored. A plain\n * `obj[key]` or `key in obj` resolves inherited `Object.prototype` members (`__proto__`,\n * `constructor`, `toString`, …), which can turn an \"unknown state/event\" into a crash or\n * a silently-accepted bogus value instead of the intended \"not found\". Treat any such key\n * as absent instead.\n */\nconst getOwn = <T>(obj: Record<string, T> | undefined, key: string): T | undefined =>\n obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n\n// ── Hierarchy helpers (internal — not re-exported from index) ─────────────────\n\n/**\n * Resolves a target state to its deepest initial leaf.\n * For compound states (those with `states` + `initial`), recursively descends.\n */\nexport const resolveLeaf = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n target: string,\n): string => {\n const segments = target.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n if (!node) return target;\n\n for (let i = 1; i < segments.length; i++) {\n node = getOwn(node.states, segments[i]);\n\n if (!node) return target;\n }\n\n let path = target;\n\n while (node?.states && node.initial) {\n path = `${path}.${node.initial}`;\n node = getOwn(node.states, node.initial);\n }\n\n return path;\n};\n\n/**\n * Returns the node at a given dot-path.\n */\nexport const getNodeAtPath = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n path: string,\n): StateNode<string, Ctx, Ev> | undefined => {\n const segments = path.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n for (let i = 1; i < segments.length; i++) {\n if (!node?.states) return undefined;\n\n node = getOwn(node.states, segments[i]);\n }\n\n return node;\n};\n\n/**\n * Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']\n */\nexport const getAncestorPaths = (path: string): string[] => {\n const segments = path.split('.');\n const paths: string[] = [];\n\n for (let i = 1; i <= segments.length; i++) {\n paths.push(segments.slice(0, i).join('.'));\n }\n\n return paths;\n};\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nconst validateNode = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n node: StateNode<string, Ctx, Ev>,\n path: string,\n allTopLevel: Record<string, StateNode<State, Ctx, Ev>>,\n): void => {\n if (node.states && !node.initial) {\n throw new ClockworkMissingCompoundInitialError(`compound state \"${path}\" must have an \"initial\" property`, path);\n }\n\n if (node.initial && node.states && !Object.hasOwn(node.states, node.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `compound state \"${path}\" initial \"${node.initial}\" not found in substates`,\n path,\n node.initial,\n );\n }\n\n for (const [eventType, input] of Object.entries(node.on ?? {})) {\n const defs = Array.isArray(input) ? input : [input];\n\n if (defs.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(\n `state \"${path}\" event \"${eventType}\" must be a non-empty transition or transition array`,\n path,\n eventType,\n );\n }\n\n for (const tr of defs as Array<TransitionDef<State, Ctx, Ev>>) {\n const targetRoot = tr.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n\n if (tr.target.includes('.') && !getNodeAtPath(allTopLevel, tr.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown nested state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n }\n }\n\n // Validate empty invoke array (D1)\n if (node.invoke !== undefined && node.invoke.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(`state \"${path}\" invoke must be a non-empty array`, path);\n }\n\n // Validate after targets and delays\n for (const afterDef of node.after ?? []) {\n if (!Number.isFinite(afterDef.delay) || afterDef.delay < 0) {\n throw new ClockworkInvalidAfterDelayError(\n `state \"${path}\" after delay must be a finite number >= 0, got ${afterDef.delay}`,\n path,\n afterDef.delay,\n );\n }\n\n const targetRoot = afterDef.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n\n if (afterDef.target.includes('.') && !getNodeAtPath(allTopLevel, afterDef.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown nested state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n }\n\n if (node.states) {\n for (const [name, child] of Object.entries(node.states)) {\n validateNode(child, `${path}.${name}`, allTopLevel);\n }\n }\n};\n\nexport const validateDefinition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n): void => {\n const { states } = definition;\n\n if (!Object.hasOwn(states, definition.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `initial state \"${definition.initial}\" not found in states`,\n '',\n definition.initial,\n );\n }\n\n for (const [stateName, node] of Object.entries(states) as Array<[string, StateNode<State, Ctx, Ev>]>) {\n validateNode(node, stateName, states);\n }\n};\n","import { batch, readonly, signal } from '@vielzeug/ripple';\n\nimport type {\n DebugEvent,\n EventByType,\n EventType,\n InterpretOptions,\n LifecycleEvent,\n MachineConfig,\n MachineDefinition,\n MachineEvent,\n MachineInstance,\n MachineSnapshot,\n SendResult,\n StateNode,\n TransitionDef,\n TransitionTraceEntry,\n} from './types.js';\n\nimport { warn } from './_dev';\nimport { createTraceBuffer } from './_trace.js';\nimport { getAncestorPaths, getNodeAtPath, resolveLeaf, validateDefinition } from './definition.js';\nimport {\n ClockworkInvalidMaxTransitionsError,\n ClockworkInvalidSnapshotStateError,\n ClockworkInvalidValidateContextError,\n ClockworkTransitionLoopGuardError,\n} from './errors.js';\n\n// ── Internal constants ────────────────────────────────────────────────────────\n\nconst INIT_EVENT = { type: '$init' } as const;\nconst HYDRATE_EVENT = { type: '$hydrate' } as const;\n\n// ── Pure resolver ─────────────────────────────────────────────────────────────\n\n/**\n * Resolves which transition should be taken for a given state + event.\n * Pure function — no side effects; useful for testing transition logic independently.\n *\n * Optionally calls `onGuard` for each guard evaluation.\n */\nconst resolveTransition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n input: {\n context: Readonly<Ctx>;\n event: NoInfer<Ev>;\n state: State;\n },\n onGuard?: (info: { context: Readonly<Ctx>; event: Ev; from: State; passed: boolean; target: State }) => void,\n): TransitionDef<State, Ctx, Ev> | undefined => {\n const { context, event, state } = input;\n\n // Defensive: callers piping untyped external data through an `Ev`-typed cast (e.g. a\n // deserialized network message passed to `send()`) can violate the MachineEvent contract\n // at runtime. Treat a missing/non-string `type` as \"no matching transition\" rather than\n // crashing with a raw TypeError.\n if (!event || typeof (event as unknown as { type?: unknown }).type !== 'string') return undefined;\n\n const ancestors = getAncestorPaths(state);\n\n for (let i = ancestors.length - 1; i >= 0; i--) {\n const node = getNodeAtPath(definition.states, ancestors[i]) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.on) continue;\n\n // Own-property check — an event `type` of \"__proto__\"/\"constructor\"/etc. must resolve\n // to \"no matching transition\", not an inherited Object.prototype member.\n const eventType = event.type as EventType<Ev>;\n const raw = Object.hasOwn(node.on, eventType) ? node.on[eventType] : undefined;\n\n if (!raw) continue;\n\n const defs = Array.isArray(raw) ? raw : [raw];\n\n for (const def of defs) {\n const passed = !def.guard || def.guard({ context, event: event as EventByType<Ev, EventType<Ev>> });\n\n onGuard?.({ context, event, from: state, passed, target: def.target as State });\n\n if (passed) return def as TransitionDef<State, Ctx, Ev>;\n }\n }\n\n return undefined;\n};\n\n// ── SendResult helpers ─────────────────────────────────────────────────────────\n\nconst RESULT_TRANSITIONED: SendResult = Object.freeze({ status: 'transitioned' });\nconst RESULT_QUEUED: SendResult = Object.freeze({ status: 'queued' });\nconst RESULT_REJECTED: SendResult = Object.freeze({ status: 'rejected' });\n\n// ── Core interpreter ──────────────────────────────────────────────────────────\n\nconst _interpret = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n options: InterpretOptions<State, Ctx, Ev> = {},\n): MachineInstance<State, Ctx, Ev> => {\n // R8: unified onDebug — no more separate onTransition\n const onDebug = options.onDebug;\n // Auto-enable trace (default 50) when onDebug is set but traceLimit not explicit\n const traceLimit = options.traceLimit ?? (onDebug ? 50 : 0);\n\n if (options.maxTransitionsPerFlush !== undefined && options.maxTransitionsPerFlush < 1) {\n throw new ClockworkInvalidMaxTransitionsError(\n 'maxTransitionsPerFlush must be greater than 0',\n options.maxTransitionsPerFlush,\n );\n }\n\n const maxTransitionsPerFlush = options.maxTransitionsPerFlush ?? 1_000;\n const clone = options.clone ?? structuredClone;\n // Widen State keys to string so getNodeAtPath / getAncestorPaths work with plain string paths.\n const states = definition.states as unknown as Record<string, StateNode<string, Ctx, Ev>>;\n const interceptors = options.interceptors ?? [];\n const persistedSnapshot = options.snapshot ?? options.persistence?.load();\n\n if (persistedSnapshot) {\n const snapshotRoot = persistedSnapshot.state.split('.')[0];\n const snapshotValid =\n Object.hasOwn(definition.states, snapshotRoot) &&\n (!persistedSnapshot.state.includes('.') ||\n !!getNodeAtPath(definition.states as Record<string, StateNode<string, Ctx, Ev>>, persistedSnapshot.state));\n\n if (!snapshotValid) {\n throw new ClockworkInvalidSnapshotStateError(\n `snapshot state \"${persistedSnapshot.state}\" not found in states`,\n persistedSnapshot.state,\n );\n }\n }\n\n // R9: validateContext returns true | string — string is the failure reason\n const assertContext = (context: Ctx, phase: 'init' | 'transition'): void => {\n const validator = definition.validateContext;\n\n if (!validator) return;\n\n const result = validator(context);\n\n if (result !== true) {\n throw new ClockworkInvalidValidateContextError(\n `context failed validation during ${phase}${result ? `: ${result}` : ''}`,\n phase,\n result,\n );\n }\n };\n\n const resolvedInitial = persistedSnapshot\n ? persistedSnapshot.state\n : (resolveLeaf(states, definition.initial) as State);\n\n const initialContext = persistedSnapshot\n ? clone(persistedSnapshot.context)\n : clone(('context' in definition ? definition.context : ({} as Ctx)) as Ctx);\n\n if (!persistedSnapshot) assertContext(initialContext, 'init');\n\n // ── Section: State & context signals ──────────────────────────────────────\n\n const state_ = signal(resolvedInitial);\n const context_ = signal(initialContext);\n\n // ── Section: Trace ring buffer ─────────────────────────────────────────────\n\n const trace = createTraceBuffer<State, Ev>(traceLimit);\n\n // ── Section: Lifecycle ─────────────────────────────────────────────────────\n\n const disposeController = new AbortController();\n let disposed = false;\n\n // ── Section: Invoke scheduler ──────────────────────────────────────────────\n\n let invokeCounter = 0;\n\n const activeInvokes = new Set<{\n controller: AbortController;\n event: Ev | LifecycleEvent;\n id: string;\n /** Path of the state node that owns this invoke — scopes abort-on-exit to that subtree. */\n path: string;\n state: State;\n }>();\n\n /**\n * Aborts active invokes. With `paths`, only invokes owned by one of those state paths are\n * stopped (used when exiting part of the hierarchy); omit `paths` to stop everything (dispose).\n */\n const stopInvokes = (paths?: readonly string[]): void => {\n for (const invoke of activeInvokes) {\n if (paths && !paths.includes(invoke.path)) continue;\n\n invoke.controller.abort();\n onDebug?.({\n context: context_.value,\n event: invoke.event,\n invokeId: invoke.id,\n state: invoke.state,\n type: 'invoke-abort',\n });\n activeInvokes.delete(invoke);\n }\n };\n\n // ── Section: After-timer scheduler ────────────────────────────────────────\n\n const activeTimers = new Set<{ path: string; timer: ReturnType<typeof setTimeout> }>();\n\n /**\n * Clears active after-timers. With `paths`, only timers owned by one of those state paths are\n * cleared (used when exiting part of the hierarchy); omit `paths` to clear everything (dispose).\n */\n const clearTimers = (paths?: readonly string[]): void => {\n for (const entry of activeTimers) {\n if (paths && !paths.includes(entry.path)) continue;\n\n clearTimeout(entry.timer);\n activeTimers.delete(entry);\n }\n };\n\n // ── Section: Persistence ───────────────────────────────────────────────────\n\n const saveSnapshot = (): void => {\n options.persistence?.save({ context: clone(context_.value), state: state_.value });\n };\n\n // ── Section: Subscribe ─────────────────────────────────────────────────────\n\n const subscribers = new Set<(snapshot: MachineSnapshot<State, Ctx>) => void>();\n\n const notifySubscribers = (): void => {\n if (subscribers.size === 0) return;\n\n const snap: MachineSnapshot<State, Ctx> = Object.freeze({ context: context_.value, state: state_.value });\n\n for (const fn of subscribers) fn(snap);\n };\n\n // ── Section: Event queue (hoisted so executeTransition closures can reference) ──\n\n type EventQueueItem = { readonly event: Ev; readonly tag: 'event' };\n type AfterQueueItem = {\n readonly actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>;\n readonly afterEvent: { readonly delay: number; readonly type: '$after' };\n readonly from: State;\n readonly tag: 'after';\n readonly target: State;\n };\n\n type QueueItem = AfterQueueItem | EventQueueItem;\n\n const queue: QueueItem[] = [];\n let draining = false;\n\n // ── Section: Hierarchy / transition execution ──────────────────────────────\n\n const computeTransitionPaths = (from: string, to: string): { entryPaths: string[]; exitPaths: string[] } => {\n if (!from.includes('.') && !to.includes('.')) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n if (from === to) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n const fromAncestors = getAncestorPaths(from);\n const toAncestors = getAncestorPaths(to);\n\n // Advance while both paths share a common prefix — lcaIndex lands at\n // the first segment that diverges (the deepest common ancestor's depth + 1).\n let lcaIndex = 0;\n\n while (\n lcaIndex < fromAncestors.length &&\n lcaIndex < toAncestors.length &&\n fromAncestors[lcaIndex] === toAncestors[lcaIndex]\n ) {\n lcaIndex++;\n }\n\n return {\n entryPaths: toAncestors.slice(lcaIndex),\n exitPaths: fromAncestors.slice(lcaIndex).reverse(),\n };\n };\n\n const executeTransition = (\n from: State,\n resolvedTarget: State,\n actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>,\n event: Ev | LifecycleEvent,\n ): void => {\n const { entryPaths, exitPaths } = computeTransitionPaths(from, resolvedTarget);\n const draft = clone(context_.value);\n\n for (const path of exitPaths) {\n getNodeAtPath(states, path)?.exit?.({ context: draft, event });\n }\n\n for (const fn of actions) fn({ context: draft, event });\n\n for (const path of entryPaths) {\n getNodeAtPath(states, path)?.entry?.({ context: draft, event });\n }\n\n // Freeze before assertContext so validateContext always receives a read-only context\n Object.freeze(draft);\n assertContext(draft, 'transition');\n\n batch(() => {\n stopInvokes(exitPaths);\n clearTimers(exitPaths);\n state_.value = resolvedTarget;\n context_.value = draft;\n });\n\n // R8: emit unified 'transition' debug event (replaces onTransition callback)\n onDebug?.({ event, from, to: resolvedTarget, type: 'transition' } as DebugEvent<State, Ctx, Ev>);\n trace?.push({ event, from, timestamp: Date.now(), to: resolvedTarget });\n notifySubscribers();\n saveSnapshot();\n // Only (re)start invokes/timers for newly-entered paths — ancestors that remain active\n // across the transition (e.g. a sibling-to-sibling move under the same compound parent)\n // keep their invokes/timers running uninterrupted.\n runInvokes(event, entryPaths);\n scheduleAfterTransitions(entryPaths);\n };\n\n // ── Section: Invoke scheduling ─────────────────────────────────────────────\n\n const runInvokes = (triggerEvent: Ev | LifecycleEvent, paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.invoke?.length) continue;\n\n for (const invokeDef of node.invoke) {\n const controller = new AbortController();\n const invokeId = invokeDef.id ?? String(++invokeCounter);\n const capturedContext = context_.value;\n const invokeInfo = { controller, event: triggerEvent, id: invokeId, path, state: state_.value };\n\n activeInvokes.add(invokeInfo);\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-start',\n });\n\n void invokeDef\n .src({ context: capturedContext, entryEvent: triggerEvent, signal: controller.signal })\n .then((result) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onDone) return;\n\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n result,\n state: state_.value,\n type: 'invoke-done',\n });\n\n queue.push({ event: invokeDef.onDone(result, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n })\n .catch((error: unknown) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onError) return;\n\n onDebug?.({\n context: capturedContext,\n error,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-error',\n });\n\n queue.push({ event: invokeDef.onError(error, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n });\n }\n }\n };\n\n // ── Section: After (delayed) transitions ───────────────────────────────────\n\n const scheduleAfterTransitions = (paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.after?.length) continue;\n\n for (const afterDef of node.after) {\n const timer = setTimeout(() => {\n activeTimers.delete(entry);\n\n // A sibling-to-sibling transition elsewhere in the tree may have moved the leaf\n // while this timer's owning path stayed active — fire from wherever we are now,\n // and only if that path is still part of the live ancestor chain.\n if (disposed || !getAncestorPaths(state_.value).includes(path)) return;\n\n const from = state_.value;\n // R10: after.guard unified — receives { context, event } like all other guards\n const afterEvent = { delay: afterDef.delay, type: '$after' } as const;\n\n if (afterDef.guard && !afterDef.guard({ context: context_.value, event: afterEvent })) return;\n\n const resolvedTarget = resolveLeaf(states, afterDef.target) as State;\n\n queue.push({\n actions: (afterDef.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >,\n afterEvent,\n from,\n tag: 'after',\n target: resolvedTarget,\n });\n drainQueue();\n }, afterDef.delay);\n const entry = { path, timer };\n\n activeTimers.add(entry);\n }\n }\n };\n\n // ── Section: Event queue processing ─────────────────────────────────────────\n\n const processEvent = (item: QueueItem): boolean => {\n if (disposed) return false;\n\n if (item.tag === 'after') {\n executeTransition(item.from, item.target, item.actions, item.afterEvent);\n\n return true;\n }\n\n const from = state_.value;\n\n const transition = resolveTransition(\n definition,\n { context: context_.value, event: item.event, state: from },\n onDebug ? (info) => onDebug({ ...info, type: 'guard' }) : undefined,\n );\n\n if (!transition) {\n onDebug?.({ event: item.event, from, type: 'transition-skipped' });\n\n return false;\n }\n\n const resolvedTarget = resolveLeaf(states, transition.target) as State;\n const actions = (transition.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >;\n\n executeTransition(from, resolvedTarget, actions, item.event);\n\n return true;\n };\n\n const drainQueueInner = (): void => {\n let processed = 0;\n\n while (queue.length > 0) {\n if (++processed > maxTransitionsPerFlush) {\n throw new ClockworkTransitionLoopGuardError(\n 'transition queue exceeded maxTransitionsPerFlush',\n maxTransitionsPerFlush,\n );\n }\n\n processEvent(queue.shift()!);\n }\n };\n\n const drainQueue = (): void => {\n if (draining) return;\n\n draining = true;\n\n try {\n drainQueueInner();\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n // ── Section: Public API ────────────────────────────────────────────────────\n\n const can = (event: Ev): boolean => {\n if (disposed) return false;\n\n return !!resolveTransition(definition, { context: context_.value, event, state: state_.value });\n };\n\n const send = (event: Ev): SendResult => {\n if (disposed) {\n warn('send() called on a disposed machine — event ignored');\n\n return RESULT_REJECTED;\n }\n\n // Run interceptors left-to-right — first null wins\n let intercepted: Ev | null = event;\n\n for (const fn of interceptors) {\n intercepted = fn(intercepted, { context: context_.value, state: state_.value });\n\n if (intercepted === null) return RESULT_REJECTED;\n }\n\n const interceptedEvent = intercepted;\n\n if (draining) {\n queue.push({ event: interceptedEvent, tag: 'event' });\n\n return RESULT_QUEUED;\n }\n\n draining = true;\n\n try {\n const transitioned = processEvent({ event: interceptedEvent, tag: 'event' });\n\n drainQueueInner();\n\n return transitioned ? RESULT_TRANSITIONED : RESULT_REJECTED;\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n const getSnapshot = (): MachineSnapshot<State, Ctx> =>\n Object.freeze({ context: clone(context_.value), state: state_.value });\n\n const getTrace = (): readonly TransitionTraceEntry<State, Ev>[] => trace?.get() ?? [];\n\n const matches = (...stateArgs: string[]): boolean => {\n if (disposed) return false;\n\n const current = state_.value;\n\n return stateArgs.some((s) => current === s || current.startsWith(`${s}.`));\n };\n\n // R5: subscribe via plain Set — no ripple effect(), no prevState/prevCtx tracking\n const subscribe = (fn: (snapshot: MachineSnapshot<State, Ctx>) => void): (() => void) => {\n subscribers.add(fn);\n\n return () => subscribers.delete(fn);\n };\n\n // ── Section: Initialization ────────────────────────────────────────────────\n\n const initialPaths = getAncestorPaths(resolvedInitial);\n\n if (persistedSnapshot) {\n runInvokes(HYDRATE_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n } else {\n const hasEntry = initialPaths.some((p) => getNodeAtPath(states, p)?.entry);\n\n if (hasEntry) {\n const initDraft = clone(context_.value);\n\n for (const p of initialPaths) {\n getNodeAtPath(states, p)?.entry?.({ context: initDraft, event: INIT_EVENT });\n }\n\n assertContext(initDraft, 'init');\n context_.value = initDraft;\n }\n\n runInvokes(INIT_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n\n if (options.persistence) saveSnapshot();\n }\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n stopInvokes();\n clearTimers();\n state_.dispose();\n context_.dispose();\n };\n\n return {\n can,\n context: readonly(context_),\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot,\n getTrace,\n matches,\n send,\n state: readonly(state_),\n subscribe,\n [Symbol.dispose]: dispose,\n };\n};\n\n// ── Public entry point ────────────────────────────────────────────────────────\n\n/**\n * Validates a machine configuration and returns a reusable definition handle.\n *\n * Call `.start(options?)` to create a running instance.\n * Call `.resolve(input, options?)` to inspect transitions without starting a machine.\n *\n * @example\n * const counterDef = createMachine({\n * context: { count: 0 },\n * initial: 'idle',\n * states: { idle: { on: { INC: { actions: [({ context }) => { context.count += 1 }], target: 'idle' } } } },\n * });\n *\n * const m1 = counterDef.start();\n * const m2 = counterDef.start({ snapshot: { context: { count: 10 }, state: 'idle' } });\n *\n * // Test transitions without a running machine:\n * counterDef.resolve({ context: { count: 0 }, event: { type: 'INC' }, state: 'idle' });\n *\n * // Or start immediately (one-shot):\n * const m3 = createMachine(config).start();\n */\nexport const createMachine = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n config: MachineConfig<State, Ctx, Ev>,\n): MachineDefinition<State, Ctx, Ev> => {\n validateDefinition(config);\n\n return {\n resolve(input, options?) {\n return resolveTransition(config, input, options?.onGuard);\n },\n start(options?) {\n return _interpret(config, options);\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var Clockwork=(function(e,t){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var n=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},r=class extends n{path;constructor(e,t,n){super(e,n),this.path=t}},i=class extends n{path;initial;constructor(e,t,n,r){super(e,r),this.path=t,this.initial=n}},a=class extends n{path;eventType;constructor(e,t,n,r){super(e,r),this.path=t,this.eventType=n}},o=class extends n{path;target;eventType;constructor(e,t,n,r,i){super(e,i),this.path=t,this.target=n,this.eventType=r}},s=class extends n{path;delay;constructor(e,t,n,r){super(e,r),this.path=t,this.delay=n}},c=class extends n{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},l=class extends n{state;constructor(e,t,n){super(e,n),this.state=t}},u=class extends n{phase;reason;constructor(e,t,n,r){super(e,r),this.phase=t,this.reason=n}},d=class extends n{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},f=!globalThis.__CLOCKWORK_PROD__;function p(e){f&&console.warn(`[@vielzeug/clockwork] ${e}`)}function m(e){if(e<=0)return null;let t=[],n=0,r=0;return{get(){return r===0?[]:(r<e?t.slice(0,r):[...t.slice(n),...t.slice(0,n)]).map(e=>({...e}))},push(i){r<e?(t.push(i),r++):(t[n]=i,n=(n+1)%e)}}}var h=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:void 0,g=(e,t)=>{let n=t.split(`.`),r=h(e,n[0]);if(!r)return t;for(let e=1;e<n.length;e++)if(r=h(r.states,n[e]),!r)return t;let i=t;for(;r?.states&&r.initial;)i=`${i}.${r.initial}`,r=h(r.states,r.initial);return i},_=(e,t)=>{let n=t.split(`.`),r=h(e,n[0]);for(let e=1;e<n.length;e++){if(!r?.states)return;r=h(r.states,n[e])}return r},v=e=>{let t=e.split(`.`),n=[];for(let e=1;e<=t.length;e++)n.push(t.slice(0,e).join(`.`));return n},y=(e,t,n)=>{if(e.states&&!e.initial)throw new r(`compound state "${t}" must have an "initial" property`,t);if(e.initial&&e.states&&!Object.hasOwn(e.states,e.initial))throw new i(`compound state "${t}" initial "${e.initial}" not found in substates`,t,e.initial);for(let[r,i]of Object.entries(e.on??{})){let e=Array.isArray(i)?i:[i];if(e.length===0)throw new a(`state "${t}" event "${r}" must be a non-empty transition or transition array`,t,r);for(let i of e){let e=i.target.split(`.`)[0];if(!Object.hasOwn(n,e))throw new o(`state "${t}" event "${r}" targets unknown state "${i.target}"`,t,i.target,r);if(i.target.includes(`.`)&&!_(n,i.target))throw new o(`state "${t}" event "${r}" targets unknown nested state "${i.target}"`,t,i.target,r)}}if(e.invoke!==void 0&&e.invoke.length===0)throw new a(`state "${t}" invoke must be a non-empty array`,t);for(let r of e.after??[]){if(!Number.isFinite(r.delay)||r.delay<0)throw new s(`state "${t}" after delay must be a finite number >= 0, got ${r.delay}`,t,r.delay);let e=r.target.split(`.`)[0];if(!Object.hasOwn(n,e))throw new o(`state "${t}" after[${r.delay}ms] targets unknown state "${r.target}"`,t,r.target);if(r.target.includes(`.`)&&!_(n,r.target))throw new o(`state "${t}" after[${r.delay}ms] targets unknown nested state "${r.target}"`,t,r.target)}if(e.states)for(let[r,i]of Object.entries(e.states))y(i,`${t}.${r}`,n)},b=e=>{let{states:t}=e;if(!Object.hasOwn(t,e.initial))throw new i(`initial state "${e.initial}" not found in states`,``,e.initial);for(let[e,n]of Object.entries(t))y(n,e,t)},x={type:`$init`},S={type:`$hydrate`},C=(e,t,n)=>{let{context:r,event:i,state:a}=t;if(!i||typeof i.type!=`string`)return;let o=v(a);for(let t=o.length-1;t>=0;t--){let s=_(e.states,o[t]);if(!s?.on)continue;let c=i.type,l=Object.hasOwn(s.on,c)?s.on[c]:void 0;if(!l)continue;let u=Array.isArray(l)?l:[l];for(let e of u){let t=!e.guard||e.guard({context:r,event:i});if(n?.({context:r,event:i,from:a,passed:t,target:e.target}),t)return e}}},w=Object.freeze({status:`transitioned`}),T=Object.freeze({status:`queued`}),E=Object.freeze({status:`rejected`}),D=(e,n={})=>{let r=n.onDebug,i=n.traceLimit??(r?50:0);if(n.maxTransitionsPerFlush!==void 0&&n.maxTransitionsPerFlush<1)throw new c(`maxTransitionsPerFlush must be greater than 0`,n.maxTransitionsPerFlush);let a=n.maxTransitionsPerFlush??1e3,o=n.clone??structuredClone,s=e.states,f=n.interceptors??[],h=n.snapshot??n.persistence?.load();if(h){let t=h.state.split(`.`)[0];if(!(Object.hasOwn(e.states,t)&&(!h.state.includes(`.`)||_(e.states,h.state))))throw new l(`snapshot state "${h.state}" not found in states`,h.state)}let y=(t,n)=>{let r=e.validateContext;if(!r)return;let i=r(t);if(i!==!0)throw new u(`context failed validation during ${n}${i?`: ${i}`:``}`,n,i)},b=h?h.state:g(s,e.initial),D=o(h?h.context:`context`in e?e.context:{});h||y(D,`init`);let O=(0,t.signal)(b),k=(0,t.signal)(D),A=m(i),j=new AbortController,M=!1,ee=0,N=new Set,P=e=>{for(let t of N)e&&!e.includes(t.path)||(t.controller.abort(),r?.({context:k.value,event:t.event,invokeId:t.id,state:t.state,type:`invoke-abort`}),N.delete(t))},F=new Set,I=e=>{for(let t of F)e&&!e.includes(t.path)||(clearTimeout(t.timer),F.delete(t))},L=()=>{n.persistence?.save({context:o(k.value),state:O.value})},R=new Set,z=()=>{if(R.size===0)return;let e=Object.freeze({context:k.value,state:O.value});for(let t of R)t(e)},B=[],V=!1,H=(e,t)=>{if(!e.includes(`.`)&&!t.includes(`.`)||e===t)return{entryPaths:[t],exitPaths:[e]};let n=v(e),r=v(t),i=0;for(;i<n.length&&i<r.length&&n[i]===r[i];)i++;return{entryPaths:r.slice(i),exitPaths:n.slice(i).reverse()}},U=(e,n,i,a)=>{let{entryPaths:c,exitPaths:l}=H(e,n),u=o(k.value);for(let e of l)_(s,e)?.exit?.({context:u,event:a});for(let e of i)e({context:u,event:a});for(let e of c)_(s,e)?.entry?.({context:u,event:a});Object.freeze(u),y(u,`transition`),(0,t.batch)(()=>{P(l),I(l),O.value=n,k.value=u}),r?.({event:a,from:e,to:n,type:`transition`}),A?.push({event:a,from:e,timestamp:Date.now(),to:n}),z(),L(),W(a,c),G(c)},W=(e,t)=>{for(let n of t){let t=_(s,n);if(t?.invoke?.length)for(let i of t.invoke){let t=new AbortController,a=i.id??String(++ee),o=k.value,s={controller:t,event:e,id:a,path:n,state:O.value};N.add(s),r?.({context:o,event:e,invokeId:a,state:O.value,type:`invoke-start`}),i.src({context:o,entryEvent:e,signal:t.signal}).then(n=>{N.delete(s),!(M||t.signal.aborted||!i.onDone)&&(r?.({context:o,event:e,invokeId:a,result:n,state:O.value,type:`invoke-done`}),B.push({event:i.onDone(n,o),tag:`event`}),V||J())}).catch(n=>{N.delete(s),!(M||t.signal.aborted||!i.onError)&&(r?.({context:o,error:n,event:e,invokeId:a,state:O.value,type:`invoke-error`}),B.push({event:i.onError(n,o),tag:`event`}),V||J())})}}},G=e=>{for(let t of e){let e=_(s,t);if(e?.after?.length)for(let n of e.after){let e={path:t,timer:setTimeout(()=>{if(F.delete(e),M||!v(O.value).includes(t))return;let r=O.value,i={delay:n.delay,type:`$after`};if(n.guard&&!n.guard({context:k.value,event:i}))return;let a=g(s,n.target);B.push({actions:n.actions??[],afterEvent:i,from:r,tag:`after`,target:a}),J()},n.delay)};F.add(e)}}},K=t=>{if(M)return!1;if(t.tag===`after`)return U(t.from,t.target,t.actions,t.afterEvent),!0;let n=O.value,i=C(e,{context:k.value,event:t.event,state:n},r?e=>r({...e,type:`guard`}):void 0);if(!i)return r?.({event:t.event,from:n,type:`transition-skipped`}),!1;let a=g(s,i.target),o=i.actions??[];return U(n,a,o,t.event),!0},q=()=>{let e=0;for(;B.length>0;){if(++e>a)throw new d(`transition queue exceeded maxTransitionsPerFlush`,a);K(B.shift())}},J=()=>{if(!V){V=!0;try{q()}catch(e){throw B.length=0,e}finally{V=!1}}},Y=t=>M?!1:!!C(e,{context:k.value,event:t,state:O.value}),X=e=>{if(M)return p(`send() called on a disposed machine — event ignored`),E;let t=e;for(let e of f)if(t=e(t,{context:k.value,state:O.value}),t===null)return E;let n=t;if(V)return B.push({event:n,tag:`event`}),T;V=!0;try{let e=K({event:n,tag:`event`});return q(),e?w:E}catch(e){throw B.length=0,e}finally{V=!1}},Z=()=>Object.freeze({context:o(k.value),state:O.value}),te=()=>A?.get()??[],ne=(...e)=>{if(M)return!1;let t=O.value;return e.some(e=>t===e||t.startsWith(`${e}.`))},re=e=>(R.add(e),()=>R.delete(e)),Q=v(b);if(h)W(S,Q),G(Q);else{if(Q.some(e=>_(s,e)?.entry)){let e=o(k.value);for(let t of Q)_(s,t)?.entry?.({context:e,event:x});y(e,`init`),k.value=e}W(x,Q),G(Q),n.persistence&&L()}let $=()=>{M||(M=!0,j.abort(),P(),I(),O.dispose(),k.dispose())};return{can:Y,context:(0,t.readonly)(k),get disposalSignal(){return j.signal},dispose:$,get disposed(){return M},getSnapshot:Z,getTrace:te,matches:ne,send:X,state:(0,t.readonly)(O),subscribe:re,[Symbol.dispose]:$}};return e.ClockworkError=n,e.ClockworkInvalidAfterDelayError=s,e.ClockworkInvalidInitialStateError=i,e.ClockworkInvalidMaxTransitionsError=c,e.ClockworkInvalidSnapshotStateError=l,e.ClockworkInvalidTransitionArrayError=a,e.ClockworkInvalidValidateContextError=u,e.ClockworkMissingCompoundInitialError=r,e.ClockworkTransitionLoopGuardError=d,e.ClockworkUnknownTargetError=o,e.createMachine=e=>(b(e),{resolve(t,n){return C(e,t,n?.onGuard)},start(t){return D(e,t)}}),e})({},Ripple);
|
|
2
|
+
//# sourceMappingURL=clockwork.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clockwork.iife.js","names":[],"sources":["../src/errors.ts","../src/_dev.ts","../src/_trace.ts","../src/definition.ts","../src/interpret.ts"],"sourcesContent":["/** Base class for all clockwork errors. Use `instanceof ClockworkError` to catch any clockwork-originated error. */\nexport class ClockworkError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ClockworkError {\n return err instanceof ClockworkError;\n }\n}\n\n/** Thrown when a compound state does not declare an `initial` substate. */\nexport class ClockworkMissingCompoundInitialError extends ClockworkError {\n readonly path: string;\n constructor(message: string, path: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n }\n}\n\n/** Thrown when a compound state's `initial` value does not match any substate. */\nexport class ClockworkInvalidInitialStateError extends ClockworkError {\n readonly path: string;\n readonly initial: string;\n constructor(message: string, path: string, initial: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.initial = initial;\n }\n}\n\n/** Thrown when a transition definition is empty or not a valid array. */\nexport class ClockworkInvalidTransitionArrayError extends ClockworkError {\n readonly path: string;\n readonly eventType?: string;\n constructor(message: string, path: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when a transition or `after` definition targets an unknown state. */\nexport class ClockworkUnknownTargetError extends ClockworkError {\n readonly path: string;\n readonly target: string;\n readonly eventType?: string;\n constructor(message: string, path: string, target: string, eventType?: string, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.target = target;\n this.eventType = eventType;\n }\n}\n\n/** Thrown when an `after` delay value is invalid (must be a finite number ≥ 0). */\nexport class ClockworkInvalidAfterDelayError extends ClockworkError {\n readonly path: string;\n readonly delay: number;\n constructor(message: string, path: string, delay: number, opts?: ErrorOptions) {\n super(message, opts);\n this.path = path;\n this.delay = delay;\n }\n}\n\n/** Thrown when `maxTransitionsPerFlush` is configured with a value less than 1. */\nexport class ClockworkInvalidMaxTransitionsError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n\n/** Thrown when a persisted snapshot references a state that no longer exists in the machine definition. */\nexport class ClockworkInvalidSnapshotStateError extends ClockworkError {\n readonly state: string;\n constructor(message: string, state: string, opts?: ErrorOptions) {\n super(message, opts);\n this.state = state;\n }\n}\n\n/** Thrown when `validateContext` returns a failure reason during init or transition. */\nexport class ClockworkInvalidValidateContextError extends ClockworkError {\n readonly phase: 'init' | 'transition';\n readonly reason: string | true;\n constructor(message: string, phase: 'init' | 'transition', reason: string | true, opts?: ErrorOptions) {\n super(message, opts);\n this.phase = phase;\n this.reason = reason;\n }\n}\n\n/** Thrown when the transition queue exceeds `maxTransitionsPerFlush`, indicating an infinite loop. */\nexport class ClockworkTransitionLoopGuardError extends ClockworkError {\n readonly maxTransitionsPerFlush: number;\n constructor(message: string, maxTransitionsPerFlush: number, opts?: ErrorOptions) {\n super(message, opts);\n this.maxTransitionsPerFlush = maxTransitionsPerFlush;\n }\n}\n","const isDev = !(globalThis as { __CLOCKWORK_PROD__?: boolean }).__CLOCKWORK_PROD__;\n\n/** @internal */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/clockwork] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n","import type { MachineEvent, TransitionTraceEntry } from './types.js';\n\nexport interface TraceBuffer<State extends string, Ev extends MachineEvent> {\n get(): readonly TransitionTraceEntry<State, Ev>[];\n push(entry: TransitionTraceEntry<State, Ev>): void;\n}\n\nexport function createTraceBuffer<State extends string, Ev extends MachineEvent>(\n limit: number,\n): TraceBuffer<State, Ev> | null {\n if (limit <= 0) return null;\n\n const buffer: TransitionTraceEntry<State, Ev>[] = [];\n let head = 0;\n let count = 0;\n\n return {\n get() {\n if (count === 0) return [];\n\n const entries = count < limit ? buffer.slice(0, count) : [...buffer.slice(head), ...buffer.slice(0, head)];\n\n return entries.map((e) => ({ ...e }));\n },\n push(entry) {\n if (count < limit) {\n buffer.push(entry);\n count++;\n } else {\n buffer[head] = entry;\n head = (head + 1) % limit;\n }\n },\n };\n}\n","import type { MachineConfig, MachineEvent, StateNode, TransitionDef } from './types.js';\n\nimport {\n ClockworkInvalidAfterDelayError,\n ClockworkInvalidInitialStateError,\n ClockworkInvalidTransitionArrayError,\n ClockworkMissingCompoundInitialError,\n ClockworkUnknownTargetError,\n} from './errors.js';\n\n// ── Key safety ────────────────────────────────────────────────────────────────\n\n/**\n * Own-property-only lookup — state paths and event types ultimately come from strings\n * (persisted snapshots, event payloads) that may not be developer-authored. A plain\n * `obj[key]` or `key in obj` resolves inherited `Object.prototype` members (`__proto__`,\n * `constructor`, `toString`, …), which can turn an \"unknown state/event\" into a crash or\n * a silently-accepted bogus value instead of the intended \"not found\". Treat any such key\n * as absent instead.\n */\nconst getOwn = <T>(obj: Record<string, T> | undefined, key: string): T | undefined =>\n obj && Object.hasOwn(obj, key) ? obj[key] : undefined;\n\n// ── Hierarchy helpers (internal — not re-exported from index) ─────────────────\n\n/**\n * Resolves a target state to its deepest initial leaf.\n * For compound states (those with `states` + `initial`), recursively descends.\n */\nexport const resolveLeaf = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n target: string,\n): string => {\n const segments = target.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n if (!node) return target;\n\n for (let i = 1; i < segments.length; i++) {\n node = getOwn(node.states, segments[i]);\n\n if (!node) return target;\n }\n\n let path = target;\n\n while (node?.states && node.initial) {\n path = `${path}.${node.initial}`;\n node = getOwn(node.states, node.initial);\n }\n\n return path;\n};\n\n/**\n * Returns the node at a given dot-path.\n */\nexport const getNodeAtPath = <Ctx extends object, Ev extends MachineEvent>(\n topLevelStates: Record<string, StateNode<string, Ctx, Ev>>,\n path: string,\n): StateNode<string, Ctx, Ev> | undefined => {\n const segments = path.split('.');\n let node = getOwn(topLevelStates, segments[0]);\n\n for (let i = 1; i < segments.length; i++) {\n if (!node?.states) return undefined;\n\n node = getOwn(node.states, segments[i]);\n }\n\n return node;\n};\n\n/**\n * Returns ancestor paths from root to leaf (inclusive), e.g. ['a', 'a.b', 'a.b.c']\n */\nexport const getAncestorPaths = (path: string): string[] => {\n const segments = path.split('.');\n const paths: string[] = [];\n\n for (let i = 1; i <= segments.length; i++) {\n paths.push(segments.slice(0, i).join('.'));\n }\n\n return paths;\n};\n\n// ── Validation ───────────────────────────────────────────────────────────────\n\nconst validateNode = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n node: StateNode<string, Ctx, Ev>,\n path: string,\n allTopLevel: Record<string, StateNode<State, Ctx, Ev>>,\n): void => {\n if (node.states && !node.initial) {\n throw new ClockworkMissingCompoundInitialError(`compound state \"${path}\" must have an \"initial\" property`, path);\n }\n\n if (node.initial && node.states && !Object.hasOwn(node.states, node.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `compound state \"${path}\" initial \"${node.initial}\" not found in substates`,\n path,\n node.initial,\n );\n }\n\n for (const [eventType, input] of Object.entries(node.on ?? {})) {\n const defs = Array.isArray(input) ? input : [input];\n\n if (defs.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(\n `state \"${path}\" event \"${eventType}\" must be a non-empty transition or transition array`,\n path,\n eventType,\n );\n }\n\n for (const tr of defs as Array<TransitionDef<State, Ctx, Ev>>) {\n const targetRoot = tr.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n\n if (tr.target.includes('.') && !getNodeAtPath(allTopLevel, tr.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" event \"${eventType}\" targets unknown nested state \"${tr.target}\"`,\n path,\n tr.target,\n eventType,\n );\n }\n }\n }\n\n // Validate empty invoke array (D1)\n if (node.invoke !== undefined && node.invoke.length === 0) {\n throw new ClockworkInvalidTransitionArrayError(`state \"${path}\" invoke must be a non-empty array`, path);\n }\n\n // Validate after targets and delays\n for (const afterDef of node.after ?? []) {\n if (!Number.isFinite(afterDef.delay) || afterDef.delay < 0) {\n throw new ClockworkInvalidAfterDelayError(\n `state \"${path}\" after delay must be a finite number >= 0, got ${afterDef.delay}`,\n path,\n afterDef.delay,\n );\n }\n\n const targetRoot = afterDef.target.split('.')[0];\n\n if (!Object.hasOwn(allTopLevel, targetRoot)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n\n if (afterDef.target.includes('.') && !getNodeAtPath(allTopLevel, afterDef.target)) {\n throw new ClockworkUnknownTargetError(\n `state \"${path}\" after[${afterDef.delay}ms] targets unknown nested state \"${afterDef.target}\"`,\n path,\n afterDef.target,\n );\n }\n }\n\n if (node.states) {\n for (const [name, child] of Object.entries(node.states)) {\n validateNode(child, `${path}.${name}`, allTopLevel);\n }\n }\n};\n\nexport const validateDefinition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: MachineConfig<State, Ctx, Ev>,\n): void => {\n const { states } = definition;\n\n if (!Object.hasOwn(states, definition.initial)) {\n throw new ClockworkInvalidInitialStateError(\n `initial state \"${definition.initial}\" not found in states`,\n '',\n definition.initial,\n );\n }\n\n for (const [stateName, node] of Object.entries(states) as Array<[string, StateNode<State, Ctx, Ev>]>) {\n validateNode(node, stateName, states);\n }\n};\n","import { batch, readonly, signal } from '@vielzeug/ripple';\n\nimport type {\n DebugEvent,\n EventByType,\n EventType,\n InterpretOptions,\n LifecycleEvent,\n MachineConfig,\n MachineDefinition,\n MachineEvent,\n MachineInstance,\n MachineSnapshot,\n SendResult,\n StateNode,\n TransitionDef,\n TransitionTraceEntry,\n} from './types.js';\n\nimport { warn } from './_dev';\nimport { createTraceBuffer } from './_trace.js';\nimport { getAncestorPaths, getNodeAtPath, resolveLeaf, validateDefinition } from './definition.js';\nimport {\n ClockworkInvalidMaxTransitionsError,\n ClockworkInvalidSnapshotStateError,\n ClockworkInvalidValidateContextError,\n ClockworkTransitionLoopGuardError,\n} from './errors.js';\n\n// ── Internal constants ────────────────────────────────────────────────────────\n\nconst INIT_EVENT = { type: '$init' } as const;\nconst HYDRATE_EVENT = { type: '$hydrate' } as const;\n\n// ── Pure resolver ─────────────────────────────────────────────────────────────\n\n/**\n * Resolves which transition should be taken for a given state + event.\n * Pure function — no side effects; useful for testing transition logic independently.\n *\n * Optionally calls `onGuard` for each guard evaluation.\n */\nconst resolveTransition = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n input: {\n context: Readonly<Ctx>;\n event: NoInfer<Ev>;\n state: State;\n },\n onGuard?: (info: { context: Readonly<Ctx>; event: Ev; from: State; passed: boolean; target: State }) => void,\n): TransitionDef<State, Ctx, Ev> | undefined => {\n const { context, event, state } = input;\n\n // Defensive: callers piping untyped external data through an `Ev`-typed cast (e.g. a\n // deserialized network message passed to `send()`) can violate the MachineEvent contract\n // at runtime. Treat a missing/non-string `type` as \"no matching transition\" rather than\n // crashing with a raw TypeError.\n if (!event || typeof (event as unknown as { type?: unknown }).type !== 'string') return undefined;\n\n const ancestors = getAncestorPaths(state);\n\n for (let i = ancestors.length - 1; i >= 0; i--) {\n const node = getNodeAtPath(definition.states, ancestors[i]) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.on) continue;\n\n // Own-property check — an event `type` of \"__proto__\"/\"constructor\"/etc. must resolve\n // to \"no matching transition\", not an inherited Object.prototype member.\n const eventType = event.type as EventType<Ev>;\n const raw = Object.hasOwn(node.on, eventType) ? node.on[eventType] : undefined;\n\n if (!raw) continue;\n\n const defs = Array.isArray(raw) ? raw : [raw];\n\n for (const def of defs) {\n const passed = !def.guard || def.guard({ context, event: event as EventByType<Ev, EventType<Ev>> });\n\n onGuard?.({ context, event, from: state, passed, target: def.target as State });\n\n if (passed) return def as TransitionDef<State, Ctx, Ev>;\n }\n }\n\n return undefined;\n};\n\n// ── SendResult helpers ─────────────────────────────────────────────────────────\n\nconst RESULT_TRANSITIONED: SendResult = Object.freeze({ status: 'transitioned' });\nconst RESULT_QUEUED: SendResult = Object.freeze({ status: 'queued' });\nconst RESULT_REJECTED: SendResult = Object.freeze({ status: 'rejected' });\n\n// ── Core interpreter ──────────────────────────────────────────────────────────\n\nconst _interpret = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n definition: Readonly<MachineConfig<State, Ctx, Ev>>,\n options: InterpretOptions<State, Ctx, Ev> = {},\n): MachineInstance<State, Ctx, Ev> => {\n // R8: unified onDebug — no more separate onTransition\n const onDebug = options.onDebug;\n // Auto-enable trace (default 50) when onDebug is set but traceLimit not explicit\n const traceLimit = options.traceLimit ?? (onDebug ? 50 : 0);\n\n if (options.maxTransitionsPerFlush !== undefined && options.maxTransitionsPerFlush < 1) {\n throw new ClockworkInvalidMaxTransitionsError(\n 'maxTransitionsPerFlush must be greater than 0',\n options.maxTransitionsPerFlush,\n );\n }\n\n const maxTransitionsPerFlush = options.maxTransitionsPerFlush ?? 1_000;\n const clone = options.clone ?? structuredClone;\n // Widen State keys to string so getNodeAtPath / getAncestorPaths work with plain string paths.\n const states = definition.states as unknown as Record<string, StateNode<string, Ctx, Ev>>;\n const interceptors = options.interceptors ?? [];\n const persistedSnapshot = options.snapshot ?? options.persistence?.load();\n\n if (persistedSnapshot) {\n const snapshotRoot = persistedSnapshot.state.split('.')[0];\n const snapshotValid =\n Object.hasOwn(definition.states, snapshotRoot) &&\n (!persistedSnapshot.state.includes('.') ||\n !!getNodeAtPath(definition.states as Record<string, StateNode<string, Ctx, Ev>>, persistedSnapshot.state));\n\n if (!snapshotValid) {\n throw new ClockworkInvalidSnapshotStateError(\n `snapshot state \"${persistedSnapshot.state}\" not found in states`,\n persistedSnapshot.state,\n );\n }\n }\n\n // R9: validateContext returns true | string — string is the failure reason\n const assertContext = (context: Ctx, phase: 'init' | 'transition'): void => {\n const validator = definition.validateContext;\n\n if (!validator) return;\n\n const result = validator(context);\n\n if (result !== true) {\n throw new ClockworkInvalidValidateContextError(\n `context failed validation during ${phase}${result ? `: ${result}` : ''}`,\n phase,\n result,\n );\n }\n };\n\n const resolvedInitial = persistedSnapshot\n ? persistedSnapshot.state\n : (resolveLeaf(states, definition.initial) as State);\n\n const initialContext = persistedSnapshot\n ? clone(persistedSnapshot.context)\n : clone(('context' in definition ? definition.context : ({} as Ctx)) as Ctx);\n\n if (!persistedSnapshot) assertContext(initialContext, 'init');\n\n // ── Section: State & context signals ──────────────────────────────────────\n\n const state_ = signal(resolvedInitial);\n const context_ = signal(initialContext);\n\n // ── Section: Trace ring buffer ─────────────────────────────────────────────\n\n const trace = createTraceBuffer<State, Ev>(traceLimit);\n\n // ── Section: Lifecycle ─────────────────────────────────────────────────────\n\n const disposeController = new AbortController();\n let disposed = false;\n\n // ── Section: Invoke scheduler ──────────────────────────────────────────────\n\n let invokeCounter = 0;\n\n const activeInvokes = new Set<{\n controller: AbortController;\n event: Ev | LifecycleEvent;\n id: string;\n /** Path of the state node that owns this invoke — scopes abort-on-exit to that subtree. */\n path: string;\n state: State;\n }>();\n\n /**\n * Aborts active invokes. With `paths`, only invokes owned by one of those state paths are\n * stopped (used when exiting part of the hierarchy); omit `paths` to stop everything (dispose).\n */\n const stopInvokes = (paths?: readonly string[]): void => {\n for (const invoke of activeInvokes) {\n if (paths && !paths.includes(invoke.path)) continue;\n\n invoke.controller.abort();\n onDebug?.({\n context: context_.value,\n event: invoke.event,\n invokeId: invoke.id,\n state: invoke.state,\n type: 'invoke-abort',\n });\n activeInvokes.delete(invoke);\n }\n };\n\n // ── Section: After-timer scheduler ────────────────────────────────────────\n\n const activeTimers = new Set<{ path: string; timer: ReturnType<typeof setTimeout> }>();\n\n /**\n * Clears active after-timers. With `paths`, only timers owned by one of those state paths are\n * cleared (used when exiting part of the hierarchy); omit `paths` to clear everything (dispose).\n */\n const clearTimers = (paths?: readonly string[]): void => {\n for (const entry of activeTimers) {\n if (paths && !paths.includes(entry.path)) continue;\n\n clearTimeout(entry.timer);\n activeTimers.delete(entry);\n }\n };\n\n // ── Section: Persistence ───────────────────────────────────────────────────\n\n const saveSnapshot = (): void => {\n options.persistence?.save({ context: clone(context_.value), state: state_.value });\n };\n\n // ── Section: Subscribe ─────────────────────────────────────────────────────\n\n const subscribers = new Set<(snapshot: MachineSnapshot<State, Ctx>) => void>();\n\n const notifySubscribers = (): void => {\n if (subscribers.size === 0) return;\n\n const snap: MachineSnapshot<State, Ctx> = Object.freeze({ context: context_.value, state: state_.value });\n\n for (const fn of subscribers) fn(snap);\n };\n\n // ── Section: Event queue (hoisted so executeTransition closures can reference) ──\n\n type EventQueueItem = { readonly event: Ev; readonly tag: 'event' };\n type AfterQueueItem = {\n readonly actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>;\n readonly afterEvent: { readonly delay: number; readonly type: '$after' };\n readonly from: State;\n readonly tag: 'after';\n readonly target: State;\n };\n\n type QueueItem = AfterQueueItem | EventQueueItem;\n\n const queue: QueueItem[] = [];\n let draining = false;\n\n // ── Section: Hierarchy / transition execution ──────────────────────────────\n\n const computeTransitionPaths = (from: string, to: string): { entryPaths: string[]; exitPaths: string[] } => {\n if (!from.includes('.') && !to.includes('.')) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n if (from === to) {\n return { entryPaths: [to], exitPaths: [from] };\n }\n\n const fromAncestors = getAncestorPaths(from);\n const toAncestors = getAncestorPaths(to);\n\n // Advance while both paths share a common prefix — lcaIndex lands at\n // the first segment that diverges (the deepest common ancestor's depth + 1).\n let lcaIndex = 0;\n\n while (\n lcaIndex < fromAncestors.length &&\n lcaIndex < toAncestors.length &&\n fromAncestors[lcaIndex] === toAncestors[lcaIndex]\n ) {\n lcaIndex++;\n }\n\n return {\n entryPaths: toAncestors.slice(lcaIndex),\n exitPaths: fromAncestors.slice(lcaIndex).reverse(),\n };\n };\n\n const executeTransition = (\n from: State,\n resolvedTarget: State,\n actions: Array<(args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void>,\n event: Ev | LifecycleEvent,\n ): void => {\n const { entryPaths, exitPaths } = computeTransitionPaths(from, resolvedTarget);\n const draft = clone(context_.value);\n\n for (const path of exitPaths) {\n getNodeAtPath(states, path)?.exit?.({ context: draft, event });\n }\n\n for (const fn of actions) fn({ context: draft, event });\n\n for (const path of entryPaths) {\n getNodeAtPath(states, path)?.entry?.({ context: draft, event });\n }\n\n // Freeze before assertContext so validateContext always receives a read-only context\n Object.freeze(draft);\n assertContext(draft, 'transition');\n\n batch(() => {\n stopInvokes(exitPaths);\n clearTimers(exitPaths);\n state_.value = resolvedTarget;\n context_.value = draft;\n });\n\n // R8: emit unified 'transition' debug event (replaces onTransition callback)\n onDebug?.({ event, from, to: resolvedTarget, type: 'transition' } as DebugEvent<State, Ctx, Ev>);\n trace?.push({ event, from, timestamp: Date.now(), to: resolvedTarget });\n notifySubscribers();\n saveSnapshot();\n // Only (re)start invokes/timers for newly-entered paths — ancestors that remain active\n // across the transition (e.g. a sibling-to-sibling move under the same compound parent)\n // keep their invokes/timers running uninterrupted.\n runInvokes(event, entryPaths);\n scheduleAfterTransitions(entryPaths);\n };\n\n // ── Section: Invoke scheduling ─────────────────────────────────────────────\n\n const runInvokes = (triggerEvent: Ev | LifecycleEvent, paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.invoke?.length) continue;\n\n for (const invokeDef of node.invoke) {\n const controller = new AbortController();\n const invokeId = invokeDef.id ?? String(++invokeCounter);\n const capturedContext = context_.value;\n const invokeInfo = { controller, event: triggerEvent, id: invokeId, path, state: state_.value };\n\n activeInvokes.add(invokeInfo);\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-start',\n });\n\n void invokeDef\n .src({ context: capturedContext, entryEvent: triggerEvent, signal: controller.signal })\n .then((result) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onDone) return;\n\n onDebug?.({\n context: capturedContext,\n event: triggerEvent,\n invokeId,\n result,\n state: state_.value,\n type: 'invoke-done',\n });\n\n queue.push({ event: invokeDef.onDone(result, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n })\n .catch((error: unknown) => {\n activeInvokes.delete(invokeInfo);\n\n if (disposed || controller.signal.aborted || !invokeDef.onError) return;\n\n onDebug?.({\n context: capturedContext,\n error,\n event: triggerEvent,\n invokeId,\n state: state_.value,\n type: 'invoke-error',\n });\n\n queue.push({ event: invokeDef.onError(error, capturedContext), tag: 'event' });\n\n if (!draining) drainQueue();\n });\n }\n }\n };\n\n // ── Section: After (delayed) transitions ───────────────────────────────────\n\n const scheduleAfterTransitions = (paths: readonly string[]): void => {\n for (const path of paths) {\n const node = getNodeAtPath(states, path) as StateNode<State, Ctx, Ev> | undefined;\n\n if (!node?.after?.length) continue;\n\n for (const afterDef of node.after) {\n const timer = setTimeout(() => {\n activeTimers.delete(entry);\n\n // A sibling-to-sibling transition elsewhere in the tree may have moved the leaf\n // while this timer's owning path stayed active — fire from wherever we are now,\n // and only if that path is still part of the live ancestor chain.\n if (disposed || !getAncestorPaths(state_.value).includes(path)) return;\n\n const from = state_.value;\n // R10: after.guard unified — receives { context, event } like all other guards\n const afterEvent = { delay: afterDef.delay, type: '$after' } as const;\n\n if (afterDef.guard && !afterDef.guard({ context: context_.value, event: afterEvent })) return;\n\n const resolvedTarget = resolveLeaf(states, afterDef.target) as State;\n\n queue.push({\n actions: (afterDef.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >,\n afterEvent,\n from,\n tag: 'after',\n target: resolvedTarget,\n });\n drainQueue();\n }, afterDef.delay);\n const entry = { path, timer };\n\n activeTimers.add(entry);\n }\n }\n };\n\n // ── Section: Event queue processing ─────────────────────────────────────────\n\n const processEvent = (item: QueueItem): boolean => {\n if (disposed) return false;\n\n if (item.tag === 'after') {\n executeTransition(item.from, item.target, item.actions, item.afterEvent);\n\n return true;\n }\n\n const from = state_.value;\n\n const transition = resolveTransition(\n definition,\n { context: context_.value, event: item.event, state: from },\n onDebug ? (info) => onDebug({ ...info, type: 'guard' }) : undefined,\n );\n\n if (!transition) {\n onDebug?.({ event: item.event, from, type: 'transition-skipped' });\n\n return false;\n }\n\n const resolvedTarget = resolveLeaf(states, transition.target) as State;\n const actions = (transition.actions ?? []) as Array<\n (args: { context: Ctx; readonly event: Ev | LifecycleEvent }) => void\n >;\n\n executeTransition(from, resolvedTarget, actions, item.event);\n\n return true;\n };\n\n const drainQueueInner = (): void => {\n let processed = 0;\n\n while (queue.length > 0) {\n if (++processed > maxTransitionsPerFlush) {\n throw new ClockworkTransitionLoopGuardError(\n 'transition queue exceeded maxTransitionsPerFlush',\n maxTransitionsPerFlush,\n );\n }\n\n processEvent(queue.shift()!);\n }\n };\n\n const drainQueue = (): void => {\n if (draining) return;\n\n draining = true;\n\n try {\n drainQueueInner();\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n // ── Section: Public API ────────────────────────────────────────────────────\n\n const can = (event: Ev): boolean => {\n if (disposed) return false;\n\n return !!resolveTransition(definition, { context: context_.value, event, state: state_.value });\n };\n\n const send = (event: Ev): SendResult => {\n if (disposed) {\n warn('send() called on a disposed machine — event ignored');\n\n return RESULT_REJECTED;\n }\n\n // Run interceptors left-to-right — first null wins\n let intercepted: Ev | null = event;\n\n for (const fn of interceptors) {\n intercepted = fn(intercepted, { context: context_.value, state: state_.value });\n\n if (intercepted === null) return RESULT_REJECTED;\n }\n\n const interceptedEvent = intercepted;\n\n if (draining) {\n queue.push({ event: interceptedEvent, tag: 'event' });\n\n return RESULT_QUEUED;\n }\n\n draining = true;\n\n try {\n const transitioned = processEvent({ event: interceptedEvent, tag: 'event' });\n\n drainQueueInner();\n\n return transitioned ? RESULT_TRANSITIONED : RESULT_REJECTED;\n } catch (err) {\n queue.length = 0;\n throw err;\n } finally {\n draining = false;\n }\n };\n\n const getSnapshot = (): MachineSnapshot<State, Ctx> =>\n Object.freeze({ context: clone(context_.value), state: state_.value });\n\n const getTrace = (): readonly TransitionTraceEntry<State, Ev>[] => trace?.get() ?? [];\n\n const matches = (...stateArgs: string[]): boolean => {\n if (disposed) return false;\n\n const current = state_.value;\n\n return stateArgs.some((s) => current === s || current.startsWith(`${s}.`));\n };\n\n // R5: subscribe via plain Set — no ripple effect(), no prevState/prevCtx tracking\n const subscribe = (fn: (snapshot: MachineSnapshot<State, Ctx>) => void): (() => void) => {\n subscribers.add(fn);\n\n return () => subscribers.delete(fn);\n };\n\n // ── Section: Initialization ────────────────────────────────────────────────\n\n const initialPaths = getAncestorPaths(resolvedInitial);\n\n if (persistedSnapshot) {\n runInvokes(HYDRATE_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n } else {\n const hasEntry = initialPaths.some((p) => getNodeAtPath(states, p)?.entry);\n\n if (hasEntry) {\n const initDraft = clone(context_.value);\n\n for (const p of initialPaths) {\n getNodeAtPath(states, p)?.entry?.({ context: initDraft, event: INIT_EVENT });\n }\n\n assertContext(initDraft, 'init');\n context_.value = initDraft;\n }\n\n runInvokes(INIT_EVENT, initialPaths);\n scheduleAfterTransitions(initialPaths);\n\n if (options.persistence) saveSnapshot();\n }\n\n const dispose = (): void => {\n if (disposed) return;\n\n disposed = true;\n disposeController.abort();\n stopInvokes();\n clearTimers();\n state_.dispose();\n context_.dispose();\n };\n\n return {\n can,\n context: readonly(context_),\n get disposalSignal() {\n return disposeController.signal;\n },\n dispose,\n get disposed() {\n return disposed;\n },\n getSnapshot,\n getTrace,\n matches,\n send,\n state: readonly(state_),\n subscribe,\n [Symbol.dispose]: dispose,\n };\n};\n\n// ── Public entry point ────────────────────────────────────────────────────────\n\n/**\n * Validates a machine configuration and returns a reusable definition handle.\n *\n * Call `.start(options?)` to create a running instance.\n * Call `.resolve(input, options?)` to inspect transitions without starting a machine.\n *\n * @example\n * const counterDef = createMachine({\n * context: { count: 0 },\n * initial: 'idle',\n * states: { idle: { on: { INC: { actions: [({ context }) => { context.count += 1 }], target: 'idle' } } } },\n * });\n *\n * const m1 = counterDef.start();\n * const m2 = counterDef.start({ snapshot: { context: { count: 10 }, state: 'idle' } });\n *\n * // Test transitions without a running machine:\n * counterDef.resolve({ context: { count: 0 }, event: { type: 'INC' }, state: 'idle' });\n *\n * // Or start immediately (one-shot):\n * const m3 = createMachine(config).start();\n */\nexport const createMachine = <State extends string, Ctx extends object, Ev extends MachineEvent>(\n config: MachineConfig<State, Ctx, Ev>,\n): MachineDefinition<State, Ctx, Ev> => {\n validateDefinition(config);\n\n return {\n resolve(input, options?) {\n return resolveTransition(config, input, options?.onGuard);\n },\n start(options?) {\n return _interpret(config, options);\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{batch as e,readonly as t,signal as n}from"@vielzeug/ripple";var r=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},i=class extends r{path;constructor(e,t,n){super(e,n),this.path=t}},a=class extends r{path;initial;constructor(e,t,n,r){super(e,r),this.path=t,this.initial=n}},o=class extends r{path;eventType;constructor(e,t,n,r){super(e,r),this.path=t,this.eventType=n}},s=class extends r{path;target;eventType;constructor(e,t,n,r,i){super(e,i),this.path=t,this.target=n,this.eventType=r}},c=class extends r{path;delay;constructor(e,t,n,r){super(e,r),this.path=t,this.delay=n}},l=class extends r{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},u=class extends r{state;constructor(e,t,n){super(e,n),this.state=t}},d=class extends r{phase;reason;constructor(e,t,n,r){super(e,r),this.phase=t,this.reason=n}},f=class extends r{maxTransitionsPerFlush;constructor(e,t,n){super(e,n),this.maxTransitionsPerFlush=t}},p=!globalThis.__CLOCKWORK_PROD__;function m(e){p&&console.warn(`[@vielzeug/clockwork] ${e}`)}function h(e){if(e<=0)return null;let t=[],n=0,r=0;return{get(){return r===0?[]:(r<e?t.slice(0,r):[...t.slice(n),...t.slice(0,n)]).map(e=>({...e}))},push(i){r<e?(t.push(i),r++):(t[n]=i,n=(n+1)%e)}}}var g=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:void 0,_=(e,t)=>{let n=t.split(`.`),r=g(e,n[0]);if(!r)return t;for(let e=1;e<n.length;e++)if(r=g(r.states,n[e]),!r)return t;let i=t;for(;r?.states&&r.initial;)i=`${i}.${r.initial}`,r=g(r.states,r.initial);return i},v=(e,t)=>{let n=t.split(`.`),r=g(e,n[0]);for(let e=1;e<n.length;e++){if(!r?.states)return;r=g(r.states,n[e])}return r},y=e=>{let t=e.split(`.`),n=[];for(let e=1;e<=t.length;e++)n.push(t.slice(0,e).join(`.`));return n},b=(e,t,n)=>{if(e.states&&!e.initial)throw new i(`compound state "${t}" must have an "initial" property`,t);if(e.initial&&e.states&&!Object.hasOwn(e.states,e.initial))throw new a(`compound state "${t}" initial "${e.initial}" not found in substates`,t,e.initial);for(let[r,i]of Object.entries(e.on??{})){let e=Array.isArray(i)?i:[i];if(e.length===0)throw new o(`state "${t}" event "${r}" must be a non-empty transition or transition array`,t,r);for(let i of e){let e=i.target.split(`.`)[0];if(!Object.hasOwn(n,e))throw new s(`state "${t}" event "${r}" targets unknown state "${i.target}"`,t,i.target,r);if(i.target.includes(`.`)&&!v(n,i.target))throw new s(`state "${t}" event "${r}" targets unknown nested state "${i.target}"`,t,i.target,r)}}if(e.invoke!==void 0&&e.invoke.length===0)throw new o(`state "${t}" invoke must be a non-empty array`,t);for(let r of e.after??[]){if(!Number.isFinite(r.delay)||r.delay<0)throw new c(`state "${t}" after delay must be a finite number >= 0, got ${r.delay}`,t,r.delay);let e=r.target.split(`.`)[0];if(!Object.hasOwn(n,e))throw new s(`state "${t}" after[${r.delay}ms] targets unknown state "${r.target}"`,t,r.target);if(r.target.includes(`.`)&&!v(n,r.target))throw new s(`state "${t}" after[${r.delay}ms] targets unknown nested state "${r.target}"`,t,r.target)}if(e.states)for(let[r,i]of Object.entries(e.states))b(i,`${t}.${r}`,n)},x=e=>{let{states:t}=e;if(!Object.hasOwn(t,e.initial))throw new a(`initial state "${e.initial}" not found in states`,``,e.initial);for(let[e,n]of Object.entries(t))b(n,e,t)},S={type:`$init`},C={type:`$hydrate`},w=(e,t,n)=>{let{context:r,event:i,state:a}=t;if(!i||typeof i.type!=`string`)return;let o=y(a);for(let t=o.length-1;t>=0;t--){let s=v(e.states,o[t]);if(!s?.on)continue;let c=i.type,l=Object.hasOwn(s.on,c)?s.on[c]:void 0;if(!l)continue;let u=Array.isArray(l)?l:[l];for(let e of u){let t=!e.guard||e.guard({context:r,event:i});if(n?.({context:r,event:i,from:a,passed:t,target:e.target}),t)return e}}},ee=Object.freeze({status:`transitioned`}),T=Object.freeze({status:`queued`}),E=Object.freeze({status:`rejected`}),D=(r,i={})=>{let a=i.onDebug,o=i.traceLimit??(a?50:0);if(i.maxTransitionsPerFlush!==void 0&&i.maxTransitionsPerFlush<1)throw new l(`maxTransitionsPerFlush must be greater than 0`,i.maxTransitionsPerFlush);let s=i.maxTransitionsPerFlush??1e3,c=i.clone??structuredClone,p=r.states,g=i.interceptors??[],b=i.snapshot??i.persistence?.load();if(b){let e=b.state.split(`.`)[0];if(!(Object.hasOwn(r.states,e)&&(!b.state.includes(`.`)||v(r.states,b.state))))throw new u(`snapshot state "${b.state}" not found in states`,b.state)}let x=(e,t)=>{let n=r.validateContext;if(!n)return;let i=n(e);if(i!==!0)throw new d(`context failed validation during ${t}${i?`: ${i}`:``}`,t,i)},D=b?b.state:_(p,r.initial),O=c(b?b.context:`context`in r?r.context:{});b||x(O,`init`);let k=n(D),A=n(O),j=h(o),M=new AbortController,N=!1,te=0,P=new Set,F=e=>{for(let t of P)e&&!e.includes(t.path)||(t.controller.abort(),a?.({context:A.value,event:t.event,invokeId:t.id,state:t.state,type:`invoke-abort`}),P.delete(t))},I=new Set,L=e=>{for(let t of I)e&&!e.includes(t.path)||(clearTimeout(t.timer),I.delete(t))},R=()=>{i.persistence?.save({context:c(A.value),state:k.value})},z=new Set,B=()=>{if(z.size===0)return;let e=Object.freeze({context:A.value,state:k.value});for(let t of z)t(e)},V=[],H=!1,U=(e,t)=>{if(!e.includes(`.`)&&!t.includes(`.`)||e===t)return{entryPaths:[t],exitPaths:[e]};let n=y(e),r=y(t),i=0;for(;i<n.length&&i<r.length&&n[i]===r[i];)i++;return{entryPaths:r.slice(i),exitPaths:n.slice(i).reverse()}},W=(t,n,r,i)=>{let{entryPaths:o,exitPaths:s}=U(t,n),l=c(A.value);for(let e of s)v(p,e)?.exit?.({context:l,event:i});for(let e of r)e({context:l,event:i});for(let e of o)v(p,e)?.entry?.({context:l,event:i});Object.freeze(l),x(l,`transition`),e(()=>{F(s),L(s),k.value=n,A.value=l}),a?.({event:i,from:t,to:n,type:`transition`}),j?.push({event:i,from:t,timestamp:Date.now(),to:n}),B(),R(),G(i,o),K(o)},G=(e,t)=>{for(let n of t){let t=v(p,n);if(t?.invoke?.length)for(let r of t.invoke){let t=new AbortController,i=r.id??String(++te),o=A.value,s={controller:t,event:e,id:i,path:n,state:k.value};P.add(s),a?.({context:o,event:e,invokeId:i,state:k.value,type:`invoke-start`}),r.src({context:o,entryEvent:e,signal:t.signal}).then(n=>{P.delete(s),!(N||t.signal.aborted||!r.onDone)&&(a?.({context:o,event:e,invokeId:i,result:n,state:k.value,type:`invoke-done`}),V.push({event:r.onDone(n,o),tag:`event`}),H||Y())}).catch(n=>{P.delete(s),!(N||t.signal.aborted||!r.onError)&&(a?.({context:o,error:n,event:e,invokeId:i,state:k.value,type:`invoke-error`}),V.push({event:r.onError(n,o),tag:`event`}),H||Y())})}}},K=e=>{for(let t of e){let e=v(p,t);if(e?.after?.length)for(let n of e.after){let e={path:t,timer:setTimeout(()=>{if(I.delete(e),N||!y(k.value).includes(t))return;let r=k.value,i={delay:n.delay,type:`$after`};if(n.guard&&!n.guard({context:A.value,event:i}))return;let a=_(p,n.target);V.push({actions:n.actions??[],afterEvent:i,from:r,tag:`after`,target:a}),Y()},n.delay)};I.add(e)}}},q=e=>{if(N)return!1;if(e.tag===`after`)return W(e.from,e.target,e.actions,e.afterEvent),!0;let t=k.value,n=w(r,{context:A.value,event:e.event,state:t},a?e=>a({...e,type:`guard`}):void 0);if(!n)return a?.({event:e.event,from:t,type:`transition-skipped`}),!1;let i=_(p,n.target),o=n.actions??[];return W(t,i,o,e.event),!0},J=()=>{let e=0;for(;V.length>0;){if(++e>s)throw new f(`transition queue exceeded maxTransitionsPerFlush`,s);q(V.shift())}},Y=()=>{if(!H){H=!0;try{J()}catch(e){throw V.length=0,e}finally{H=!1}}},X=e=>N?!1:!!w(r,{context:A.value,event:e,state:k.value}),Z=e=>{if(N)return m(`send() called on a disposed machine — event ignored`),E;let t=e;for(let e of g)if(t=e(t,{context:A.value,state:k.value}),t===null)return E;let n=t;if(H)return V.push({event:n,tag:`event`}),T;H=!0;try{let e=q({event:n,tag:`event`});return J(),e?ee:E}catch(e){throw V.length=0,e}finally{H=!1}},ne=()=>Object.freeze({context:c(A.value),state:k.value}),re=()=>j?.get()??[],ie=(...e)=>{if(N)return!1;let t=k.value;return e.some(e=>t===e||t.startsWith(`${e}.`))},ae=e=>(z.add(e),()=>z.delete(e)),Q=y(D);if(b)G(C,Q),K(Q);else{if(Q.some(e=>v(p,e)?.entry)){let e=c(A.value);for(let t of Q)v(p,t)?.entry?.({context:e,event:S});x(e,`init`),A.value=e}G(S,Q),K(Q),i.persistence&&R()}let $=()=>{N||(N=!0,M.abort(),F(),L(),k.dispose(),A.dispose())};return{can:X,context:t(A),get disposalSignal(){return M.signal},dispose:$,get disposed(){return N},getSnapshot:ne,getTrace:re,matches:ie,send:Z,state:t(k),subscribe:ae,[Symbol.dispose]:$}},O=e=>(x(e),{resolve(t,n){return w(e,t,n?.onGuard)},start(t){return D(e,t)}});export{r as ClockworkError,c as ClockworkInvalidAfterDelayError,a as ClockworkInvalidInitialStateError,l as ClockworkInvalidMaxTransitionsError,u as ClockworkInvalidSnapshotStateError,o as ClockworkInvalidTransitionArrayError,d as ClockworkInvalidValidateContextError,i as ClockworkMissingCompoundInitialError,f as ClockworkTransitionLoopGuardError,s as ClockworkUnknownTargetError,O as createMachine};
|
|
2
|
+
//# sourceMappingURL=clockwork.js.map
|