@daltonr/pathwrite-core 0.1.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Richard Dalton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @daltonr/pathwrite-core
2
+
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
+
5
+ ## Key types
6
+
7
+ ```typescript
8
+ // Define your path's data shape once
9
+ interface CourseData extends PathData {
10
+ courseName: string;
11
+ subjects: SubjectEntry[];
12
+ }
13
+
14
+ const path: PathDefinition<CourseData> = {
15
+ id: "course-path",
16
+ steps: [
17
+ {
18
+ id: "details",
19
+ canMoveNext: (ctx) => ctx.data.courseName.length > 0,
20
+ onLeave: (ctx) => ({ courseName: ctx.data.courseName.trim() })
21
+ },
22
+ { id: "review" }
23
+ ]
24
+ };
25
+ ```
26
+
27
+ | Type | Description |
28
+ |------|-------------|
29
+ | `PathDefinition<TData>` | A path's ID, title, and ordered list of step definitions. |
30
+ | `PathStep<TData>` | A single step: guards, lifecycle hooks. |
31
+ | `PathStepContext<TData>` | Passed to every hook and guard. `data` is a **readonly snapshot copy** — return a patch to update state. |
32
+ | `PathSnapshot<TData>` | Point-in-time read of the engine: step ID, index, count, flags, and a copy of data. |
33
+ | `PathEvent` | Union of `stateChanged`, `completed`, `cancelled`, and `resumed`. |
34
+
35
+ ## PathEngine API
36
+
37
+ ```typescript
38
+ const engine = new PathEngine();
39
+
40
+ engine.start(definition, initialData?); // start or re-start a path
41
+ engine.startSubPath(definition, data?); // push sub-path onto the stack (requires active path)
42
+ engine.next();
43
+ engine.previous();
44
+ engine.cancel();
45
+ engine.setData(key, value); // update a single data value; emits stateChanged
46
+ engine.snapshot(); // returns PathSnapshot | null
47
+
48
+ const unsubscribe = engine.subscribe((event) => { ... });
49
+ unsubscribe(); // remove the listener
50
+ ```
51
+
52
+ ## Lifecycle hooks
53
+
54
+ All hooks are optional. Hooks that want to update data **return a partial patch** — the engine applies it automatically. Direct mutation of `ctx.data` is a no-op; the context receives a copy.
55
+
56
+ | Hook | When called | Can return patch |
57
+ |------|-------------|-----------------|
58
+ | `onEnter` | On arrival at a step (start, next, previous, resume) | ✅ |
59
+ | `onLeave` | On departure from a step (only when the guard allows) | ✅ |
60
+ | `onSubPathComplete` | On the parent step when a sub-path finishes | ✅ |
61
+ | `canMoveNext` | Before advancing — return `false` to block | — |
62
+ | `canMovePrevious` | Before going back — return `false` to block | — |
63
+
64
+ ### Example — sub-path result merged into parent data
65
+
66
+ ```typescript
67
+ {
68
+ id: "subjects-list",
69
+ onSubPathComplete: (_id, subData, ctx) => ({
70
+ subjects: [...(ctx.data.subjects ?? []), { name: subData.name, teacher: subData.teacher }]
71
+ })
72
+ }
73
+ ```
74
+
75
+ ## Sub-path flow
76
+
77
+ ```
78
+ engine.start(mainPath) → stack: [] active: main
79
+ engine.startSubPath(subPath) → stack: [main] active: sub
80
+ engine.next() // sub finishes
81
+ → onSubPathComplete fires on the parent step
82
+ → stack: [] active: main
83
+ ```
84
+
85
+ Cancelling a sub-path pops it off the stack silently — `onSubPathComplete` is **not** called.
86
+
87
+ ## Events
88
+
89
+ ```typescript
90
+ engine.subscribe((event) => {
91
+ switch (event.type) {
92
+ case "stateChanged": // event.snapshot
93
+ case "completed": // event.pathId, event.data
94
+ case "cancelled": // event.pathId, event.data
95
+ case "resumed": // event.resumedPathId, event.fromSubPathId, event.snapshot
96
+ }
97
+ });
98
+ ```
@@ -0,0 +1,96 @@
1
+ export type PathData = Record<string, unknown>;
2
+ export interface PathStepContext<TData extends PathData = PathData> {
3
+ readonly pathId: string;
4
+ readonly stepId: string;
5
+ readonly data: Readonly<TData>;
6
+ }
7
+ export interface PathStep<TData extends PathData = PathData> {
8
+ id: string;
9
+ title?: string;
10
+ meta?: Record<string, unknown>;
11
+ shouldSkip?: (ctx: PathStepContext<TData>) => boolean | Promise<boolean>;
12
+ canMoveNext?: (ctx: PathStepContext<TData>) => boolean | Promise<boolean>;
13
+ canMovePrevious?: (ctx: PathStepContext<TData>) => boolean | Promise<boolean>;
14
+ onEnter?: (ctx: PathStepContext<TData>) => Partial<TData> | void | Promise<Partial<TData> | void>;
15
+ onLeave?: (ctx: PathStepContext<TData>) => Partial<TData> | void | Promise<Partial<TData> | void>;
16
+ onSubPathComplete?: (subPathId: string, subPathData: PathData, ctx: PathStepContext<TData>) => Partial<TData> | void | Promise<Partial<TData> | void>;
17
+ }
18
+ export interface PathDefinition<TData extends PathData = PathData> {
19
+ id: string;
20
+ title?: string;
21
+ steps: PathStep<TData>[];
22
+ }
23
+ export type StepStatus = "completed" | "current" | "upcoming";
24
+ export interface StepSummary {
25
+ id: string;
26
+ title?: string;
27
+ meta?: Record<string, unknown>;
28
+ status: StepStatus;
29
+ }
30
+ export interface PathSnapshot<TData extends PathData = PathData> {
31
+ pathId: string;
32
+ stepId: string;
33
+ stepTitle?: string;
34
+ stepMeta?: Record<string, unknown>;
35
+ stepIndex: number;
36
+ stepCount: number;
37
+ progress: number;
38
+ steps: StepSummary[];
39
+ isFirstStep: boolean;
40
+ isLastStep: boolean;
41
+ nestingLevel: number;
42
+ /** True while an async guard or hook is executing. Use to disable navigation controls. */
43
+ isNavigating: boolean;
44
+ data: TData;
45
+ }
46
+ export type PathEvent = {
47
+ type: "stateChanged";
48
+ snapshot: PathSnapshot;
49
+ } | {
50
+ type: "completed";
51
+ pathId: string;
52
+ data: PathData;
53
+ } | {
54
+ type: "cancelled";
55
+ pathId: string;
56
+ data: PathData;
57
+ } | {
58
+ type: "resumed";
59
+ resumedPathId: string;
60
+ fromSubPathId: string;
61
+ snapshot: PathSnapshot;
62
+ };
63
+ export declare class PathEngine {
64
+ private activePath;
65
+ private readonly pathStack;
66
+ private readonly listeners;
67
+ private _isNavigating;
68
+ subscribe(listener: (event: PathEvent) => void): () => void;
69
+ start(path: PathDefinition, initialData?: PathData): Promise<void>;
70
+ /** Starts a sub-path on top of the currently active path. Throws if no path is running. */
71
+ startSubPath(path: PathDefinition, initialData?: PathData): Promise<void>;
72
+ next(): Promise<void>;
73
+ previous(): Promise<void>;
74
+ /** Cancel is synchronous (no hooks). Returns a resolved Promise for API consistency. */
75
+ cancel(): Promise<void>;
76
+ setData(key: string, value: unknown): Promise<void>;
77
+ /** Jumps directly to the step with the given ID. Does not check guards or shouldSkip. */
78
+ goToStep(stepId: string): Promise<void>;
79
+ snapshot(): PathSnapshot | null;
80
+ private _startAsync;
81
+ private _nextAsync;
82
+ private _previousAsync;
83
+ private _goToStepAsync;
84
+ private finishActivePath;
85
+ private requireActivePath;
86
+ private assertPathHasSteps;
87
+ private emit;
88
+ private emitStateChanged;
89
+ private getCurrentStep;
90
+ private applyPatch;
91
+ private skipSteps;
92
+ private enterCurrentStep;
93
+ private leaveCurrentStep;
94
+ private canMoveNext;
95
+ private canMovePrevious;
96
+ }
package/dist/index.js ADDED
@@ -0,0 +1,325 @@
1
+ export class PathEngine {
2
+ activePath = null;
3
+ pathStack = [];
4
+ listeners = new Set();
5
+ _isNavigating = false;
6
+ subscribe(listener) {
7
+ this.listeners.add(listener);
8
+ return () => this.listeners.delete(listener);
9
+ }
10
+ // ---------------------------------------------------------------------------
11
+ // Public API
12
+ // ---------------------------------------------------------------------------
13
+ start(path, initialData = {}) {
14
+ this.assertPathHasSteps(path);
15
+ return this._startAsync(path, initialData);
16
+ }
17
+ /** Starts a sub-path on top of the currently active path. Throws if no path is running. */
18
+ startSubPath(path, initialData = {}) {
19
+ this.requireActivePath();
20
+ return this.start(path, initialData);
21
+ }
22
+ next() {
23
+ const active = this.requireActivePath();
24
+ return this._nextAsync(active);
25
+ }
26
+ previous() {
27
+ const active = this.requireActivePath();
28
+ return this._previousAsync(active);
29
+ }
30
+ /** Cancel is synchronous (no hooks). Returns a resolved Promise for API consistency. */
31
+ cancel() {
32
+ const active = this.requireActivePath();
33
+ if (this._isNavigating)
34
+ return Promise.resolve();
35
+ const cancelledPathId = active.definition.id;
36
+ const cancelledData = { ...active.data };
37
+ if (this.pathStack.length > 0) {
38
+ this.activePath = this.pathStack.pop() ?? null;
39
+ this.emitStateChanged();
40
+ return Promise.resolve();
41
+ }
42
+ this.activePath = null;
43
+ this.emit({ type: "cancelled", pathId: cancelledPathId, data: cancelledData });
44
+ return Promise.resolve();
45
+ }
46
+ setData(key, value) {
47
+ const active = this.requireActivePath();
48
+ active.data[key] = value;
49
+ this.emitStateChanged();
50
+ return Promise.resolve();
51
+ }
52
+ /** Jumps directly to the step with the given ID. Does not check guards or shouldSkip. */
53
+ goToStep(stepId) {
54
+ const active = this.requireActivePath();
55
+ const targetIndex = active.definition.steps.findIndex((s) => s.id === stepId);
56
+ if (targetIndex === -1) {
57
+ throw new Error(`Step "${stepId}" not found in path "${active.definition.id}".`);
58
+ }
59
+ return this._goToStepAsync(active, targetIndex);
60
+ }
61
+ snapshot() {
62
+ if (this.activePath === null) {
63
+ return null;
64
+ }
65
+ const active = this.activePath;
66
+ const step = this.getCurrentStep(active);
67
+ const { steps } = active.definition;
68
+ const stepCount = steps.length;
69
+ return {
70
+ pathId: active.definition.id,
71
+ stepId: step.id,
72
+ stepTitle: step.title,
73
+ stepMeta: step.meta,
74
+ stepIndex: active.currentStepIndex,
75
+ stepCount,
76
+ progress: stepCount <= 1 ? 1 : active.currentStepIndex / (stepCount - 1),
77
+ steps: steps.map((s, i) => ({
78
+ id: s.id,
79
+ title: s.title,
80
+ meta: s.meta,
81
+ status: i < active.currentStepIndex ? "completed"
82
+ : i === active.currentStepIndex ? "current"
83
+ : "upcoming"
84
+ })),
85
+ isFirstStep: active.currentStepIndex === 0,
86
+ isLastStep: active.currentStepIndex === stepCount - 1 &&
87
+ this.pathStack.length === 0,
88
+ nestingLevel: this.pathStack.length,
89
+ isNavigating: this._isNavigating,
90
+ data: { ...active.data }
91
+ };
92
+ }
93
+ // ---------------------------------------------------------------------------
94
+ // Private async helpers
95
+ // ---------------------------------------------------------------------------
96
+ async _startAsync(path, initialData) {
97
+ if (this._isNavigating)
98
+ return;
99
+ if (this.activePath !== null) {
100
+ this.pathStack.push(this.activePath);
101
+ }
102
+ this.activePath = {
103
+ definition: path,
104
+ currentStepIndex: 0,
105
+ data: { ...initialData }
106
+ };
107
+ this._isNavigating = true;
108
+ await this.skipSteps(1);
109
+ if (this.activePath.currentStepIndex >= path.steps.length) {
110
+ this._isNavigating = false;
111
+ await this.finishActivePath();
112
+ return;
113
+ }
114
+ this.emitStateChanged();
115
+ try {
116
+ this.applyPatch(await this.enterCurrentStep());
117
+ this._isNavigating = false;
118
+ this.emitStateChanged();
119
+ }
120
+ catch (err) {
121
+ this._isNavigating = false;
122
+ this.emitStateChanged();
123
+ throw err;
124
+ }
125
+ }
126
+ async _nextAsync(active) {
127
+ if (this._isNavigating)
128
+ return;
129
+ this._isNavigating = true;
130
+ this.emitStateChanged();
131
+ try {
132
+ const step = this.getCurrentStep(active);
133
+ if (await this.canMoveNext(active, step)) {
134
+ this.applyPatch(await this.leaveCurrentStep(active, step));
135
+ active.currentStepIndex += 1;
136
+ await this.skipSteps(1);
137
+ }
138
+ if (active.currentStepIndex >= active.definition.steps.length) {
139
+ this._isNavigating = false;
140
+ await this.finishActivePath();
141
+ return;
142
+ }
143
+ this.applyPatch(await this.enterCurrentStep());
144
+ this._isNavigating = false;
145
+ this.emitStateChanged();
146
+ }
147
+ catch (err) {
148
+ this._isNavigating = false;
149
+ this.emitStateChanged();
150
+ throw err;
151
+ }
152
+ }
153
+ async _previousAsync(active) {
154
+ if (this._isNavigating)
155
+ return;
156
+ this._isNavigating = true;
157
+ this.emitStateChanged();
158
+ try {
159
+ const step = this.getCurrentStep(active);
160
+ if (await this.canMovePrevious(active, step)) {
161
+ this.applyPatch(await this.leaveCurrentStep(active, step));
162
+ active.currentStepIndex -= 1;
163
+ await this.skipSteps(-1);
164
+ }
165
+ if (active.currentStepIndex < 0) {
166
+ this._isNavigating = false;
167
+ await this.cancel();
168
+ return;
169
+ }
170
+ this.applyPatch(await this.enterCurrentStep());
171
+ this._isNavigating = false;
172
+ this.emitStateChanged();
173
+ }
174
+ catch (err) {
175
+ this._isNavigating = false;
176
+ this.emitStateChanged();
177
+ throw err;
178
+ }
179
+ }
180
+ async _goToStepAsync(active, targetIndex) {
181
+ if (this._isNavigating)
182
+ return;
183
+ this._isNavigating = true;
184
+ this.emitStateChanged();
185
+ try {
186
+ const currentStep = this.getCurrentStep(active);
187
+ this.applyPatch(await this.leaveCurrentStep(active, currentStep));
188
+ active.currentStepIndex = targetIndex;
189
+ this.applyPatch(await this.enterCurrentStep());
190
+ this._isNavigating = false;
191
+ this.emitStateChanged();
192
+ }
193
+ catch (err) {
194
+ this._isNavigating = false;
195
+ this.emitStateChanged();
196
+ throw err;
197
+ }
198
+ }
199
+ async finishActivePath() {
200
+ const finished = this.requireActivePath();
201
+ const finishedPathId = finished.definition.id;
202
+ const finishedData = { ...finished.data };
203
+ if (this.pathStack.length > 0) {
204
+ this.activePath = this.pathStack.pop();
205
+ const parent = this.activePath;
206
+ const parentStep = this.getCurrentStep(parent);
207
+ if (parentStep.onSubPathComplete) {
208
+ const ctx = {
209
+ pathId: parent.definition.id,
210
+ stepId: parentStep.id,
211
+ data: { ...parent.data }
212
+ };
213
+ this.applyPatch(await parentStep.onSubPathComplete(finishedPathId, finishedData, ctx));
214
+ }
215
+ this.emit({
216
+ type: "resumed",
217
+ resumedPathId: parent.definition.id,
218
+ fromSubPathId: finishedPathId,
219
+ snapshot: this.snapshot()
220
+ });
221
+ }
222
+ else {
223
+ this.activePath = null;
224
+ this.emit({ type: "completed", pathId: finishedPathId, data: finishedData });
225
+ }
226
+ }
227
+ // ---------------------------------------------------------------------------
228
+ // Private helpers
229
+ // ---------------------------------------------------------------------------
230
+ requireActivePath() {
231
+ if (this.activePath === null) {
232
+ throw new Error("No active path.");
233
+ }
234
+ return this.activePath;
235
+ }
236
+ assertPathHasSteps(path) {
237
+ if (!path.steps || path.steps.length === 0) {
238
+ throw new Error(`Path "${path.id}" must have at least one step.`);
239
+ }
240
+ }
241
+ emit(event) {
242
+ for (const listener of this.listeners) {
243
+ listener(event);
244
+ }
245
+ }
246
+ emitStateChanged() {
247
+ this.emit({ type: "stateChanged", snapshot: this.snapshot() });
248
+ }
249
+ getCurrentStep(active) {
250
+ return active.definition.steps[active.currentStepIndex];
251
+ }
252
+ applyPatch(patch) {
253
+ if (patch && typeof patch === "object") {
254
+ const active = this.activePath;
255
+ if (active) {
256
+ Object.assign(active.data, patch);
257
+ }
258
+ }
259
+ }
260
+ async skipSteps(direction) {
261
+ const active = this.activePath;
262
+ if (!active)
263
+ return;
264
+ while (active.currentStepIndex >= 0 &&
265
+ active.currentStepIndex < active.definition.steps.length) {
266
+ const step = active.definition.steps[active.currentStepIndex];
267
+ if (!step.shouldSkip)
268
+ break;
269
+ const ctx = {
270
+ pathId: active.definition.id,
271
+ stepId: step.id,
272
+ data: { ...active.data }
273
+ };
274
+ const skip = await step.shouldSkip(ctx);
275
+ if (!skip)
276
+ break;
277
+ active.currentStepIndex += direction;
278
+ }
279
+ }
280
+ async enterCurrentStep() {
281
+ const active = this.activePath;
282
+ if (!active)
283
+ return;
284
+ const step = this.getCurrentStep(active);
285
+ if (!step.onEnter)
286
+ return;
287
+ const ctx = {
288
+ pathId: active.definition.id,
289
+ stepId: step.id,
290
+ data: { ...active.data }
291
+ };
292
+ return step.onEnter(ctx);
293
+ }
294
+ async leaveCurrentStep(active, step) {
295
+ if (!step.onLeave)
296
+ return;
297
+ const ctx = {
298
+ pathId: active.definition.id,
299
+ stepId: step.id,
300
+ data: { ...active.data }
301
+ };
302
+ return step.onLeave(ctx);
303
+ }
304
+ async canMoveNext(active, step) {
305
+ if (!step.canMoveNext)
306
+ return true;
307
+ const ctx = {
308
+ pathId: active.definition.id,
309
+ stepId: step.id,
310
+ data: { ...active.data }
311
+ };
312
+ return step.canMoveNext(ctx);
313
+ }
314
+ async canMovePrevious(active, step) {
315
+ if (!step.canMovePrevious)
316
+ return true;
317
+ const ctx = {
318
+ pathId: active.definition.id,
319
+ stepId: step.id,
320
+ data: { ...active.data }
321
+ };
322
+ return step.canMovePrevious(ctx);
323
+ }
324
+ }
325
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@daltonr/pathwrite-core",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "license": "MIT",
6
+ "description": "Headless path engine — deterministic state machine with stack-based sub-path orchestration. Zero dependencies.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/richardadalton/pathwrite.git",
10
+ "directory": "packages/core"
11
+ },
12
+ "keywords": [
13
+ "wizard",
14
+ "stepper",
15
+ "path",
16
+ "state-machine",
17
+ "multi-step",
18
+ "workflow",
19
+ "headless"
20
+ ],
21
+ "sideEffects": false,
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "main": "dist/index.js",
29
+ "types": "dist/index.d.ts",
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc -p tsconfig.json",
37
+ "clean": "rm -rf dist tsconfig.tsbuildinfo",
38
+ "prepublishOnly": "npm run clean && npm run build"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }