{"_id":"@bazariodev/fsm-persist","_rev":"2-327d28e4a77d4cb0f7ca8be2dc605a45","name":"@bazariodev/fsm-persist","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@bazariodev/fsm-persist","version":"1.0.0","keywords":["fsm","finite-state-machine","state-machine","persistence","typescript","realtime","telephony","ucaas"],"author":{"name":"Bazario"},"license":"MIT","_id":"@bazariodev/fsm-persist@1.0.0","maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-persist#readme","bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"dist":{"shasum":"04db525df6b8c42225ad3ab3823e0526e6b5c2cf","tarball":"https://registry.npmjs.org/@bazariodev/fsm-persist/-/fsm-persist-1.0.0.tgz","fileCount":9,"integrity":"sha512-XxzQZT96Twgl/PoFIYn74ro9nVHuM+RYbduRvNs9EUwRgxPD+eZQowtw+rwVpCq2QOhxzdvnnz/Dmt0Ue+2V1g==","signatures":[{"sig":"MEUCIGfwmWIC/hPlsLT/8j8JviSPSt4eG77IopL08mWR3MfPAiEA8YzDqnlqyQaQJVNjLDzcShn7W710tpCJRB3W15uBdrQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":107059},"main":"./dist/index.cjs","type":"module","_from":"file:bazariodev-fsm-persist-1.0.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"bazario","email":"bazario.dev@gmail.com"},"_resolved":"/private/var/folders/xk/pm_239nx0cjgz296_sbs_f1c0000gn/T/57cc7f1767e637a5286eee0c515eec6c/bazariodev-fsm-persist-1.0.0.tgz","_integrity":"sha512-XxzQZT96Twgl/PoFIYn74ro9nVHuM+RYbduRvNs9EUwRgxPD+eZQowtw+rwVpCq2QOhxzdvnnz/Dmt0Ue+2V1g==","repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-persist"},"_npmVersion":"11.5.1","description":"Persistence helpers for @bazariodev/fsm snapshots with write-through storage and rehydrate-by-construction restore.","directories":{},"sideEffects":false,"_nodeVersion":"24.7.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@bazariodev/fsm":"^1.0.0","@bazariodev/fsm-hierarchy":"^1.0.0"},"peerDependencies":{"@bazariodev/fsm":"^1.0.0"},"_npmOperationalInternal":{"tmp":"tmp/fsm-persist_1.0.0_1783331028524_0.895785250149504","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"_id":"@bazariodev/fsm-persist@1.1.0","bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"dist":{"shasum":"581b9739f1d25b864b1788997ed899efca5462fa","tarball":"https://registry.npmjs.org/@bazariodev/fsm-persist/-/fsm-persist-1.1.0.tgz","fileCount":9,"integrity":"sha512-h6ctWTCk+s38768gluEV10GAwcjzlmvJVgxpwbCpH56Z7CwTlGc1wzwiyvoBIutgLT13qIePh8dgz34FHgYCDw==","signatures":[{"sig":"MEYCIQCMVowzPwvBsi8e9kZUHWB5bToAtg3C1mAuQDJC1DU0iwIhAIXHbE/Bev9yRyFfsIovC1j96qzSsVJAowz2MNDkW5/C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH6cDwEiGxjFCmnSzD/osDxEDKHG+iLw0oRebREeAPXgAiEA5XMWl4TJtstppLNJdp+kr7XElyAL7YY++du3zpSk/aU="}],"unpackedSize":88766},"main":"./dist/index.cjs","name":"@bazariodev/fsm-persist","type":"module","_from":"file:bazariodev-fsm-persist-1.1.0.tgz","types":"./dist/index.d.ts","author":{"name":"Bazario"},"module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"license":"MIT","scripts":{"test":"vitest run","build":"tsup","typecheck":"tsc --noEmit","test:watch":"vitest"},"version":"1.1.0","_npmUser":{"name":"bazario","email":"bazario.dev@gmail.com"},"homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-persist#readme","keywords":["fsm","finite-state-machine","state-machine","persistence","typescript","realtime","telephony","ucaas"],"_resolved":"/private/var/folders/xk/pm_239nx0cjgz296_sbs_f1c0000gn/T/e73146c63aaefecd074a7fa45ddf0770/bazariodev-fsm-persist-1.1.0.tgz","_integrity":"sha512-h6ctWTCk+s38768gluEV10GAwcjzlmvJVgxpwbCpH56Z7CwTlGc1wzwiyvoBIutgLT13qIePh8dgz34FHgYCDw==","repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-persist"},"_npmVersion":"11.5.1","description":"Persistence helpers for @bazariodev/fsm snapshots with write-through storage and rehydrate-by-construction restore.","directories":{},"maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"sideEffects":false,"_nodeVersion":"24.7.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"@bazariodev/fsm":"^1.1.0","@bazariodev/fsm-hierarchy":"^1.1.0"},"peerDependencies":{"@bazariodev/fsm":"^1.1.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/fsm-persist_1.1.0_1790588900137_0.2740063594947926"}}},"time":{"created":"2026-07-06T09:43:48.404Z","modified":"2026-09-28T09:48:20.397Z","1.0.0":"2026-07-06T09:43:48.662Z","1.1.0":"2026-09-28T09:48:20.212Z"},"bugs":{"url":"https://github.com/Bazariodev/bazario-labs/issues"},"author":{"name":"Bazario"},"license":"MIT","homepage":"https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm-persist#readme","keywords":["fsm","finite-state-machine","state-machine","persistence","typescript","realtime","telephony","ucaas"],"repository":{"url":"git+https://github.com/Bazariodev/bazario-labs.git","type":"git","directory":"packages/fsm-persist"},"description":"Persistence helpers for @bazariodev/fsm snapshots with write-through storage and rehydrate-by-construction restore.","maintainers":[{"name":"bazario","email":"bazario.dev@gmail.com"}],"readme":"# @bazariodev/fsm-persist\n\nPersistence helpers for [`@bazariodev/fsm`](https://github.com/Bazariodev/bazario-labs/tree/main/packages/fsm) and hierarchy-shaped sources.\n\nFull design rationale: [`Persist.md` ADR](https://github.com/Bazariodev/bazario-labs/blob/main/.agent/ADR/Modules/Persist.md).\n\n```sh\npnpm add @bazariodev/fsm-persist @bazariodev/fsm\n```\n\n## Flat machines\n\n```ts\nimport { Fsm } from '@bazariodev/fsm';\nimport { persistFsm, restoreFsmConfig } from '@bazariodev/fsm-persist';\n\nconst restored = restoreFsmConfig(callConfig, {\n  storage: localStorage,\n  key: 'call',\n});\n\nconst machine = new Fsm(restored.config);\nconst persist = persistFsm(machine, {\n  storage: localStorage,\n  key: 'call',\n  name: callConfig.name,\n});\n```\n\nRestore is by construction: `restoreFsmConfig` returns a config whose `initial` and `context` come from storage when the record is valid. Construct the machine normally. A restored machine starts at `version: 0` and `previousValue: null`.\n\n## Hierarchies\n\n```ts\nimport { FsmHierarchy } from '@bazariodev/fsm-hierarchy';\nimport {\n  persistHierarchy,\n  restoreHierarchyConfig,\n} from '@bazariodev/fsm-persist';\n\nconst restored = restoreHierarchyConfig(rootConfig, {\n  storage: localStorage,\n  key: 'call-tree',\n});\n\nconst hierarchy = new FsmHierarchy(restored.config);\nconst persist = persistHierarchy(hierarchy, {\n  storage: localStorage,\n  key: 'call-tree',\n  name: rootConfig.name,\n});\n```\n\nHierarchy restore walks the stored active spine top-down. If the root state no longer exists, nothing is restored. If a deeper level no longer matches the current config, the valid prefix restores and everything below it starts fresh at the declared `initial`.\n\n## API\n\n```ts\nimport type { FsmSubscribable } from '@bazariodev/fsm';\n\ntype PersistStorage = {\n  getItem(key: string): string | null;\n  setItem(key: string, value: string): void;\n  removeItem(key: string): void;\n};\n```\n\n`localStorage` and `sessionStorage` satisfy `PersistStorage` directly. The source port is structural and exported by `@bazariodev/fsm`; `Fsm`, `FsmHierarchy`, and hierarchy node handles satisfy it.\n\nWriters:\n\n- `persistFsm(source, options)`\n- `persistHierarchy(source, options)`\n- `new FsmPersist(source, toState, options)` for custom projected state\n\nReaders:\n\n- `loadRecord(options)` validates and returns the versioned envelope only\n- `restoreFsmConfig(config, options)`\n- `restoreHierarchyConfig(config, options)`\n\n`FsmPersist` writes once at construction and then on each committed notification. `filter` gates all writes. `stop()` unsubscribes without removing the record; `clear()` removes the record without stopping.\n\n## Recovery model\n\nOnly state-at-rest is persisted: active state value and context. Effects, timers, subscribers, and in-flight work are not persisted. After restore, state `onEnter` runs normally, and attaching effects or delays re-fires the restored state's effects. That re-entry is the recovery model.\n\nOnly recovery-safe states belong in persisted records. For flows that cannot be meaningfully re-entered after a reload, use `filter` or a custom `FsmPersist` projection to persist a safe restore point instead.\n\n## Security\n\nPersisted context is plaintext web storage. Credentials, tokens, and PII do not belong in persisted machine context. `filter` is not redaction: when a snapshot is filtered out, the previous record remains in storage. Keep secrets out of persisted context, project a reduced state with custom `toState` / `serialize`, and call `clear()` on logout.\n\n## Error policy\n\nBad storage data never bricks startup. Missing, corrupt, stale, wrong-name, wrong-kind, and unknown-state records degrade to a fresh start and log through the injected `Logger`.\n\nWrite failures are contained too. A throwing `filter`, `toState`, `now`, `serialize`, `setItem`, or `removeItem` is logged and does not affect the machine.\n","readmeFilename":"README.md"}