@daltonr/pathwrite-store
v0.15.0
Published
Persistence adapters for PathEngine — LocalStorageStore (browser), AsyncStorageStore (React Native / any async key-value store), and HttpStore (REST API)
Maintainers
Readme
@daltonr/pathwrite-store
HTTP, localStorage, and AsyncStorage persistence for Pathwrite.
Installation
npm install @daltonr/pathwrite-storeAsyncStorageStore takes the storage instance as a constructor option (new AsyncStorageStore({ storage: AsyncStorage })), so your app installs @react-native-async-storage/async-storage itself — it is not a dependency of this package.
Quick start
import { PathEngine } from "@daltonr/pathwrite-core";
import { HttpStore, persistence, restoreOrStart } from "@daltonr/pathwrite-store";
const store = new HttpStore({
baseUrl: "/api/wizard",
headers: { Authorization: `Bearer ${token}` },
// Expects these three endpoints on your backend:
// PUT /api/wizard/state/{key} — save state (body: SerializedPathState)
// GET /api/wizard/state/{key} — load state (return 404 when not found)
// DELETE /api/wizard/state/{key} — delete state on completion
});
const key = `user:${userId}:onboarding`;
const { engine, restored } = await restoreOrStart({
store,
key,
path: onboardingWizard,
initialData: { name: "", email: "" },
observers: [
persistence({ store, key, strategy: "onNext" }),
],
});
// Pass the engine to any framework adapter
// e.g. const { snapshot, next } = usePath({ engine });
if (restored) {
console.log("Resuming from saved progress.");
}Stores
| Store | Import | Use for |
|---|---|---|
| HttpStore | @daltonr/pathwrite-store | REST API backend (browser or Node). |
| LocalStorageStore | @daltonr/pathwrite-store | Browser localStorage or sessionStorage. Falls back to in-memory in Node/test environments. |
| AsyncStorageStore | @daltonr/pathwrite-store | React Native. Pass your @react-native-async-storage/async-storage instance as the storage option; the package declares no dependency on it. |
All three implement the PathStore interface from @daltonr/pathwrite-core (save, load, delete) and are interchangeable as far as persistence() and restoreOrStart() are concerned.
Save strategies
Pass strategy to persistence() to control when saves fire.
| Strategy | When it saves | API calls (5 keystrokes + Next) |
|---|---|---|
| "onNext" (default) | After next() navigates to a new step, and when a sub-path returns to its parent (completed or cancelled) | 1 |
| "onEveryChange" | Every settled stateChanged event (add debounceMs for text inputs) | 6 (or 2 with debounceMs: 500) |
| "onSubPathComplete" | When a sub-path finishes and the parent path resumes | varies |
| "onComplete" | When the path completes; does not delete the record afterward (the record is marked completed, and restoreOrStart starts fresh when it finds one) | 0 mid-flow, 1 at end |
| "manual" | Never — call store.save(key, engine.exportState()!) yourself | 0 |
restoreOrStart()
The observer persistence() returns has two extra methods: flush() saves immediately (cancelling a pending debounce window) and resolves once every queued save has landed — call it on beforeunload or before unmount; dispose() cancels a pending debounce window and ignores later events so a timer never outlives the host component.
restoreOrStart() handles the standard load/restore-or-start pattern in a single call. It tries store.load(key); if a saved state is found it reconstructs the engine at the saved step via PathEngine.fromState(); if nothing is found it creates a fresh engine and calls engine.start(path, initialData). Observers are wired before the first event in both cases, so the persistence observer never misses a state transition.
const { engine, restored } = await restoreOrStart({
store, // any PathStore
key, // string session key, e.g. "user:123:signup"
path, // PathDefinition for the wizard
initialData, // used only when starting fresh (not on restore)
observers, // PathObserver[] — wired before the first event
pathDefinitions, // optional: required when the path uses sub-paths
onRestoreError, // optional: called when saved state exists but cannot be used
});engine is a plain PathEngine ready to pass to any framework adapter. restored is true when a saved session was found. When the path later completes, the persistence observer automatically calls store.delete(key) so a returning user starts fresh.
Saved state that cannot be used never blocks the app. If the store fails to load it (corrupt JSON, network), its version is unsupported, or it names a path id that is no longer in pathDefinitions (a renamed path), restoreOrStart reports the error through onRestoreError (or console.warn when the callback is absent), deletes the record on a best-effort basis, and starts fresh with restored: false.
Further reading
- docs/developer-guide/09-persistence.md — strategies, offline patterns, custom stores, and the full
HttpStoreoptions reference - docs/README.md — documentation index
