ihsm 0.0.13 → 0.0.19
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 +190 -6
- package/lib/cjs/index.d.ts +282 -0
- package/lib/cjs/index.js +331 -0
- package/lib/cjs/index.js.map +1 -0
- package/lib/cjs/internal/defs.private.d.ts +31 -0
- package/lib/cjs/internal/defs.private.js +3 -0
- package/lib/cjs/internal/defs.private.js.map +1 -0
- package/lib/cjs/internal/dispatch.debug.d.ts +4 -0
- package/lib/cjs/internal/dispatch.debug.js +330 -0
- package/lib/cjs/internal/dispatch.debug.js.map +1 -0
- package/lib/cjs/internal/dispatch.production.d.ts +6 -0
- package/lib/cjs/internal/dispatch.production.js +239 -0
- package/lib/cjs/internal/dispatch.production.js.map +1 -0
- package/lib/cjs/internal/dispatch.trace.d.ts +4 -0
- package/lib/cjs/internal/dispatch.trace.js +410 -0
- package/lib/cjs/internal/dispatch.trace.js.map +1 -0
- package/lib/cjs/internal/hsm.d.ts +54 -0
- package/lib/cjs/internal/hsm.js +182 -0
- package/lib/cjs/internal/hsm.js.map +1 -0
- package/lib/cjs/internal/utils.d.ts +18 -0
- package/lib/cjs/internal/utils.js +51 -0
- package/lib/cjs/internal/utils.js.map +1 -0
- package/lib/cjs/package.json +3 -0
- package/lib/esm/index.d.ts +282 -0
- package/lib/esm/index.js +314 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/internal/defs.private.d.ts +31 -0
- package/lib/esm/internal/defs.private.js +2 -0
- package/lib/esm/internal/defs.private.js.map +1 -0
- package/lib/esm/internal/dispatch.debug.d.ts +4 -0
- package/lib/esm/internal/dispatch.debug.js +326 -0
- package/lib/esm/internal/dispatch.debug.js.map +1 -0
- package/lib/esm/internal/dispatch.production.d.ts +6 -0
- package/lib/esm/internal/dispatch.production.js +235 -0
- package/lib/esm/internal/dispatch.production.js.map +1 -0
- package/lib/esm/internal/dispatch.trace.d.ts +4 -0
- package/lib/esm/internal/dispatch.trace.js +406 -0
- package/lib/esm/internal/dispatch.trace.js.map +1 -0
- package/lib/esm/internal/hsm.d.ts +54 -0
- package/lib/esm/internal/hsm.js +178 -0
- package/lib/esm/internal/hsm.js.map +1 -0
- package/lib/esm/internal/utils.d.ts +18 -0
- package/lib/esm/internal/utils.js +41 -0
- package/lib/esm/internal/utils.js.map +1 -0
- package/lib/esm/package.json +3 -0
- package/package.json +114 -66
- package/lib/index.browser.js +0 -523
- package/lib/index.d.ts +0 -105
- package/lib/index.js +0 -374
- package/tsconfig.json +0 -72
package/README.md
CHANGED
|
@@ -1,9 +1,193 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
[](https://github.com/filasieno/ihsm/actions/workflows/ci.yml)
|
|
2
|
+
[](https://github.com/filasieno/ihsm/actions/workflows/docs.yml)
|
|
3
|
+
[](https://coveralls.io/github/filasieno/ihsm)
|
|
4
|
+
[](https://github.com/filasieno/ihsm/blob/HEAD/LICENSE)
|
|
5
|
+
[](https://www.npmjs.com/package/ihsm)
|
|
6
|
+
[](https://github.com/filasieno/ihsm/blob/HEAD/package.json)
|
|
7
|
+
|
|
8
|
+
# ihsm
|
|
9
|
+
|
|
10
|
+
An idiomatic hierarchical state machine package for TypeScript — **Samek/QP-style** class hierarchy with
|
|
11
|
+
**cached LCA transitions**, **zero production dependencies**, and **100% code coverage** on the runtime.
|
|
12
|
+
|
|
13
|
+
## Quality
|
|
14
|
+
|
|
15
|
+
| Metric | Value |
|
|
16
|
+
|--------|-------|
|
|
17
|
+
| **Statements** | 100% |
|
|
18
|
+
| **Branches** | 100% |
|
|
19
|
+
| **Functions** | 100% |
|
|
20
|
+
| **Lines** | 100% |
|
|
21
|
+
|
|
22
|
+
CI enforces full coverage on every push (`nix flake check`).
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- User-defined event payloads (typed `Protocol`)
|
|
27
|
+
- User-defined state context (`ctx`)
|
|
28
|
+
- Hierarchically nested states (class inheritance)
|
|
29
|
+
- Orthogonal regions (nest multiple machines; compose via `post`/`call`)
|
|
30
|
+
- Internal transitions (handle event without calling `transition()`)
|
|
31
|
+
- Explicit transitions with cached entry/exit sequences
|
|
32
|
+
- Guards (inline `if` in handlers)
|
|
33
|
+
- History (`ctx` + `restore()`)
|
|
34
|
+
- Entry / exit actions (`onEntry`, `onExit`)
|
|
35
|
+
- Async and sync handlers
|
|
36
|
+
- **`call()` — typed request/response through the actor mailbox** (unique)
|
|
37
|
+
- **`then()` — decision pseudo-states with automatic follow-up transitions**
|
|
38
|
+
- **`postNow()` — hi-priority extended transitions within the same dispatch**
|
|
39
|
+
- Actor-style messaging (`post`, `deferredPost`, serialized queue)
|
|
40
|
+
- Structured errors and trace levels
|
|
41
|
+
|
|
42
|
+
## Documentation
|
|
43
|
+
|
|
44
|
+
| Resource | Link |
|
|
45
|
+
|----------|------|
|
|
46
|
+
| **Documentation site** | [filasieno.github.io/ihsm](https://filasieno.github.io/ihsm/) — reference manual + interactive tutorials |
|
|
47
|
+
| Reference (source) | [reference/REFERENCE.md](./reference/REFERENCE.md) |
|
|
48
|
+
| Tutorials (source) | [tutorials/](./tutorials/) |
|
|
49
|
+
| Examples | [`src/spec/`](./src/spec/) |
|
|
50
|
+
| Code of conduct | [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md) |
|
|
51
|
+
| Security | [SECURITY.md](./SECURITY.md) |
|
|
52
|
+
|
|
53
|
+
Each tutorial page on the documentation site combines prose, code samples, and an embedded playground
|
|
54
|
+
(sender/message forms, live trace, reset). The same machines are verified headlessly by Mocha specs under
|
|
55
|
+
`tutorials/*/tutorial.spec.ts`.
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
```shell
|
|
60
|
+
npm install ihsm@latest
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Runtime support
|
|
64
|
+
|
|
65
|
+
ihsm ships modern **ES2022** ESM and CommonJS — no transpiled legacy (ES5/ES2015)
|
|
66
|
+
output and no polyfills. Supported runtimes:
|
|
67
|
+
|
|
68
|
+
| Runtime | Minimum |
|
|
69
|
+
| ------- | ------- |
|
|
70
|
+
| Node.js | **22+** |
|
|
71
|
+
| Chrome / Edge | **94+** |
|
|
72
|
+
| Firefox | **93+** |
|
|
73
|
+
| Safari (macOS / iOS) | **15.4+** |
|
|
74
|
+
|
|
75
|
+
Older browsers and JavaScript engines are intentionally **not** supported. If you
|
|
76
|
+
must target them, transpile `ihsm` yourself with your bundler (the published
|
|
77
|
+
`browserslist` field declares this baseline for downstream tooling).
|
|
78
|
+
|
|
79
|
+
## Requirements
|
|
80
|
+
|
|
81
|
+
**[Nix](https://nixos.org/download/)** with flakes enabled — the only prerequisite to build and test
|
|
82
|
+
from source.
|
|
83
|
+
|
|
84
|
+
## Building
|
|
85
|
+
|
|
86
|
+
```shell
|
|
87
|
+
git clone https://github.com/filasieno/ihsm.git
|
|
88
|
+
cd ihsm
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Development environment
|
|
92
|
+
|
|
93
|
+
**Always use the Nix dev shell** before running npm scripts. It provides Node 22,
|
|
94
|
+
PlantUML, Graphviz, and a store-pinned `node_modules` symlink (same lockfile as CI).
|
|
95
|
+
|
|
96
|
+
```shell
|
|
97
|
+
nix develop
|
|
98
|
+
# or: direnv allow # .envrc → use flake; auto-enters the shell in supported terminals
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Run npm commands **inside** that shell, or prefix each one with `nix develop --command`:
|
|
102
|
+
|
|
103
|
+
```shell
|
|
104
|
+
nix develop --command npm test
|
|
6
105
|
```
|
|
7
106
|
|
|
8
|
-
|
|
107
|
+
If you see `remove local node_modules/ to use Nix store deps`, delete a plain
|
|
108
|
+
`npm install` tree: `rm -rf node_modules` and enter `nix develop` again.
|
|
109
|
+
|
|
110
|
+
### Nix commands (CI parity)
|
|
111
|
+
|
|
112
|
+
| Command | Purpose |
|
|
113
|
+
| ------- | ------- |
|
|
114
|
+
| `nix flake check` | Full CI gate: library compile, unit + tutorial tests, lint, docs site |
|
|
115
|
+
| `nix build` | Compile library and run tests → `result/lib/` |
|
|
116
|
+
| `nix build .#lint` | TypeScript (full solution), ESLint, Prettier |
|
|
117
|
+
| `nix build .#docs` | Production documentation site → `result/share/doc/ihsm/` |
|
|
118
|
+
|
|
119
|
+
Full check before opening a PR:
|
|
120
|
+
|
|
121
|
+
```shell
|
|
122
|
+
nix flake check
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
After `nix build .#docs`, copy artifacts from `result/share/doc/ihsm/` or run
|
|
126
|
+
`bash scripts/verify-docs-site.sh result/share/doc/ihsm`.
|
|
127
|
+
|
|
128
|
+
### npm scripts
|
|
129
|
+
|
|
130
|
+
All commands below assume **`nix develop`** (interactive shell) or
|
|
131
|
+
**`nix develop --command …`** (one-shot). See [website/README.md](./website/README.md)
|
|
132
|
+
for docs-site layout and generated output.
|
|
133
|
+
|
|
134
|
+
#### Build
|
|
135
|
+
|
|
136
|
+
| Command | Purpose |
|
|
137
|
+
| ------- | ------- |
|
|
138
|
+
| `npm run build` | Compile the publishable library → `lib/cjs/` (CommonJS) and `lib/esm/` (ESM), then finalize |
|
|
139
|
+
| `npm run build-cjs` | Compile the CommonJS tree only → `lib/cjs/` |
|
|
140
|
+
| `npm run build-esm` | Compile the ESM tree only → `lib/esm/` |
|
|
141
|
+
| `npm run clean` | Remove generated artifacts (`lib/`, `.tsc/`, coverage, `docs-build/`, `website/docs/`, …) |
|
|
142
|
+
| `npm run dist` | Clean, then build library and documentation site (maintainer bundle) |
|
|
143
|
+
|
|
144
|
+
#### Test
|
|
145
|
+
|
|
146
|
+
| Command | Purpose |
|
|
147
|
+
| ------- | ------- |
|
|
148
|
+
| `npm test` | Unit tests in Node (`src/spec/`) with NYC coverage, then the same specs minified in headless Chromium |
|
|
149
|
+
| `npm run test:node` | Node-only unit tests (with coverage) |
|
|
150
|
+
| `npm run test:browser` | Minified browser bundles for unit + tutorial specs (Playwright + esbuild) |
|
|
151
|
+
| `npm run test:tutorials` | Tutorial specs in Node, then minified in the browser |
|
|
152
|
+
| `npm run test:all` | `npm test` + `npm run test:tutorials` (both environments) |
|
|
153
|
+
| `npm run coverage` | Print an LCOV coverage report from the last `npm run test:node` run |
|
|
154
|
+
|
|
155
|
+
First-time browser setup: `npx playwright install chromium`.
|
|
156
|
+
|
|
157
|
+
#### Quality
|
|
158
|
+
|
|
159
|
+
| Command | Purpose |
|
|
160
|
+
| ------- | ------- |
|
|
161
|
+
| `npm run typecheck` | Type-check the full project graph (CJS lib, ESM lib, tutorials, website); runs `sync:docs` first |
|
|
162
|
+
| `npm run lint` | Typecheck, then ESLint and Prettier check |
|
|
163
|
+
| `npm run prettier` | Auto-format TypeScript sources (`src/`, `tutorials/`, `website/`) |
|
|
164
|
+
| `npm run verify:source` | Fail if generated output (compiled `.js`/`.d.ts`, docs) appears in the source tree |
|
|
165
|
+
| `npm run release:check` | Local release gate: `test:all`, lint, build, doc, and `verify:doc` |
|
|
166
|
+
|
|
167
|
+
#### Documentation
|
|
168
|
+
|
|
169
|
+
| Command | Purpose |
|
|
170
|
+
| ------- | ------- |
|
|
171
|
+
| `npm run sync:docs` | Generate gitignored site inputs: `website/docs/`, `website/sidebars.ts`, PlantUML SVGs |
|
|
172
|
+
| `npm run doc` | `sync:docs`, then production Docusaurus build (website workspace) |
|
|
173
|
+
| `npm run doc:preview` | `sync:docs`, then Docusaurus dev server at [localhost:3010/ihsm/](http://localhost:3010/ihsm/) |
|
|
174
|
+
| `npm run doc:site` | `sync:docs`, then static site → `docs-build/` |
|
|
175
|
+
| `npm run verify:doc` | Sanity-check `docs-build/` (links, assets, tutorial pages) |
|
|
176
|
+
|
|
177
|
+
Release process: [RELEASING.md](./RELEASING.md).
|
|
178
|
+
|
|
179
|
+
## Contributing
|
|
180
|
+
|
|
181
|
+
Contributions are welcome — bug reports, docs, and code.
|
|
182
|
+
|
|
183
|
+
- Bug reports → [issue template](https://github.com/filasieno/ihsm/issues/new?template=bug_report.yml)
|
|
184
|
+
- Features → [issue template](https://github.com/filasieno/ihsm/issues/new?template=feature_request.yml)
|
|
185
|
+
- Security → [GitHub Security Advisories](https://github.com/filasieno/ihsm/security/advisories/new) (not public issues)
|
|
186
|
+
|
|
187
|
+
Please follow [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md). New behavior needs tests in `src/spec/`; tutorial changes need matching specs under `tutorials/`.
|
|
188
|
+
|
|
189
|
+
**Generated output is never committed** — only sources (`src/`, `tutorials/`, `reference/`, `website/docs-src/`). CI runs `scripts/verify-no-generated-in-source.sh`. Build artifacts (`lib/`, `website/docs/`, `docs-build/`, …) are gitignored and produced by Nix/npm.
|
|
190
|
+
|
|
191
|
+
## License
|
|
9
192
|
|
|
193
|
+
[MIT](./LICENSE) © Fabio N. Filasieno, Roberto Boati
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default context and protocol map when a machine is created without explicit typing.
|
|
3
|
+
* @category Factory
|
|
4
|
+
*/
|
|
5
|
+
export type Any = Record<string, any>;
|
|
6
|
+
/**
|
|
7
|
+
* Rejects an async {@link Hsm.call} service with an error.
|
|
8
|
+
* @category Event handler
|
|
9
|
+
*/
|
|
10
|
+
export type RejectCallback = (error: Error) => void;
|
|
11
|
+
/**
|
|
12
|
+
* Resolves an async {@link Hsm.call} service with a typed reply.
|
|
13
|
+
* @category Event handler
|
|
14
|
+
*/
|
|
15
|
+
export type ResolveCallback<Reply> = (result: Reply) => void;
|
|
16
|
+
/**
|
|
17
|
+
* Called when event dispatch fails and the runtime does not recover via `onError`.
|
|
18
|
+
* @category Factory
|
|
19
|
+
*/
|
|
20
|
+
export interface DispatchErrorCallback<Context, Protocol extends {} | undefined> {
|
|
21
|
+
(hsm: Base<Context, Protocol>, err: Error): void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Trace verbosity for dispatch logging.
|
|
25
|
+
* @category Factory
|
|
26
|
+
*/
|
|
27
|
+
export declare enum TraceLevel {
|
|
28
|
+
PRODUCTION = 0,
|
|
29
|
+
DEBUG = 1,
|
|
30
|
+
VERBOSE_DEBUG = 2
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Receives trace lines from the runtime and from handlers via `this.traceWriter.write`.
|
|
34
|
+
* @category Factory
|
|
35
|
+
*/
|
|
36
|
+
export interface TraceWriter {
|
|
37
|
+
write<Context, Protocol extends {} | undefined>(hsm: Properties<Context, Protocol>, msg: any): void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @category State machine
|
|
41
|
+
*/
|
|
42
|
+
export interface Properties<Context, Protocol extends {} | undefined> {
|
|
43
|
+
readonly currentState: StateClass<Context, Protocol>;
|
|
44
|
+
readonly currentStateName: string;
|
|
45
|
+
readonly topState: StateClass<Context, Protocol>;
|
|
46
|
+
readonly topStateName: string;
|
|
47
|
+
readonly ctxTypeName: string;
|
|
48
|
+
readonly traceHeader: string;
|
|
49
|
+
readonly eventName: string;
|
|
50
|
+
readonly eventPayload: any[];
|
|
51
|
+
traceLevel: TraceLevel;
|
|
52
|
+
traceWriter: TraceWriter;
|
|
53
|
+
dispatchErrorCallback: DispatchErrorCallback<Context, Protocol>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @category State machine
|
|
57
|
+
*/
|
|
58
|
+
export interface Base<Context, Protocol extends {} | undefined> extends Properties<Context, Protocol> {
|
|
59
|
+
post<EventName extends keyof Protocol>(eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
60
|
+
deferredPost<EventName extends keyof Protocol>(millis: number, eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @category State machine
|
|
64
|
+
*/
|
|
65
|
+
export interface State<Context, Protocol extends {} | undefined> extends Base<Context, Protocol> {
|
|
66
|
+
readonly ctx: Context;
|
|
67
|
+
transition(nextState: StateClass<Context, Protocol>): void;
|
|
68
|
+
unhandled(): never;
|
|
69
|
+
sleep(millis: number): Promise<void>;
|
|
70
|
+
/** Handler-only: queue an event on the internal high-priority mailbox (before normal `post`). */
|
|
71
|
+
postNow<EventName extends keyof Protocol>(eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Actor handle returned by {@link makeHsm} — client API (`post`, `call`, `sync`, `restore`).
|
|
75
|
+
* @category State machine
|
|
76
|
+
*/
|
|
77
|
+
export interface Hsm<Context = Any, Protocol extends {} | undefined = undefined> extends Base<Context, Protocol> {
|
|
78
|
+
readonly ctx: Context;
|
|
79
|
+
sync(): Promise<void>;
|
|
80
|
+
restore(state: StateClass<Context, Protocol>, ctx: Context): void;
|
|
81
|
+
call<EventName extends keyof Protocol>(eventName: ServiceName<Protocol, EventName>, ...eventPayload: ServiceRequest<Protocol, EventName>): Promise<ServiceResponse<Protocol, EventName>>;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* @category Event handler
|
|
85
|
+
*/
|
|
86
|
+
export type PostedEvent<Protocol extends {} | undefined, EventName extends keyof Protocol> = Protocol extends undefined ? string : EventName extends keyof State<any, any> ? never : EventName;
|
|
87
|
+
/**
|
|
88
|
+
* @category Event handler
|
|
89
|
+
*/
|
|
90
|
+
export type EventPayload<Protocol extends {} | undefined, EventName extends keyof Protocol> = Protocol extends undefined ? any[] : Protocol[EventName] extends (...payload: infer Payload) => Promise<void> | void ? (Payload extends any[] ? Payload : never) : never;
|
|
91
|
+
/**
|
|
92
|
+
* Constructor type for a state class in the machine hierarchy.
|
|
93
|
+
* @category State machine
|
|
94
|
+
*/
|
|
95
|
+
export type StateClass<Context = Any, Protocol extends {} | undefined = undefined> = Function & {
|
|
96
|
+
prototype: TopState<Context, Protocol>;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
*
|
|
100
|
+
*/
|
|
101
|
+
export type ServiceRequest<Protocol, EventName extends keyof Protocol> = Protocol extends undefined ? any[] : Protocol[EventName] extends (resolve: (result: infer Reply) => void, reject: (error: infer Error) => void, ...payload: infer Payload) => Promise<void> | void ? (Payload extends any[] ? Payload : never) : never;
|
|
102
|
+
/**
|
|
103
|
+
*
|
|
104
|
+
*/
|
|
105
|
+
export type ServiceResponse<Protocol, EventName extends keyof Protocol> = Protocol extends undefined ? any : Protocol[EventName] extends (resolve: infer Reply, reject: infer Error, ...payload: infer Payload) => Promise<void> | void ? Reply : never;
|
|
106
|
+
/**
|
|
107
|
+
*
|
|
108
|
+
*/
|
|
109
|
+
export type ServiceName<Protocol, EventName> = Protocol extends undefined ? string : EventName extends keyof State<any, any> ? never : EventName;
|
|
110
|
+
/**
|
|
111
|
+
* Optional lifecycle hooks implemented by state classes (`onEntry`, `onExit`, …).
|
|
112
|
+
* @category State machine
|
|
113
|
+
*/
|
|
114
|
+
export interface StateEvents<Context, Protocol extends {} | undefined> {
|
|
115
|
+
onExit(): Promise<void> | void;
|
|
116
|
+
onEntry(): Promise<void> | void;
|
|
117
|
+
onError<EventName extends keyof Protocol>(error: RuntimeError<Context, Protocol, EventName>): Promise<void> | void;
|
|
118
|
+
onUnhandled<EventName extends keyof Protocol>(error: UnhandledEventError<Context, Protocol, EventName>): Promise<void> | void;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Root of the state class hierarchy; hosts mailbox machinery. Subclass or pass to {@link makeHsm}.
|
|
122
|
+
* @category State machine
|
|
123
|
+
*/
|
|
124
|
+
export declare abstract class TopState<Context = Any, Protocol extends {} | undefined = undefined> implements State<Context, Protocol>, StateEvents<Context, Protocol> {
|
|
125
|
+
readonly ctx: Context;
|
|
126
|
+
readonly hsm: State<Context, Protocol>;
|
|
127
|
+
constructor();
|
|
128
|
+
get eventName(): string;
|
|
129
|
+
get eventPayload(): any[];
|
|
130
|
+
get traceHeader(): string;
|
|
131
|
+
get topState(): StateClass<Context, Protocol>;
|
|
132
|
+
get currentStateName(): string;
|
|
133
|
+
get currentState(): StateClass<Context, Protocol>;
|
|
134
|
+
get ctxTypeName(): string;
|
|
135
|
+
set traceLevel(value: TraceLevel);
|
|
136
|
+
get traceLevel(): TraceLevel;
|
|
137
|
+
get topStateName(): string;
|
|
138
|
+
get traceWriter(): TraceWriter;
|
|
139
|
+
set traceWriter(value: TraceWriter);
|
|
140
|
+
get dispatchErrorCallback(): DispatchErrorCallback<Context, Protocol>;
|
|
141
|
+
set dispatchErrorCallback(value: DispatchErrorCallback<Context, Protocol>);
|
|
142
|
+
transition(nextState: StateClass<Context, Protocol>): void;
|
|
143
|
+
unhandled(): never;
|
|
144
|
+
sleep(millis: number): Promise<void>;
|
|
145
|
+
post<EventName extends keyof Protocol>(eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
146
|
+
deferredPost<EventName extends keyof Protocol>(millis: number, eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
147
|
+
postNow<EventName extends keyof Protocol>(eventName: PostedEvent<Protocol, EventName>, ...eventPayload: EventPayload<Protocol, EventName>): void;
|
|
148
|
+
onExit(): Promise<void> | void;
|
|
149
|
+
onEntry(): Promise<void> | void;
|
|
150
|
+
onError<EventName extends keyof Protocol>(error: RuntimeError<Context, Protocol, EventName>): Promise<void> | void;
|
|
151
|
+
onUnhandled<EventName extends keyof Protocol>(error: UnhandledEventError<Context, Protocol, EventName>): Promise<void> | void;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @category Error
|
|
155
|
+
*/
|
|
156
|
+
export declare abstract class HsmError<Context, Protocol extends {} | undefined> extends Error {
|
|
157
|
+
name: string;
|
|
158
|
+
topStateName: string;
|
|
159
|
+
stateName: string;
|
|
160
|
+
context: Context;
|
|
161
|
+
cause?: Error;
|
|
162
|
+
protected constructor(name: string, hsm: State<Context, Protocol>, message: string, cause?: Error);
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* @category Error
|
|
166
|
+
*/
|
|
167
|
+
export declare abstract class RuntimeError<Context, Protocol extends {} | undefined, EventName extends keyof Protocol> extends HsmError<Context, Protocol> {
|
|
168
|
+
eventName: PostedEvent<Protocol, EventName>;
|
|
169
|
+
eventPayload: EventPayload<Protocol, EventName>;
|
|
170
|
+
protected constructor(errorName: string, hsm: State<Context, Protocol>, message: string, cause?: Error);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* @category Error
|
|
174
|
+
*/
|
|
175
|
+
export declare class TransitionError<Context, Protocol extends {} | undefined, EventName extends keyof Protocol> extends RuntimeError<Context, Protocol, EventName> {
|
|
176
|
+
failedStateName: string;
|
|
177
|
+
failedCallback: 'onExit' | 'onEntry';
|
|
178
|
+
fromStateName: string;
|
|
179
|
+
toStateName: string;
|
|
180
|
+
constructor(hsm: State<Context, Protocol>, cause: Error, failedStateName: string, failedCallback: 'onExit' | 'onEntry', fromStateName: string, toStateName: string);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* @category Error
|
|
184
|
+
*/
|
|
185
|
+
export declare class EventHandlerError<Context, Protocol extends {} | undefined, EventName extends keyof Protocol> extends RuntimeError<Context, Protocol, EventName> {
|
|
186
|
+
constructor(hsm: State<Context, Protocol>, cause: Error);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* @category Error
|
|
190
|
+
*/
|
|
191
|
+
export declare class UnhandledEventError<Context, Protocol extends {} | undefined, EventName extends keyof Protocol> extends RuntimeError<Context, Protocol, EventName> {
|
|
192
|
+
constructor(hsm: State<Context, Protocol>);
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* @category Error
|
|
196
|
+
*/
|
|
197
|
+
export declare class InitialStateError<Context, Protocol extends {} | undefined> extends Error {
|
|
198
|
+
targetStateName: string;
|
|
199
|
+
constructor(targetState: StateClass<Context, Protocol>);
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* @category Error
|
|
203
|
+
*/
|
|
204
|
+
export declare class FatalError<Context, Protocol extends {} | undefined, EventName extends keyof Protocol> extends RuntimeError<Context, Protocol, EventName> {
|
|
205
|
+
constructor(hsm: State<Context, Protocol>, cause: Error);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* @category Error
|
|
209
|
+
*/
|
|
210
|
+
export declare class InitializationError<Context, Protocol extends {} | undefined> extends HsmError<Context, Protocol> {
|
|
211
|
+
failedState: StateClass<Context, Protocol>;
|
|
212
|
+
constructor(hsm: State<Context, Protocol>, failedState: StateClass<Context, Protocol>, cause: Error);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Terminal error state class used when the machine cannot recover.
|
|
216
|
+
* @category State machine
|
|
217
|
+
*/
|
|
218
|
+
export declare class FatalErrorState<Context, Protocol extends {} | undefined> extends TopState<Context, Protocol> {
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Marks `TargetState` as the initial substate of its parent composite state.
|
|
222
|
+
* @category Factory
|
|
223
|
+
*/
|
|
224
|
+
export declare function InitialState<Context, Protocol extends {} | undefined>(TargetState: StateClass<Context, Protocol>): void;
|
|
225
|
+
/**
|
|
226
|
+
* Assigns a stable display name to a state class.
|
|
227
|
+
*
|
|
228
|
+
* Minifiers (and browser production bundles) rewrite class names, so the
|
|
229
|
+
* built-in `Class.name` is unreliable in optimized builds. Registering an
|
|
230
|
+
* explicit name keeps {@link Properties.currentStateName},
|
|
231
|
+
* {@link Properties.topStateName}, trace output, and error messages stable in
|
|
232
|
+
* every environment (Node and minified browsers alike).
|
|
233
|
+
*
|
|
234
|
+
* The name is stored as a non-enumerable, non-inherited own property, so it is
|
|
235
|
+
* never accidentally shared with subclasses through the prototype chain.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* class Door extends TopState {}
|
|
240
|
+
* defineStateName(Door, 'Door');
|
|
241
|
+
* ```
|
|
242
|
+
* @category State machine
|
|
243
|
+
*/
|
|
244
|
+
export declare function defineStateName<Context, Protocol extends {} | undefined>(state: StateClass<Context, Protocol>, name: string): void;
|
|
245
|
+
/**
|
|
246
|
+
* Registers stable display names for every state class found in an exports map,
|
|
247
|
+
* using the export key as the display name.
|
|
248
|
+
*
|
|
249
|
+
* This is the convenient way to make a whole machine module minification-safe:
|
|
250
|
+
* pass the module namespace (or an object literal of the state classes) and
|
|
251
|
+
* each state class gets its export key as its display name. Non state-class
|
|
252
|
+
* values (factory functions, interfaces compiled away, constants) are ignored.
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```ts
|
|
256
|
+
* // machine.ts
|
|
257
|
+
* export class DoorTop extends TopState {}
|
|
258
|
+
* export class Open extends DoorTop {}
|
|
259
|
+
* export class Closed extends DoorTop {}
|
|
260
|
+
* registerStateNames({ DoorTop, Open, Closed });
|
|
261
|
+
* ```
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* // from another module
|
|
265
|
+
* import * as machine from './machine';
|
|
266
|
+
* registerStateNames(machine);
|
|
267
|
+
* ```
|
|
268
|
+
* @category State machine
|
|
269
|
+
*/
|
|
270
|
+
export declare function registerStateNames(exports: Record<string, unknown>): void;
|
|
271
|
+
/**
|
|
272
|
+
* Creates a state machine instance bound to the given context object.
|
|
273
|
+
*
|
|
274
|
+
* @param topState - Root state class
|
|
275
|
+
* @param ctx - Mutable domain context
|
|
276
|
+
* @param initialize - When `true`, walk `@InitialState` chain and run `onEntry` on the path to the initial leaf (default `true`)
|
|
277
|
+
* @param traceLevel - Trace verbosity (default {@link TraceLevel.DEBUG})
|
|
278
|
+
* @param traceWriter - Trace sink (default console logger)
|
|
279
|
+
* @param dispatchErrorCallback - Hook when dispatch throws and is not recovered (default: log and rethrow)
|
|
280
|
+
* @category Factory
|
|
281
|
+
*/
|
|
282
|
+
export declare function makeHsm<Context, Protocol extends undefined | {}>(topState: StateClass<Context, Protocol>, ctx: Context, initialize?: boolean, traceLevel?: TraceLevel, traceWriter?: TraceWriter, dispatchErrorCallback?: DispatchErrorCallback<Context, Protocol>): Hsm<Context, Protocol>;
|