@daltonr/pathwrite-core 0.3.0 → 0.4.0

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 CHANGED
@@ -2,6 +2,39 @@
2
2
 
3
3
  Headless path engine with zero dependencies. Manages step navigation, navigation guards, lifecycle hooks, and stack-based sub-path orchestration. Works equally well driving a UI wizard or a backend document lifecycle — no framework required.
4
4
 
5
+ ## Quick Reference: Common Patterns
6
+
7
+ ### ✅ Write Defensive Guards
8
+ ```typescript
9
+ // Guards run BEFORE onEnter - always handle undefined data
10
+ canMoveNext: (ctx) => (ctx.data.name ?? "").trim().length > 0 // ✅ Safe
11
+ canMoveNext: (ctx) => ctx.data.name.trim().length > 0 // ❌ Crashes!
12
+ ```
13
+
14
+ ### ✅ Use `isFirstEntry` to Prevent Data Reset
15
+ ```typescript
16
+ onEnter: (ctx) => {
17
+ if (ctx.isFirstEntry) {
18
+ return { items: [], status: "pending" }; // Initialize only on first visit
19
+ }
20
+ // Don't reset when user navigates back
21
+ }
22
+ ```
23
+
24
+ ### ✅ Correlate Sub-Paths with `meta`
25
+ ```typescript
26
+ // Starting sub-path
27
+ engine.startSubPath(subPath, initialData, { itemIndex: i });
28
+
29
+ // In parent step
30
+ onSubPathComplete: (_id, subData, ctx, meta) => {
31
+ const index = meta?.itemIndex; // Correlate back to collection item
32
+ // ...
33
+ }
34
+ ```
35
+
36
+ ---
37
+
5
38
  ## Key types
6
39
 
7
40
  ```typescript
@@ -38,6 +71,7 @@ const path: PathDefinition<CourseData> = {
38
71
  const engine = new PathEngine();
39
72
 
40
73
  engine.start(definition, initialData?); // start or re-start a path
74
+ engine.restart(definition, initialData?); // tear down stack and start fresh (no hooks, no cancelled event)
41
75
  engine.startSubPath(definition, data?); // push sub-path onto the stack (requires active path)
42
76
  engine.next();
43
77
  engine.previous();
@@ -47,6 +81,10 @@ engine.goToStep(stepId); // jump to step by ID; bypasses guard
47
81
  engine.goToStepChecked(stepId); // jump to step by ID; checks canMoveNext / canMovePrevious first
48
82
  engine.snapshot(); // returns PathSnapshot | null
49
83
 
84
+ // Serialization API (for persistence)
85
+ const state = engine.exportState(); // returns SerializedPathState | null
86
+ const restoredEngine = PathEngine.fromState(state, pathDefinitions);
87
+
50
88
  const unsubscribe = engine.subscribe((event) => { ... });
51
89
  unsubscribe(); // remove the listener
52
90
  ```
@@ -60,36 +98,318 @@ All hooks are optional. Hooks that want to update data **return a partial patch*
60
98
  | `onEnter` | On arrival at a step (start, next, previous, resume) | ✅ |
61
99
  | `onLeave` | On departure from a step (only when the guard allows) | ✅ |
62
100
  | `onSubPathComplete` | On the parent step when a sub-path finishes | ✅ |
101
+ | `onSubPathCancel` | On the parent step when a sub-path is cancelled | ✅ |
63
102
  | `canMoveNext` | Before advancing — return `false` to block | — |
64
103
  | `canMovePrevious` | Before going back — return `false` to block | — |
65
104
  | `validationMessages` | On every snapshot — return `string[]` explaining why the step is not yet valid | — |
66
105
 
106
+ ### Using `isFirstEntry` to Avoid Data Reset
107
+
108
+ **Problem:** `onEnter` fires EVERY time you enter a step, including when navigating backward. If you initialize data in `onEnter`, you'll overwrite user input when they return to the step.
109
+
110
+ **Solution:** Use `ctx.isFirstEntry` to distinguish first visit from re-entry:
111
+
112
+ ```typescript
113
+ {
114
+ id: "user-details",
115
+ onEnter: (ctx) => {
116
+ // Only initialize on first entry, not on re-entry
117
+ if (ctx.isFirstEntry) {
118
+ return {
119
+ name: "",
120
+ email: "",
121
+ preferences: { newsletter: true }
122
+ };
123
+ }
124
+ // On re-entry (e.g., user pressed Back), keep existing data
125
+ }
126
+ }
127
+ ```
128
+
129
+ **Common Patterns:**
130
+
131
+ ```typescript
132
+ // Initialize empty collection on first entry only
133
+ onEnter: (ctx) => {
134
+ if (ctx.isFirstEntry) {
135
+ return { approvals: [], comments: [] };
136
+ }
137
+ }
138
+
139
+ // Fetch data from API only once
140
+ onEnter: async (ctx) => {
141
+ if (ctx.isFirstEntry) {
142
+ const userData = await fetchUserProfile(ctx.data.userId);
143
+ return { ...userData };
144
+ }
145
+ }
146
+
147
+ // Set defaults but preserve user changes on re-entry
148
+ onEnter: (ctx) => {
149
+ if (ctx.isFirstEntry) {
150
+ return {
151
+ reviewStatus: "pending",
152
+ lastModified: new Date().toISOString()
153
+ };
154
+ }
155
+ }
156
+ ```
157
+
67
158
  ### Snapshot guard booleans
68
159
 
69
160
  The snapshot includes `canMoveNext` and `canMovePrevious` booleans — the evaluated results of the current step's guards. Use them to proactively disable navigation buttons. Sync guards reflect their real value; async guards default to `true` (optimistic). Both update automatically when data changes via `setData`.
70
161
 
