aifsmjs 0.3.1 → 0.4.1
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 +5 -5
- package/README_ZHTW.md +5 -5
- package/llms-full.txt +46 -5
- package/package.json +1 -2
- package/STABILITY.md +0 -77
package/README.md
CHANGED
|
@@ -107,7 +107,7 @@ The three layers are fully decoupled: take `step()` alone for replay, take `Mach
|
|
|
107
107
|
| Will do (v1) | Won't do |
|
|
108
108
|
| --------------------------------------------------- | ------------------------------------------------- |
|
|
109
109
|
| Flat states + transitions | Parallel state regions |
|
|
110
|
-
| Hierarchical sugar via `state.sub` (
|
|
110
|
+
| Hierarchical sugar via `state.sub` (stable since 0.4.0) | Closures embedded in definition (breaks serialize) |
|
|
111
111
|
| Guards (sync only; inline async throws `InvalidDefinitionError` at `defineMachine`; runtime throws `AsyncGuardError` on thenable return) | Async guards |
|
|
112
112
|
| Actions (assign + enqueue effects) | Async API inside an action (use an effect) |
|
|
113
113
|
| Fire-and-forget effects | Actor invocation / spawn |
|
|
@@ -357,7 +357,7 @@ Non-goals:
|
|
|
357
357
|
- No async lifecycle hook
|
|
358
358
|
- Inspect middleware cannot alter the transition outcome
|
|
359
359
|
|
|
360
|
-
### Sub-machine lifecycle (since 0.
|
|
360
|
+
### Sub-machine lifecycle (stable since 0.4.0)
|
|
361
361
|
|
|
362
362
|
When a state declares `sub`, the per-transition ordering is:
|
|
363
363
|
|
|
@@ -497,8 +497,8 @@ Example-first, PBT-augmented. Lesson from jssm: "3000+ tests / 100% coverage" tu
|
|
|
497
497
|
| ------- | ------------------------------------------------------------------ |
|
|
498
498
|
| v0.1 | core + guards + effects + inspect + replay + pbt (this release) |
|
|
499
499
|
| v0.2 | Async-guard detection, coverage tuning, llms-full.txt verify gate |
|
|
500
|
-
| v0.3 | Hierarchical sugar via `state.sub` (experimental
|
|
501
|
-
| v0.4 |
|
|
500
|
+
| v0.3 | Hierarchical sugar via `state.sub` (experimental) |
|
|
501
|
+
| v0.4 | Sub-machine API promoted to stable; dependency-reduction cycle |
|
|
502
502
|
| v0.5 | `aifsmjs-bridge-bitecs` / `aifsmjs-bridge-pixi` (separate sub-packages) |
|
|
503
503
|
| v1.0 | API freeze and stability guarantee |
|
|
504
504
|
|
|
@@ -509,7 +509,7 @@ Example-first, PBT-augmented. Lesson from jssm: "3000+ tests / 100% coverage" tu
|
|
|
509
509
|
- **Tick / game-loop hook** (out of scope for v1)
|
|
510
510
|
- **ECS / Pixi bridges** (out of scope for v1)
|
|
511
511
|
|
|
512
|
-
**
|
|
512
|
+
**Future candidate**: `historyState` — remember last active sub-state on
|
|
513
513
|
re-entry. Workaround today: snapshot via `onTransition` and restore
|
|
514
514
|
manually.
|
|
515
515
|
|
package/README_ZHTW.md
CHANGED
|
@@ -106,7 +106,7 @@ console.log(runtime.getSnapshot().context); // { ticks: 1 }
|
|
|
106
106
|
| 會做(v1) | 不會做 |
|
|
107
107
|
| --------------------------------------------------- | ------------------------------------------------- |
|
|
108
108
|
| Flat states + transitions | Parallel state regions |
|
|
109
|
-
| 透過 `state.sub` 的階層式 sugar(
|
|
109
|
+
| 透過 `state.sub` 的階層式 sugar(stable since 0.4.0) | Definition 內直接綁 closure(會無法序列化) |
|
|
110
110
|
| Guards(sync only;inline async 在 `defineMachine` 時丟 `InvalidDefinitionError`;runtime 偵測到 thenable 回傳則丟 `AsyncGuardError`) | Async guards |
|
|
111
111
|
| Actions(assign + enqueue effects) | 在 action 內呼叫 async API(請放到 effect) |
|
|
112
112
|
| Fire-and-forget effects | Actor invocation / spawn |
|
|
@@ -356,7 +356,7 @@ sched.cancelAll();
|
|
|
356
356
|
- async lifecycle hook
|
|
357
357
|
- Inspect middleware 影響 transition 結果
|
|
358
358
|
|
|
359
|
-
### Sub-machine lifecycle(since 0.
|
|
359
|
+
### Sub-machine lifecycle(stable since 0.4.0)
|
|
360
360
|
|
|
361
361
|
當一個 state 宣告 `sub` 時,每次 transition 的執行順序為:
|
|
362
362
|
|
|
@@ -491,8 +491,8 @@ aifsmjs 在幾個常見議題上做了刻意取捨,跟主流 FSM library 寫
|
|
|
491
491
|
| ---- | ----------------------------------------------------------------- |
|
|
492
492
|
| v0.1 | core + guards + effects + inspect + replay + pbt(本次發佈) |
|
|
493
493
|
| v0.2 | Async-guard 偵測、coverage 調整、llms-full.txt verify gate |
|
|
494
|
-
| v0.3 | 透過 `state.sub` 的階層式 sugar(experimental
|
|
495
|
-
| v0.4 |
|
|
494
|
+
| v0.3 | 透過 `state.sub` 的階層式 sugar(experimental) |
|
|
495
|
+
| v0.4 | sub-machine API 升 stable;降依賴 cycle |
|
|
496
496
|
| v0.5 | `aifsmjs-bridge-bitecs` / `aifsmjs-bridge-pixi`(獨立 sub-package) |
|
|
497
497
|
| v1.0 | API freeze 與 stability guarantee |
|
|
498
498
|
|
|
@@ -503,7 +503,7 @@ aifsmjs 在幾個常見議題上做了刻意取捨,跟主流 FSM library 寫
|
|
|
503
503
|
- **Tick / game-loop hook**(v1 不做)
|
|
504
504
|
- **ECS / Pixi bridges**(v1 不做)
|
|
505
505
|
|
|
506
|
-
|
|
506
|
+
**未來候選**:`historyState` — re-entry 時自動恢復上一次的 sub-state。0.3.0 的暫代方案:透過 `onTransition` snapshot sub-runtime 的 value,之後手動還原。
|
|
507
507
|
|
|
508
508
|
---
|
|
509
509
|
|
package/llms-full.txt
CHANGED
|
@@ -120,7 +120,7 @@ The three layers are fully decoupled: take `step()` alone for replay, take `Mach
|
|
|
120
120
|
| Will do (v1) | Won't do |
|
|
121
121
|
| --------------------------------------------------- | ------------------------------------------------- |
|
|
122
122
|
| Flat states + transitions | Parallel state regions |
|
|
123
|
-
| Hierarchical sugar via `state.sub` (
|
|
123
|
+
| Hierarchical sugar via `state.sub` (stable since 0.4.0) | Closures embedded in definition (breaks serialize) |
|
|
124
124
|
| Guards (sync only; inline async throws `InvalidDefinitionError` at `defineMachine`; runtime throws `AsyncGuardError` on thenable return) | Async guards |
|
|
125
125
|
| Actions (assign + enqueue effects) | Async API inside an action (use an effect) |
|
|
126
126
|
| Fire-and-forget effects | Actor invocation / spawn |
|
|
@@ -370,7 +370,7 @@ Non-goals:
|
|
|
370
370
|
- No async lifecycle hook
|
|
371
371
|
- Inspect middleware cannot alter the transition outcome
|
|
372
372
|
|
|
373
|
-
### Sub-machine lifecycle (since 0.
|
|
373
|
+
### Sub-machine lifecycle (stable since 0.4.0)
|
|
374
374
|
|
|
375
375
|
When a state declares `sub`, the per-transition ordering is:
|
|
376
376
|
|
|
@@ -510,8 +510,8 @@ Example-first, PBT-augmented. Lesson from jssm: "3000+ tests / 100% coverage" tu
|
|
|
510
510
|
| ------- | ------------------------------------------------------------------ |
|
|
511
511
|
| v0.1 | core + guards + effects + inspect + replay + pbt (this release) |
|
|
512
512
|
| v0.2 | Async-guard detection, coverage tuning, llms-full.txt verify gate |
|
|
513
|
-
| v0.3 | Hierarchical sugar via `state.sub` (experimental
|
|
514
|
-
| v0.4 |
|
|
513
|
+
| v0.3 | Hierarchical sugar via `state.sub` (experimental) |
|
|
514
|
+
| v0.4 | Sub-machine API promoted to stable; dependency-reduction cycle |
|
|
515
515
|
| v0.5 | `aifsmjs-bridge-bitecs` / `aifsmjs-bridge-pixi` (separate sub-packages) |
|
|
516
516
|
| v1.0 | API freeze and stability guarantee |
|
|
517
517
|
|
|
@@ -522,7 +522,7 @@ Example-first, PBT-augmented. Lesson from jssm: "3000+ tests / 100% coverage" tu
|
|
|
522
522
|
- **Tick / game-loop hook** (out of scope for v1)
|
|
523
523
|
- **ECS / Pixi bridges** (out of scope for v1)
|
|
524
524
|
|
|
525
|
-
**
|
|
525
|
+
**Future candidate**: `historyState` — remember last active sub-state on
|
|
526
526
|
re-entry. Workaround today: snapshot via `onTransition` and restore
|
|
527
527
|
manually.
|
|
528
528
|
|
|
@@ -543,6 +543,47 @@ All notable changes to this project will be documented in this file.
|
|
|
543
543
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
544
544
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
545
545
|
|
|
546
|
+
## [0.4.1] — 2026-05-29
|
|
547
|
+
|
|
548
|
+
### Changed
|
|
549
|
+
|
|
550
|
+
- **`STABILITY.md` is now repo-only** — removed from the npm `files`
|
|
551
|
+
allowlist, aligning with the majority of the ai*js family (5 of 7
|
|
552
|
+
packages already ship the stability contract repo-only). The file stays
|
|
553
|
+
in the repository and remains visible on GitHub and the rendered npm
|
|
554
|
+
package page; it is simply no longer bundled inside the published
|
|
555
|
+
tarball. Packaging consistency patch: **no runtime API change, no
|
|
556
|
+
signature change**; the built bundles (`dist/`) are byte-identical to
|
|
557
|
+
0.4.0 (core gzip 4,387 B).
|
|
558
|
+
|
|
559
|
+
## [0.4.0] — 2026-05-29
|
|
560
|
+
|
|
561
|
+
### Changed
|
|
562
|
+
|
|
563
|
+
- **Sub-machine API promoted experimental → stable.** The hierarchical
|
|
564
|
+
sub-machine surface shipped in 0.3.0 — `StateDef.sub`, `StateDef.subImpl`,
|
|
565
|
+
`Runtime.subRuntime()`, `SubMachineError`, and the `SubMachineDef` type
|
|
566
|
+
alias — is now stable. Signatures and runtime semantics, including the
|
|
567
|
+
init-failure quarantine behaviour, are frozen for the 1.x line; the
|
|
568
|
+
boundaries documented in `STABILITY.md` are intentional design trade-offs,
|
|
569
|
+
not instability. **No signature changed from 0.3.x.**
|
|
570
|
+
|
|
571
|
+
### Dependency reduction
|
|
572
|
+
|
|
573
|
+
- Part of the ai*js v0.4.0 dependency-reduction cycle. `fast-check` remains
|
|
574
|
+
an **optional** peer dependency isolated to the `aifsmjs/pbt` subpath. A
|
|
575
|
+
fresh build confirms the core entry and the five non-pbt subpaths
|
|
576
|
+
(`guards` / `effects` / `inspect` / `replay` / `timer`) are tree-shake-free
|
|
577
|
+
of `fast-check` (only `dist/pbt/index.js` references it). `pnpm audit`
|
|
578
|
+
reports zero advisories. No `devDependency` changes.
|
|
579
|
+
|
|
580
|
+
### Compatibility
|
|
581
|
+
|
|
582
|
+
This release adds **no runtime API** and changes **no signature**. The core
|
|
583
|
+
bundle is byte-identical to 0.3.1 (gzip 4,387 B); existing 0.3.x consumer
|
|
584
|
+
code is unaffected. The only substantive change is the documented stability
|
|
585
|
+
tier of the sub-machine API.
|
|
586
|
+
|
|
546
587
|
## [0.3.1] — 2026-05-29
|
|
547
588
|
|
|
548
589
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aifsmjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Small, strict FSM library for deterministic, replayable state machines in any TypeScript/JS app — multi-step forms, checkout funnels, auth flows, tutorials, scene flow. Pure step() lifecycle, opt-in effects, inspect, replay, and a fast-check property-based testing adapter. Browser / Node / Bun / Deno / WebView / Worker friendly.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fsm",
|
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
"dist",
|
|
75
75
|
"README.md",
|
|
76
76
|
"README_ZHTW.md",
|
|
77
|
-
"STABILITY.md",
|
|
78
77
|
"LICENSE",
|
|
79
78
|
"llms.txt",
|
|
80
79
|
"llms-full.txt"
|
package/STABILITY.md
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# Stability
|
|
2
|
-
|
|
3
|
-
This document defines the stability tier of every public symbol exported by
|
|
4
|
-
`aifsmjs`. Tiers govern what breaks may occur in future minor / major bumps.
|
|
5
|
-
|
|
6
|
-
## Stable (since 0.1.0)
|
|
7
|
-
|
|
8
|
-
Fully stable. Breaking changes only at a major version bump (1.0+).
|
|
9
|
-
|
|
10
|
-
- `createMachine`, `defineMachine`, `setup`, `createRuntime`, `initialSnapshot`
|
|
11
|
-
- `step`, `resolveTransitions`, `evalGuard`, `resolveGuard`, `isAsyncGuardFn`
|
|
12
|
-
- `assign`, `mergeContext`, `createSnapshot`, `deepFreeze`, `freezeSnapshot`
|
|
13
|
-
- `Runtime.send`, `Runtime.reset`, `Runtime.can`, `Runtime.getSnapshot`,
|
|
14
|
-
`Runtime.snapshot`, `Runtime.subscribe`, `Runtime.on`, `Runtime.dispose`,
|
|
15
|
-
`Runtime.signal`, `Runtime.disposed`
|
|
16
|
-
- All error classes from 0.1.0–0.2.1: `RuntimeDisposedError`,
|
|
17
|
-
`InvalidDefinitionError`, `UnknownActionError`, `UnknownGuardError`,
|
|
18
|
-
`AsyncGuardError`
|
|
19
|
-
- Types: `MachineDef`, `StateDef` (fields `on`, `entry`, `exit`, `final`),
|
|
20
|
-
`TransitionDef`, `Snapshot`, `Implementations`, `Guard`, `Action`,
|
|
21
|
-
`EffectHandler`, `Effect`, `Enqueuer`, `Middleware`, `MiddlewareContext`,
|
|
22
|
-
`RuntimeOptions`, `StepResult`, `ResetEvent`, `RESET_EVENT_TYPE`,
|
|
23
|
-
`RuntimeTransitionEvent`, `RuntimeErrorEvent`, `RuntimeEventMap`
|
|
24
|
-
- All subpath exports: `aifsmjs/guards`, `aifsmjs/effects`, `aifsmjs/inspect`,
|
|
25
|
-
`aifsmjs/replay`, `aifsmjs/pbt`, `aifsmjs/timer`
|
|
26
|
-
- `Runtime.onTransition` (added in 0.3.0) — pure sugar over the stable
|
|
27
|
-
`on('transition', ...)` API; listed under Stable because the underlying
|
|
28
|
-
contract is unchanged.
|
|
29
|
-
|
|
30
|
-
## Experimental (since 0.3.0)
|
|
31
|
-
|
|
32
|
-
Shape and behaviour may change in any minor bump until 1.0. Production use
|
|
33
|
-
is OK; expect a one-line patch on minor upgrades.
|
|
34
|
-
|
|
35
|
-
- `StateDef.sub` (optional `SubMachineDef`) — when present, a child runtime
|
|
36
|
-
is lazily initialised on entry and disposed on exit. Per-transition
|
|
37
|
-
ordering is parent `step()` (exit / actions / entry) → child dispose →
|
|
38
|
-
child init → snapshot commit.
|
|
39
|
-
- `StateDef.subImpl` (optional `Implementations`) — paired with `sub`;
|
|
40
|
-
passed to the child `createRuntime`. Defaults to `{}`.
|
|
41
|
-
- `Runtime.subRuntime()` — returns the live child handle, or `undefined`.
|
|
42
|
-
Returned generic is `Runtime<unknown, { type: string }, string>`; caller
|
|
43
|
-
narrows via cast if necessary.
|
|
44
|
-
- `SubMachineError` — thrown by `send()` / `reset()` on child init/dispose
|
|
45
|
-
failure. Fields: `parentState`, `phase ("init" | "dispose")`, `cause`.
|
|
46
|
-
- `SubMachineDef` type alias.
|
|
47
|
-
|
|
48
|
-
### Known boundaries (0.3.0)
|
|
49
|
-
|
|
50
|
-
- **Replay / PBT do not see child state.** `replay()` and
|
|
51
|
-
`commandsFromMachine` only inspect parent snapshots. If your business
|
|
52
|
-
logic lives in the parent layer, replay is still deterministic.
|
|
53
|
-
- **`subRuntime()` may return a disposed handle** if an external caller
|
|
54
|
-
disposed it. The handle is not reinitialised until the parent leaves and
|
|
55
|
-
re-enters the sub-bearing state. Detect with `child.disposed`.
|
|
56
|
-
- **Self-targeting external (`A → A`) is treated as full exit/entry**:
|
|
57
|
-
child is disposed and reinitialised. The 0.3.0 dispatcher re-resolves
|
|
58
|
-
guards to identify the chosen transition before deciding external vs
|
|
59
|
-
internal, so guarded internal transitions on the same event no longer
|
|
60
|
-
trigger a reinit.
|
|
61
|
-
- **Init-failure mid-transition leaves the parent without a live child.**
|
|
62
|
-
If `applySubLifecycle` successfully disposes the old child and then the
|
|
63
|
-
new child's `createRuntime` throws, the parent's snapshot is rolled back
|
|
64
|
-
to `prev` but `subRuntime()` returns `undefined`. Callers catching
|
|
65
|
-
`SubMachineError(phase: "init")` should treat the runtime as quarantined
|
|
66
|
-
— call `runtime.dispose()` (idempotent) or `runtime.reset()` (which
|
|
67
|
-
attempts re-init) before sending further events. A future major may
|
|
68
|
-
switch to a two-phase "init before dispose" commit strategy; for 0.3.x
|
|
69
|
-
this remains opt-in only when child failures are expected.
|
|
70
|
-
|
|
71
|
-
## Draft (planned, not implemented in 0.3.0)
|
|
72
|
-
|
|
73
|
-
API sketched, not shipped. May change before release.
|
|
74
|
-
|
|
75
|
-
- `historyState` (v0.4 candidate) — opt-in pseudo-state that remembers
|
|
76
|
-
the last active sub-state on re-entry. Workaround in 0.3.0: snapshot
|
|
77
|
-
the sub-runtime's value on exit via `onTransition`, restore manually.
|