@rxova/journey-core 0.6.0 → 0.6.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 +78 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,11 +11,13 @@ npm i @rxova/journey-core
|
|
|
11
11
|
## What You Get
|
|
12
12
|
|
|
13
13
|
- Deterministic transition matching (first match wins).
|
|
14
|
-
- Timeline + pointer navigation model.
|
|
15
|
-
- Built-in
|
|
14
|
+
- Timeline + pointer navigation model (`history.timeline` + `history.index`).
|
|
15
|
+
- Built-in navigation and terminal events:
|
|
16
|
+
`goToNextStep()`, `goToPreviousStep()`, `goToLastVisitedStep()`, `completeJourney()`, `terminateJourney()`.
|
|
17
|
+
- Async guard/effect lifecycle state in `snapshot.async`.
|
|
16
18
|
- Typed observability stream via `subscribeEvent`.
|
|
17
19
|
- Step metadata updates via `updateStepMetadata`.
|
|
18
|
-
- Optional persistence
|
|
20
|
+
- Optional persistence with schema versioning and migration hooks.
|
|
19
21
|
|
|
20
22
|
## Quickstart
|
|
21
23
|
|
|
@@ -48,6 +50,72 @@ const snapshot = machine.getSnapshot();
|
|
|
48
50
|
console.log(snapshot.history.timeline, snapshot.history.index, snapshot.currentStepId);
|
|
49
51
|
```
|
|
50
52
|
|
|
53
|
+
## Behavioral Guarantees
|
|
54
|
+
|
|
55
|
+
- Transition selection is ordered: the first matching transition wins.
|
|
56
|
+
- `send({ type: "back" })` falls back to previous-step navigation when no explicit `back` transition exists.
|
|
57
|
+
- Once status is `complete` or `terminated`, pointer navigation and transitions no-op until `resetMachine()`.
|
|
58
|
+
- Forward navigation after moving back truncates timeline tail before appending the next step.
|
|
59
|
+
- Snapshot shape is stable: `currentStepId === history.timeline[history.index]`.
|
|
60
|
+
|
|
61
|
+
## Async Lifecycle
|
|
62
|
+
|
|
63
|
+
When guards/effects are async, step async state is tracked in `snapshot.async.byStep[stepId]`:
|
|
64
|
+
|
|
65
|
+
- `evaluating-when`: async guard in progress
|
|
66
|
+
- `running-effect`: async effect in progress
|
|
67
|
+
- `error`: guard/effect rejected
|
|
68
|
+
- `idle`: no active async work
|
|
69
|
+
|
|
70
|
+
`clearStepError(stepId?)` resets a step from `error` to `idle`.
|
|
71
|
+
|
|
72
|
+
## Persistence
|
|
73
|
+
|
|
74
|
+
Persistence is optional and disabled automatically if storage is unavailable.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const machine = createJourneyMachine(journey, {
|
|
78
|
+
persistence: {
|
|
79
|
+
key: "checkout:journey",
|
|
80
|
+
version: 2,
|
|
81
|
+
clearOnReset: false,
|
|
82
|
+
migrate: (legacySnapshot, persistedVersion) => {
|
|
83
|
+
if (persistedVersion < 2) {
|
|
84
|
+
return {
|
|
85
|
+
currentStepId: "start",
|
|
86
|
+
history: { timeline: ["start"], index: 0 },
|
|
87
|
+
context: { name: "" },
|
|
88
|
+
status: "running",
|
|
89
|
+
visited: { start: true, review: false },
|
|
90
|
+
stepMeta: { start: undefined, review: undefined }
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return legacySnapshot as never;
|
|
94
|
+
},
|
|
95
|
+
onError: (error) => {
|
|
96
|
+
console.error("Persistence error", error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Hydration coercion is defensive: malformed timeline/index/visited/status values fall back to safe defaults.
|
|
103
|
+
|
|
104
|
+
## Observability
|
|
105
|
+
|
|
106
|
+
Use `subscribeEvent` to inspect transition and navigation lifecycle events:
|
|
107
|
+
|
|
108
|
+
- `transition.start`
|
|
109
|
+
- `transition.success`
|
|
110
|
+
- `transition.error`
|
|
111
|
+
- `step.exit`
|
|
112
|
+
- `step.enter`
|
|
113
|
+
- `navigation.previous`
|
|
114
|
+
- `navigation.lastVisited`
|
|
115
|
+
- `journey.complete`
|
|
116
|
+
- `journey.close`
|
|
117
|
+
- `metadata.updated`
|
|
118
|
+
|
|
51
119
|
## Transition Ergonomics
|
|
52
120
|
|
|
53
121
|
```ts
|
|
@@ -55,6 +123,13 @@ import { createTransitions, tx } from "@rxova/journey-core";
|
|
|
55
123
|
|
|
56
124
|
const transitions = createTransitions(
|
|
57
125
|
tx.from("start").on("goToNextStep").to("review"),
|
|
126
|
+
tx
|
|
127
|
+
.from("review")
|
|
128
|
+
.on("goToNextStep")
|
|
129
|
+
.choose(
|
|
130
|
+
tx.when(({ context }) => context.canSubmit).to("done", { id: "review-submit" }),
|
|
131
|
+
tx.otherwise().to("review", { id: "review-stay" })
|
|
132
|
+
),
|
|
58
133
|
tx.from("review").toComplete()
|
|
59
134
|
);
|
|
60
135
|
```
|