71
- ### Example sub-path result merged into parent data
162
+ ### ⚠️ IMPORTANT: Guards Run Before `onEnter`
163
+
164
+ **Guards are evaluated BEFORE `onEnter` runs on first entry.** This is critical to understand:
165
+
166
+ 1. When a path starts, the engine creates the first snapshot immediately
167
+ 2. Guards (`canMoveNext`, `validationMessages`) are evaluated to populate that snapshot
168
+ 3. Only THEN does `onEnter` run to initialize data
169
+
170
+ **This means guards see `initialData`, not data that `onEnter` would set.**
171
+
172
+ #### Defensive Guard Patterns
173
+
174
+ Always write guards defensively to handle undefined/missing data:
72
175
 
73
176
  ```typescript
177
+ // ❌ WRONG - Crashes on first snapshot when initialData = {}
74
178
  {
75
- id: "subjects-list",
76
- onSubPathComplete: (_id, subData, ctx) => ({
77
- subjects: [...(ctx.data.subjects ?? []), { name: subData.name, teacher: subData.teacher }]
78
- })
179
+ id: "user-details",
180
+ canMoveNext: (ctx) => ctx.data.name.trim().length > 0, // TypeError!
181
+ onEnter: () => ({ name: "" }) // Too late - guard already ran
182
+ }
183
+
184
+ // ✅ CORRECT - Use nullish coalescing
185
+ {
186
+ id: "user-details",
187
+ canMoveNext: (ctx) => (ctx.data.name ?? "").trim().length > 0,
188
+ onEnter: () => ({ name: "" })
79
189
  }
190
+
191
+ // ✅ ALSO CORRECT - Provide initialData so fields exist from the start
192
+ engine.start(path, { name: "", email: "" });
80
193
  ```
81
194
 
82
- ## Sub-path flow
195
+ #### More Defensive Patterns
196
+
197
+ ```typescript
198
+ // Arrays
199
+ canMoveNext: (ctx) => (ctx.data.items ?? []).length > 0
200
+
201
+ // Numbers
202
+ canMoveNext: (ctx) => (ctx.data.age ?? 0) >= 18
83
203
 
204
+ // Complex objects
205
+ canMoveNext: (ctx) => {
206
+ const address = ctx.data.address ?? {};
207
+ return (address.street ?? "").length > 0 && (address.city ?? "").length > 0;
208
+ }
209
+
210
+ // Validation messages
211
+ validationMessages: (ctx) => {
212
+ const messages = [];
213
+ if (!(ctx.data.email ?? "").includes("@")) {
214
+ messages.push("Please enter a valid email");
215
+ }
216
+ return messages;
217
+ }
84
218
  ```
219
+
220
+ #### Error Handling
221
+
222
+ If a guard or `validationMessages` hook throws, Pathwrite catches the error, emits a `console.warn` (with the step ID and thrown value), and returns the safe default (`true` / `[]`) so the UI remains operable. However, **relying on error handling is not recommended** — write defensive guards instead.
223
+
224
+ ### Sub-path example with meta correlation
225
+
226
+ ```typescript
227
+ {
228
+ id: "subjects-list",
229
+ onSubPathComplete: (_id, subData, ctx, meta) => {
230
+ // meta contains the correlation object passed to startSubPath
231
+ const index = meta?.index as number;
232
+ return {
233
+ subjects: [...(ctx.data.subjects ?? []), {
234
+ index,
235
+ name: subData.name,
236
+ teacher: subData.teacher
237
+ }]
238
+ };
239
+ },
240
+ onSubPathCancel: (_id, ctx, meta) => {
241
+ // Called when user cancels sub-path (e.g., Back on first step)
242
+ const index = meta?.index as number;
243
+ console.log(`User skipped subject ${index}`);
244
+ // Return patch to record the skip, or return nothing to ignore
245
+ }
246
+ }
247
+ ```
248
+
249
+ ## Sub-Paths: Comprehensive Guide
250
+
251
+ Sub-paths let you nest workflows — for example, running a mini-wizard for each item in a collection.
252
+
253
+ ### Basic Flow
254
+
255
+ ```typescript
85
256
  engine.start(mainPath) → stack: [] active: main
86
257
  engine.startSubPath(subPath) → stack: [main] active: sub
87
258
  engine.next() // sub finishes
88
259
  → onSubPathComplete fires on the parent step
89
- → stack: [] active: main
260
+ → stack: [] active: main (resumed)
261
+ ```
262
+
263
+ ### Complete Example: Document Approval Workflow
264
+
265
+ ```typescript
266
+ interface ApprovalData extends PathData {
267
+ documentTitle: string;
268
+ approvers: Array<{ name: string; email: string }>;
269
+ approvals: Array<{ approverIndex: number; decision: string; comments: string }>;
270
+ }
271
+
272
+ interface ApproverReviewData extends PathData {
273
+ documentTitle: string; // Passed from parent
274
+ decision?: "approve" | "reject";
275
+ comments?: string;
276
+ }
277
+
278
+ // Main path
279
+ const approvalPath: PathDefinition<ApprovalData> = {
280
+ id: "approval-workflow",
281
+ steps: [
282
+ {
283
+ id: "setup",
284
+ onEnter: (ctx) => {
285
+ if (ctx.isFirstEntry) {
286
+ return { approvers: [], approvals: [] };
287
+ }
288
+ }
289
+ },
290
+ {
291
+ id: "run-approvals",
292
+ // Block next until all approvers have completed
293
+ canMoveNext: (ctx) => {
294
+ const approversCount = (ctx.data.approvers ?? []).length;
295
+ const approvalsCount = (ctx.data.approvals ?? []).length;
296
+ return approversCount > 0 && approvalsCount === approversCount;
297
+ },
298
+ validationMessages: (ctx) => {
299
+ const approversCount = (ctx.data.approvers ?? []).length;
300
+ const approvalsCount = (ctx.data.approvals ?? []).length;
301
+ const remaining = approversCount - approvalsCount;
302
+ if (remaining > 0) {
303
+ return [`${remaining} approver(s) still need to complete their review`];
304
+ }
305
+ return [];
306
+ },
307
+ // Called when each approver sub-path completes
308
+ onSubPathComplete: (_subPathId, subData, ctx, meta) => {
309
+ const reviewData = subData as ApproverReviewData;
310
+ const approverIndex = meta?.approverIndex as number;
311
+
312
+ return {
313
+ approvals: [
314
+ ...(ctx.data.approvals ?? []),
315
+ {
316
+ approverIndex,
317
+ decision: reviewData.decision!,
318
+ comments: reviewData.comments ?? ""
319
+ }
320
+ ]
321
+ };
322
+ },
323
+ // Called when approver cancels (presses Back on first step)
324
+ onSubPathCancel: (_subPathId, ctx, meta) => {
325
+ const approverIndex = meta?.approverIndex as number;
326
+ console.log(`Approver ${approverIndex} declined to review`);
327
+ // Could add to a "skipped" list or just ignore
328
+ }
329
+ },
330
+ { id: "summary" }
331
+ ]
332
+ };
333
+
334
+ // Sub-path for each approver
335
+ const approverReviewPath: PathDefinition<ApproverReviewData> = {
336
+ id: "approver-review",
337
+ steps: [
338
+ { id: "review-document" },
339
+ {
340
+ id: "make-decision",
341
+ canMoveNext: (ctx) => ctx.data.decision !== undefined
342
+ },
343
+ { id: "add-comments" }
344
+ ]
345
+ };
346
+
347
+ // Usage in UI component
348
+ function ReviewStep() {
349
+ const approvers = snapshot.data.approvers ?? [];
350
+ const approvals = snapshot.data.approvals ?? [];
351
+
352
+ const startReview = (approverIndex: number) => {
353
+ const approver = approvers[approverIndex];
354
+
355
+ // Start sub-path with meta correlation
356
+ engine.startSubPath(
357
+ approverReviewPath,
358
+ {
359
+ documentTitle: snapshot.data.documentTitle, // Pass context from parent
360
+ // decision and comments will be filled during sub-path
361
+ },
362
+ { approverIndex } // Meta: correlates completion back to this approver
363
+ );
364
+ };
365
+
366
+ return (
367
+ <div>
368
+ {approvers.map((approver, i) => (
369
+ <div key={i}>
370
+ {approver.name}
371
+ {approvals.some(a => a.approverIndex === i) ? (
372
+ <span>✓ Reviewed</span>
373
+ ) : (
374
+ <button onClick={() => startReview(i)}>Start Review</button>
375
+ )}
376
+ </div>
377
+ ))}
378
+ </div>
379
+ );
380
+ }
90
381
  ```
91
382
 
92
- Cancelling a sub-path pops it off the stack silently — `onSubPathComplete` is **not** called.
383
+ ### Sub-Path Key Concepts
384
+
385
+ 1. **Stack-based**: Sub-paths push onto a stack. Parent is paused while sub-path is active.
386
+
387
+ 2. **Meta correlation**: Pass a `meta` object to `startSubPath()` to identify which collection item triggered the sub-path. It's passed back unchanged to `onSubPathComplete` and `onSubPathCancel`.
388
+
389
+ 3. **Data isolation**: Sub-path data is separate from parent data. Pass needed context (like `documentTitle`) in `initialData`.
390
+
391
+ 4. **Completion vs Cancellation**:
392
+ - **Complete**: User reaches the last step → `onSubPathComplete` fires
393
+ - **Cancel**: User presses Back on first step → `onSubPathCancel` fires
394
+ - `onSubPathComplete` is NOT called on cancellation
395
+
396
+ 5. **Parent remains on same step**: After sub-path completes/cancels, parent resumes at the same step (not advanced automatically).
397
+
398
+ 6. **Guards still apply**: Parent step's `canMoveNext` is evaluated when resuming. Use it to block until all sub-paths complete.
399
+
400
+ ### What the Shell Renders During Sub-Paths
401
+
402
+ When a sub-path is active:
403
+ - Progress bar shows sub-path steps (parent steps disappear)
404
+ - Back button on sub-path's first step cancels the sub-path
405
+ - Completing the sub-path returns to parent (parent step re-renders)
406
+
407
+ ### Nesting Levels
408
+
409
+ Sub-paths can themselves start sub-paths (unlimited nesting). Use `snapshot.nestingLevel` to determine depth:
410
+ - `0` = top-level path
411
+ - `1` = first-level sub-path
412
+ - `2+` = deeper nesting
93
413
 
94
414
  ## Events
95
415
 
@@ -103,3 +423,48 @@ engine.subscribe((event) => {
103
423
  }
104
424
  });
105
425
  ```
426
+
427
+ ## State Persistence
428
+
429
+ The engine supports exporting and restoring state for persistence scenarios (e.g., saving wizard progress to a server or localStorage).
430
+
431
+ ### exportState()
432
+
433
+ Returns a plain JSON-serializable object (`SerializedPathState`) containing the current state:
434
+ - Current path ID and step index
435
+ - Path data
436
+ - Visited step IDs
437
+ - Sub-path stack (if nested paths are active)
438
+ - Navigation flags
439
+
440
+ Returns `null` if no path is active.
441
+
442
+ ```typescript
443
+ const state = engine.exportState();
444
+ if (state) {
445
+ const json = JSON.stringify(state);
446
+ // Save to localStorage, send to server, etc.
447
+ }
448
+ ```
449
+
450
+ ### PathEngine.fromState()
451
+
452
+ Restores a PathEngine from previously exported state. **Important:** You must provide the same path definitions that were active when the state was exported.
453
+
454
+ ```typescript
455
+ const state = JSON.parse(savedJson);
456
+ const engine = PathEngine.fromState(state, {
457
+ "main-path": mainPathDefinition,
458
+ "sub-path": subPathDefinition
459
+ });
460
+
461
+ // Engine is restored to the exact step and state
462
+ const snapshot = engine.snapshot();
463
+ ```
464
+
465
+ Throws if:
466
+ - State references a path ID not in `pathDefinitions`
467
+ - State version is unsupported
468
+
469
+ The restored engine is fully functional — you can continue navigation, modify data, complete or cancel paths normally.
470
+ ```
package/dist/index.d.ts CHANGED
@@ -1,4 +1,20 @@
1
1
  export type PathData = Record<string, unknown>;
2
+ export interface SerializedPathState {
3
+ version: 1;
4
+ pathId: string;
5
+ currentStepIndex: number;
6
+ data: PathData;
7
+ visitedStepIds: string[];
8
+ subPathMeta?: Record<string, unknown>;
9
+ pathStack: Array<{
10
+ pathId: string;
11
+ currentStepIndex: number;
12
+ data: PathData;
13
+ visitedStepIds: string[];
14
+ subPathMeta?: Record<string, unknown>;
15
+ }>;
16
+ _isNavigating: boolean;
17
+ }
2
18
  export interface PathStepContext<TData extends PathData = PathData> {
3
19
  readonly pathId: string;
4
20
  readonly stepId: string;
@@ -101,8 +117,36 @@ export declare class PathEngine {
101
117
  private readonly pathStack;
102
118
  private readonly listeners;
103
119
  private _isNavigating;
120
+ /**
121
+ * Restores a PathEngine from previously exported state.
122
+ *
123
+ * **Important:** You must provide the same path definitions that were
124
+ * active when the state was exported. The path IDs in `state` are used
125
+ * to match against the provided definitions.
126
+ *
127
+ * @param state The serialized state from `exportState()`.
128
+ * @param pathDefinitions A map of path ID → definition. Must include the
129
+ * active path and any paths in the stack.
130
+ * @returns A new PathEngine instance with the restored state.
131
+ * @throws If `state` references a path ID not present in `pathDefinitions`,
132
+ * or if the state format is invalid.
133
+ */
134
+ static fromState(state: SerializedPathState, pathDefinitions: Record<string, PathDefinition>): PathEngine;
104
135
  subscribe(listener: (event: PathEvent) => void): () => void;
105
136
  start(path: PathDefinition<any>, initialData?: PathData): Promise<void>;
137
+ /**
138
+ * Tears down any active path (and the entire sub-path stack) without firing
139
+ * lifecycle hooks or emitting `cancelled`, then immediately starts the given
140
+ * path from scratch.
141
+ *
142
+ * Safe to call at any time — whether a path is running, already completed,
143
+ * or has never been started. Use this to implement a "Start over" button or
144
+ * to retry a path after completion without remounting the host component.
145
+ *
146
+ * @param path The path definition to (re)start.
147
+ * @param initialData Data to seed the fresh path with. Defaults to `{}`.
148
+ */
149
+ restart(path: PathDefinition<any>, initialData?: PathData): Promise<void>;
106
150
  /**
107
151
  * Starts a sub-path on top of the currently active path. Throws if no path
108
152
  * is running.
@@ -137,6 +181,18 @@ export declare class PathEngine {
137
181
  */
138
182
  goToStepChecked(stepId: string): Promise<void>;
139
183
  snapshot(): PathSnapshot | null;
184
+ /**
185
+ * Exports the current engine state as a plain JSON-serializable object.
186
+ * Use with storage adapters (e.g. `@daltonr/pathwrite-store-http`) to
187
+ * persist and restore wizard progress.
188
+ *
189
+ * Returns `null` if no path is active.
190
+ *
191
+ * **Important:** This only exports the _state_ (data, step position, etc.),
192
+ * not the path definition. When restoring, you must provide the same
193
+ * `PathDefinition` to `fromState()`.
194
+ */
195
+ exportState(): SerializedPathState | null;
140
196
  private _startAsync;
141
197
  private _nextAsync;
142
198
  private _previousAsync;
@@ -159,12 +215,27 @@ export declare class PathEngine {
159
215
  * Evaluates a guard function synchronously for inclusion in the snapshot.
160
216
  * If the guard is absent, returns `true`.
161
217
  * If the guard returns a `Promise`, returns `true` (optimistic default).
218
+ *
219
+ * **Note:** Guards are evaluated on every snapshot, including the very first one
220
+ * emitted at the start of a path — _before_ `onEnter` has run on that step.
221
+ * This means `data` will still reflect the `initialData` passed to `start()`.
222
+ * Write guards defensively (e.g. `(data.name ?? "").trim().length > 0`) so they
223
+ * do not throw when optional fields are absent on first entry.
224
+ *
225
+ * If a guard throws, the error is caught, a `console.warn` is emitted, and the
226
+ * safe default (`true`) is returned so the UI remains operable.
162
227
  */
163
228
  private evaluateGuardSync;
164
229
  /**
165
230
  * Evaluates a validationMessages function synchronously for inclusion in the snapshot.
166
231
  * If the hook is absent, returns `[]`.
167
232
  * If the hook returns a `Promise`, returns `[]` (async hooks are not supported in snapshots).
233
+ *
234
+ * **Note:** Like guards, `validationMessages` is evaluated before `onEnter` runs on first
235
+ * entry. Write it defensively so it does not throw when fields are absent.
236
+ *
237
+ * If the function throws, the error is caught, a `console.warn` is emitted, and `[]`
238
+ * is returned so validation messages do not block the UI unexpectedly.
168
239
  */
169
240
  private evaluateValidationMessagesSync;
170
241
  }
package/dist/index.js CHANGED
@@ -3,6 +3,57 @@ export class PathEngine {
3
3
  pathStack = [];
4
4
  listeners = new Set();
5
5
  _isNavigating = false;
6
+ /**
7
+ * Restores a PathEngine from previously exported state.
8
+ *
9
+ * **Important:** You must provide the same path definitions that were
10
+ * active when the state was exported. The path IDs in `state` are used
11
+ * to match against the provided definitions.
12
+ *
13
+ * @param state The serialized state from `exportState()`.
14
+ * @param pathDefinitions A map of path ID → definition. Must include the
15
+ * active path and any paths in the stack.
16
+ * @returns A new PathEngine instance with the restored state.
17
+ * @throws If `state` references a path ID not present in `pathDefinitions`,
18
+ * or if the state format is invalid.
19
+ */
20
+ static fromState(state, pathDefinitions) {
21
+ if (state.version !== 1) {
22
+ throw new Error(`Unsupported SerializedPathState version: ${state.version}`);
23
+ }
24
+ const engine = new PathEngine();
25
+ // Restore the path stack (sub-paths)
26
+ for (const stackItem of state.pathStack) {
27
+ const definition = pathDefinitions[stackItem.pathId];
28
+ if (!definition) {
29
+ throw new Error(`Cannot restore state: path definition "${stackItem.pathId}" not found. ` +
30
+ `Provide all path definitions that were active when state was exported.`);
31
+ }
32
+ engine.pathStack.push({
33
+ definition,
34
+ currentStepIndex: stackItem.currentStepIndex,
35
+ data: { ...stackItem.data },
36
+ visitedStepIds: new Set(stackItem.visitedStepIds),
37
+ subPathMeta: stackItem.subPathMeta ? { ...stackItem.subPathMeta } : undefined
38
+ });
39
+ }
40
+ // Restore the active path
41
+ const activeDefinition = pathDefinitions[state.pathId];
42
+ if (!activeDefinition) {
43
+ throw new Error(`Cannot restore state: active path definition "${state.pathId}" not found.`);
44
+ }
45
+ engine.activePath = {
46
+ definition: activeDefinition,
47
+ currentStepIndex: state.currentStepIndex,
48
+ data: { ...state.data },
49
+ visitedStepIds: new Set(state.visitedStepIds),
50
+ // Active path's subPathMeta is not serialized (it's transient metadata
51
+ // from the parent when this path was started). On restore, it's undefined.
52
+ subPathMeta: undefined
53
+ };
54
+ engine._isNavigating = state._isNavigating;
55
+ return engine;
56
+ }
6
57
  subscribe(listener) {
7
58
  this.listeners.add(listener);
8
59
  return () => this.listeners.delete(listener);
@@ -14,6 +65,25 @@ export class PathEngine {
14
65
  this.assertPathHasSteps(path);
15
66
  return this._startAsync(path, initialData);
16
67
  }
68
+ /**
69
+ * Tears down any active path (and the entire sub-path stack) without firing
70
+ * lifecycle hooks or emitting `cancelled`, then immediately starts the given
71
+ * path from scratch.
72
+ *
73
+ * Safe to call at any time — whether a path is running, already completed,
74
+ * or has never been started. Use this to implement a "Start over" button or
75
+ * to retry a path after completion without remounting the host component.
76
+ *
77
+ * @param path The path definition to (re)start.
78
+ * @param initialData Data to seed the fresh path with. Defaults to `{}`.
79
+ */
80
+ restart(path, initialData = {}) {
81
+ this.assertPathHasSteps(path);
82
+ this._isNavigating = false;
83
+ this.activePath = null;
84
+ this.pathStack.length = 0;
85
+ return this._startAsync(path, initialData);
86
+ }
17
87
  /**
18
88
  * Starts a sub-path on top of the currently active path. Throws if no path
19
89
  * is running.
@@ -47,8 +117,10 @@ export class PathEngine {
47
117
  return Promise.resolve();
48
118
  const cancelledPathId = active.definition.id;
49
119
  const cancelledData = { ...active.data };
50
- const cancelledMeta = active.subPathMeta;
51
120
  if (this.pathStack.length > 0) {
121
+ // Get meta from the parent in the stack
122
+ const parent = this.pathStack[this.pathStack.length - 1];
123
+ const cancelledMeta = parent.subPathMeta;
52
124
  return this._cancelSubPathAsync(cancelledPathId, cancelledData, cancelledMeta);
53
125
  }
54
126
  this.activePath = null;
@@ -125,6 +197,38 @@ export class PathEngine {
125
197
  data: { ...active.data }
126
198
  };
127
199
  }
200
+ /**
201
+ * Exports the current engine state as a plain JSON-serializable object.
202
+ * Use with storage adapters (e.g. `@daltonr/pathwrite-store-http`) to
203
+ * persist and restore wizard progress.
204
+ *
205
+ * Returns `null` if no path is active.
206
+ *
207
+ * **Important:** This only exports the _state_ (data, step position, etc.),
208
+ * not the path definition. When restoring, you must provide the same
209
+ * `PathDefinition` to `fromState()`.
210
+ */
211
+ exportState() {
212
+ if (this.activePath === null) {
213
+ return null;
214
+ }
215
+ const active = this.activePath;
216
+ return {
217
+ version: 1,
218
+ pathId: active.definition.id,
219
+ currentStepIndex: active.currentStepIndex,
220
+ data: { ...active.data },
221
+ visitedStepIds: Array.from(active.visitedStepIds),
222
+ pathStack: this.pathStack.map((p) => ({
223
+ pathId: p.definition.id,
224
+ currentStepIndex: p.currentStepIndex,
225
+ data: { ...p.data },
226
+ visitedStepIds: Array.from(p.visitedStepIds),
227
+ subPathMeta: p.subPathMeta ? { ...p.subPathMeta } : undefined
228
+ })),
229
+ _isNavigating: this._isNavigating
230
+ };
231
+ }
128
232
  // ---------------------------------------------------------------------------
129
233
  // Private async helpers
130
234
  // ---------------------------------------------------------------------------
@@ -132,14 +236,19 @@ export class PathEngine {
132
236
  if (this._isNavigating)
133
237
  return;
134
238
  if (this.activePath !== null) {
135
- this.pathStack.push(this.activePath);
239
+ // Store the meta on the parent before pushing to stack
240
+ const parentWithMeta = {
241
+ ...this.activePath,
242
+ subPathMeta
243
+ };
244
+ this.pathStack.push(parentWithMeta);
136
245
  }
137
246
  this.activePath = {
138
247
  definition: path,
139
248
  currentStepIndex: 0,
140
249
  data: { ...initialData },
141
250
  visitedStepIds: new Set(),
142
- subPathMeta
251
+ subPathMeta: undefined
143
252
  };
144
253
  this._isNavigating = true;
145
254
  await this.skipSteps(1);
@@ -297,10 +406,11 @@ export class PathEngine {
297
406
  const finished = this.requireActivePath();
298
407
  const finishedPathId = finished.definition.id;
299
408
  const finishedData = { ...finished.data };
300
- const finishedMeta = finished.subPathMeta;
301
409
  if (this.pathStack.length > 0) {
302
- this.activePath = this.pathStack.pop();
303
- const parent = this.activePath;
410
+ const parent = this.pathStack.pop();
411
+ // The meta is stored on the parent, not the sub-path
412
+ const finishedMeta = parent.subPathMeta;
413
+ this.activePath = parent;
304
414
  const parentStep = this.getCurrentStep(parent);
305
415
  if (parentStep.onSubPathComplete) {
306
416
  const ctx = {
@@ -433,6 +543,15 @@ export class PathEngine {
433
543
  * Evaluates a guard function synchronously for inclusion in the snapshot.
434
544
  * If the guard is absent, returns `true`.
435
545
  * If the guard returns a `Promise`, returns `true` (optimistic default).
546
+ *
547
+ * **Note:** Guards are evaluated on every snapshot, including the very first one
548
+ * emitted at the start of a path — _before_ `onEnter` has run on that step.
549
+ * This means `data` will still reflect the `initialData` passed to `start()`.
550
+ * Write guards defensively (e.g. `(data.name ?? "").trim().length > 0`) so they
551
+ * do not throw when optional fields are absent on first entry.
552
+ *
553
+ * If a guard throws, the error is caught, a `console.warn` is emitted, and the
554
+ * safe default (`true`) is returned so the UI remains operable.
436
555
  */
437
556
  evaluateGuardSync(guard, active) {
438
557
  if (!guard)
@@ -444,15 +563,37 @@ export class PathEngine {
444
563
  data: { ...active.data },
445
564
  isFirstEntry: !active.visitedStepIds.has(step.id)
446
565
  };
447
- const result = guard(ctx);
448
- if (typeof result === "boolean")
449
- return result;
450
- return true;
566
+ try {
567
+ const result = guard(ctx);
568
+ if (typeof result === "boolean")
569
+ return result;
570
+ // Async guard detected - warn and return optimistic default
571
+ if (result && typeof result.then === "function") {
572
+ console.warn(`[pathwrite] Async guard detected on step "${step.id}". ` +
573
+ `Guards in snapshots must be synchronous. ` +
574
+ `Returning true (optimistic) as default. ` +
575
+ `The async guard will still be enforced during actual navigation.`);
576
+ }
577
+ return true;
578
+ }
579
+ catch (err) {
580
+ console.warn(`[pathwrite] Guard on step "${step.id}" threw an error during snapshot evaluation. ` +
581
+ `Returning true (allow navigation) as a safe default. ` +
582
+ `Note: guards are evaluated before onEnter runs on first entry — ` +
583
+ `ensure guards handle missing/undefined data gracefully.`, err);
584
+ return true;
585
+ }
451
586
  }
452
587
  /**
453
588
  * Evaluates a validationMessages function synchronously for inclusion in the snapshot.
454
589
  * If the hook is absent, returns `[]`.
455
590
  * If the hook returns a `Promise`, returns `[]` (async hooks are not supported in snapshots).
591
+ *
592
+ * **Note:** Like guards, `validationMessages` is evaluated before `onEnter` runs on first
593
+ * entry. Write it defensively so it does not throw when fields are absent.
594
+ *
595
+ * If the function throws, the error is caught, a `console.warn` is emitted, and `[]`
596
+ * is returned so validation messages do not block the UI unexpectedly.
456
597
  */
457
598
  evaluateValidationMessagesSync(fn, active) {
458
599
  if (!fn)
@@ -464,10 +605,26 @@ export class PathEngine {
464
605
  data: { ...active.data },
465
606
  isFirstEntry: !active.visitedStepIds.has(step.id)
466
607
  };
467
- const result = fn(ctx);
468
- if (Array.isArray(result))
469
- return result;
470
- return [];
608
+ try {
609
+ const result = fn(ctx);
610
+ if (Array.isArray(result))
611
+ return result;
612
+ // Async validationMessages detected - warn and return empty array
613
+ if (result && typeof result.then === "function") {
614
+ console.warn(`[pathwrite] Async validationMessages detected on step "${step.id}". ` +
615
+ `validationMessages in snapshots must be synchronous. ` +
616
+ `Returning [] as default. ` +
617
+ `Use synchronous validation or move async checks to canMoveNext.`);
618
+ }
619
+ return [];
620
+ }
621
+ catch (err) {
622
+ console.warn(`[pathwrite] validationMessages on step "${step.id}" threw an error during snapshot evaluation. ` +
623
+ `Returning [] as a safe default. ` +
624
+ `Note: validationMessages is evaluated before onEnter runs on first entry — ` +
625
+ `ensure it handles missing/undefined data gracefully.`, err);
626
+ return [];
627
+ }
471
628
  }
472
629
  }
473
630
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@daltonr/pathwrite-core",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Headless path engine — deterministic state machine with stack-based sub-path orchestration. Zero dependencies.",
package/src/index.ts CHANGED
@@ -1,5 +1,22 @@
1
1
  export type PathData = Record<string, unknown>;
2
2
 
3
+ export interface SerializedPathState {
4
+ version: 1;
5
+ pathId: string;
6
+ currentStepIndex: number;
7
+ data: PathData;
8
+ visitedStepIds: string[];
9
+ subPathMeta?: Record<string, unknown>;
10
+ pathStack: Array<{
11
+ pathId: string;
12
+ currentStepIndex: number;
13
+ data: PathData;
14
+ visitedStepIds: string[];
15
+ subPathMeta?: Record<string, unknown>;
16
+ }>;
17
+ _isNavigating: boolean;
18
+ }
19
+
3
20
  export interface PathStepContext<TData extends PathData = PathData> {
4
21
  readonly pathId: string;
5
22
  readonly stepId: string;
@@ -121,6 +138,71 @@ export class PathEngine {
121
138
  private readonly listeners = new Set<(event: PathEvent) => void>();
122
139
  private _isNavigating = false;
123
140
 
141
+ /**
142
+ * Restores a PathEngine from previously exported state.
143
+ *
144
+ * **Important:** You must provide the same path definitions that were
145
+ * active when the state was exported. The path IDs in `state` are used
146
+ * to match against the provided definitions.
147
+ *
148
+ * @param state The serialized state from `exportState()`.
149
+ * @param pathDefinitions A map of path ID → definition. Must include the
150
+ * active path and any paths in the stack.
151
+ * @returns A new PathEngine instance with the restored state.
152
+ * @throws If `state` references a path ID not present in `pathDefinitions`,
153
+ * or if the state format is invalid.
154
+ */
155
+ public static fromState(
156
+ state: SerializedPathState,
157
+ pathDefinitions: Record<string, PathDefinition>
158
+ ): PathEngine {
159
+ if (state.version !== 1) {
160
+ throw new Error(`Unsupported SerializedPathState version: ${state.version}`);
161
+ }
162
+
163
+ const engine = new PathEngine();
164
+
165
+ // Restore the path stack (sub-paths)
166
+ for (const stackItem of state.pathStack) {
167
+ const definition = pathDefinitions[stackItem.pathId];
168
+ if (!definition) {
169
+ throw new Error(
170
+ `Cannot restore state: path definition "${stackItem.pathId}" not found. ` +
171
+ `Provide all path definitions that were active when state was exported.`
172
+ );
173
+ }
174
+ engine.pathStack.push({
175
+ definition,
176
+ currentStepIndex: stackItem.currentStepIndex,
177
+ data: { ...stackItem.data },
178
+ visitedStepIds: new Set(stackItem.visitedStepIds),
179
+ subPathMeta: stackItem.subPathMeta ? { ...stackItem.subPathMeta } : undefined
180
+ });
181
+ }
182
+
183
+ // Restore the active path
184
+ const activeDefinition = pathDefinitions[state.pathId];
185
+ if (!activeDefinition) {
186
+ throw new Error(
187
+ `Cannot restore state: active path definition "${state.pathId}" not found.`
188
+ );
189
+ }
190
+
191
+ engine.activePath = {
192
+ definition: activeDefinition,
193
+ currentStepIndex: state.currentStepIndex,
194
+ data: { ...state.data },
195
+ visitedStepIds: new Set(state.visitedStepIds),
196
+ // Active path's subPathMeta is not serialized (it's transient metadata
197
+ // from the parent when this path was started). On restore, it's undefined.
198
+ subPathMeta: undefined
199
+ };
200
+
201
+ engine._isNavigating = state._isNavigating;
202
+
203
+ return engine;
204
+ }
205
+
124
206
  public subscribe(listener: (event: PathEvent) => void): () => void {
125
207
  this.listeners.add(listener);
126
208
  return () => this.listeners.delete(listener);
@@ -135,6 +217,26 @@ export class PathEngine {
135
217
  return this._startAsync(path, initialData);
136
218
  }
137
219
 
220
+ /**
221
+ * Tears down any active path (and the entire sub-path stack) without firing
222
+ * lifecycle hooks or emitting `cancelled`, then immediately starts the given
223
+ * path from scratch.
224
+ *
225
+ * Safe to call at any time — whether a path is running, already completed,
226
+ * or has never been started. Use this to implement a "Start over" button or
227
+ * to retry a path after completion without remounting the host component.
228
+ *
229
+ * @param path The path definition to (re)start.
230
+ * @param initialData Data to seed the fresh path with. Defaults to `{}`.
231
+ */
232
+ public restart(path: PathDefinition<any>, initialData: PathData = {}): Promise<void> {
233
+ this.assertPathHasSteps(path);
234
+ this._isNavigating = false;
235
+ this.activePath = null;
236
+ this.pathStack.length = 0;
237
+ return this._startAsync(path, initialData);
238
+ }
239
+
138
240
  /**
139
241
  * Starts a sub-path on top of the currently active path. Throws if no path
140
242
  * is running.
@@ -171,9 +273,11 @@ export class PathEngine {
171
273
 
172
274
  const cancelledPathId = active.definition.id;
173
275
  const cancelledData = { ...active.data };
174
- const cancelledMeta = active.subPathMeta;
175
276
 
176
277
  if (this.pathStack.length > 0) {
278
+ // Get meta from the parent in the stack
279
+ const parent = this.pathStack[this.pathStack.length - 1];
280
+ const cancelledMeta = parent.subPathMeta;
177
281
  return this._cancelSubPathAsync(cancelledPathId, cancelledData, cancelledMeta);
178
282
  }
179
283
 
@@ -258,6 +362,41 @@ export class PathEngine {
258
362
  };
259
363
  }
260
364
 
365
+ /**
366
+ * Exports the current engine state as a plain JSON-serializable object.
367
+ * Use with storage adapters (e.g. `@daltonr/pathwrite-store-http`) to
368
+ * persist and restore wizard progress.
369
+ *
370
+ * Returns `null` if no path is active.
371
+ *
372
+ * **Important:** This only exports the _state_ (data, step position, etc.),
373
+ * not the path definition. When restoring, you must provide the same
374
+ * `PathDefinition` to `fromState()`.
375
+ */
376
+ public exportState(): SerializedPathState | null {
377
+ if (this.activePath === null) {
378
+ return null;
379
+ }
380
+
381
+ const active = this.activePath;
382
+
383
+ return {
384
+ version: 1,
385
+ pathId: active.definition.id,
386
+ currentStepIndex: active.currentStepIndex,
387
+ data: { ...active.data },
388
+ visitedStepIds: Array.from(active.visitedStepIds),
389
+ pathStack: this.pathStack.map((p) => ({
390
+ pathId: p.definition.id,
391
+ currentStepIndex: p.currentStepIndex,
392
+ data: { ...p.data },
393
+ visitedStepIds: Array.from(p.visitedStepIds),
394
+ subPathMeta: p.subPathMeta ? { ...p.subPathMeta } : undefined
395
+ })),
396
+ _isNavigating: this._isNavigating
397
+ };
398
+ }
399
+
261
400
  // ---------------------------------------------------------------------------
262
401
  // Private async helpers
263
402
  // ---------------------------------------------------------------------------
@@ -266,7 +405,12 @@ export class PathEngine {
266
405
  if (this._isNavigating) return;
267
406
 
268
407
  if (this.activePath !== null) {
269
- this.pathStack.push(this.activePath);
408
+ // Store the meta on the parent before pushing to stack
409
+ const parentWithMeta: ActivePath = {
410
+ ...this.activePath,
411
+ subPathMeta
412
+ };
413
+ this.pathStack.push(parentWithMeta);
270
414
  }
271
415
 
272
416
  this.activePath = {
@@ -274,7 +418,7 @@ export class PathEngine {
274
418
  currentStepIndex: 0,
275
419
  data: { ...initialData },
276
420
  visitedStepIds: new Set(),
277
- subPathMeta
421
+ subPathMeta: undefined
278
422
  };
279
423
 
280
424
  this._isNavigating = true;
@@ -463,11 +607,12 @@ export class PathEngine {
463
607
  const finished = this.requireActivePath();
464
608
  const finishedPathId = finished.definition.id;
465
609
  const finishedData = { ...finished.data };
466
- const finishedMeta = finished.subPathMeta;
467
610
 
468
611
  if (this.pathStack.length > 0) {
469
- this.activePath = this.pathStack.pop()!;
470
- const parent = this.activePath;
612
+ const parent = this.pathStack.pop()!;
613
+ // The meta is stored on the parent, not the sub-path
614
+ const finishedMeta = parent.subPathMeta;
615
+ this.activePath = parent;
471
616
  const parentStep = this.getCurrentStep(parent);
472
617
 
473
618
  if (parentStep.onSubPathComplete) {
@@ -620,6 +765,15 @@ export class PathEngine {
620
765
  * Evaluates a guard function synchronously for inclusion in the snapshot.
621
766
  * If the guard is absent, returns `true`.
622
767
  * If the guard returns a `Promise`, returns `true` (optimistic default).
768
+ *
769
+ * **Note:** Guards are evaluated on every snapshot, including the very first one
770
+ * emitted at the start of a path — _before_ `onEnter` has run on that step.
771
+ * This means `data` will still reflect the `initialData` passed to `start()`.
772
+ * Write guards defensively (e.g. `(data.name ?? "").trim().length > 0`) so they
773
+ * do not throw when optional fields are absent on first entry.
774
+ *
775
+ * If a guard throws, the error is caught, a `console.warn` is emitted, and the
776
+ * safe default (`true`) is returned so the UI remains operable.
623
777
  */
624
778
  private evaluateGuardSync(
625
779
  guard: ((ctx: PathStepContext) => boolean | Promise<boolean>) | undefined,
@@ -633,15 +787,41 @@ export class PathEngine {
633
787
  data: { ...active.data },
634
788
  isFirstEntry: !active.visitedStepIds.has(step.id)
635
789
  };
636
- const result = guard(ctx);
637
- if (typeof result === "boolean") return result;
638
- return true;
790
+ try {
791
+ const result = guard(ctx);
792
+ if (typeof result === "boolean") return result;
793
+ // Async guard detected - warn and return optimistic default
794
+ if (result && typeof result.then === "function") {
795
+ console.warn(
796
+ `[pathwrite] Async guard detected on step "${step.id}". ` +
797
+ `Guards in snapshots must be synchronous. ` +
798
+ `Returning true (optimistic) as default. ` +
799
+ `The async guard will still be enforced during actual navigation.`
800
+ );
801
+ }
802
+ return true;
803
+ } catch (err) {
804
+ console.warn(
805
+ `[pathwrite] Guard on step "${step.id}" threw an error during snapshot evaluation. ` +
806
+ `Returning true (allow navigation) as a safe default. ` +
807
+ `Note: guards are evaluated before onEnter runs on first entry — ` +
808
+ `ensure guards handle missing/undefined data gracefully.`,
809
+ err
810
+ );
811
+ return true;
812
+ }
639
813
  }
640
814
 
641
815
  /**
642
816
  * Evaluates a validationMessages function synchronously for inclusion in the snapshot.
643
817
  * If the hook is absent, returns `[]`.
644
818
  * If the hook returns a `Promise`, returns `[]` (async hooks are not supported in snapshots).
819
+ *
820
+ * **Note:** Like guards, `validationMessages` is evaluated before `onEnter` runs on first
821
+ * entry. Write it defensively so it does not throw when fields are absent.
822
+ *
823
+ * If the function throws, the error is caught, a `console.warn` is emitted, and `[]`
824
+ * is returned so validation messages do not block the UI unexpectedly.
645
825
  */
646
826
  private evaluateValidationMessagesSync(
647
827
  fn: ((ctx: PathStepContext) => string[] | Promise<string[]>) | undefined,
@@ -655,9 +835,29 @@ export class PathEngine {
655
835
  data: { ...active.data },
656
836
  isFirstEntry: !active.visitedStepIds.has(step.id)
657
837
  };
658
- const result = fn(ctx);
659
- if (Array.isArray(result)) return result;
660
- return [];
838
+ try {
839
+ const result = fn(ctx);
840
+ if (Array.isArray(result)) return result;
841
+ // Async validationMessages detected - warn and return empty array
842
+ if (result && typeof result.then === "function") {
843
+ console.warn(
844
+ `[pathwrite] Async validationMessages detected on step "${step.id}". ` +
845
+ `validationMessages in snapshots must be synchronous. ` +
846
+ `Returning [] as default. ` +
847
+ `Use synchronous validation or move async checks to canMoveNext.`
848
+ );
849
+ }
850
+ return [];
851
+ } catch (err) {
852
+ console.warn(
853
+ `[pathwrite] validationMessages on step "${step.id}" threw an error during snapshot evaluation. ` +
854
+ `Returning [] as a safe default. ` +
855
+ `Note: validationMessages is evaluated before onEnter runs on first entry — ` +
856
+ `ensure it handles missing/undefined data gracefully.`,
857
+ err
858
+ );
859
+ return [];
860
+ }
661
861
  }
662
862
  }
663
863