@rxova/journey-core 1.0.0 → 1.0.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 +24 -24
- package/dist/connectors/immer/immer.cjs.map +1 -1
- package/dist/connectors/immer/immer.js.map +1 -1
- package/dist/core/helpers.d.cts +0 -6
- package/dist/core/helpers.d.ts +0 -6
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/linear/linear.types.d.cts +1 -1
- package/dist/linear/linear.types.d.ts +1 -1
- package/dist/plugins/execution-paths/execution-paths.d.cts +1 -1
- package/dist/plugins/execution-paths/execution-paths.d.ts +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.cjs.map +3 -3
- package/dist/plugins/index.d.cts +6 -6
- package/dist/plugins/index.d.ts +6 -6
- package/dist/plugins/index.js +1 -1
- package/dist/plugins/index.js.map +3 -3
- package/dist/plugins/persistence/persistence.d.cts +1 -1
- package/dist/plugins/persistence/persistence.d.ts +1 -1
- package/package.json +6 -7
package/README.md
CHANGED
|
@@ -38,17 +38,17 @@ const checkout = createLinearJourney<CheckoutStepId, CheckoutContext, CheckoutTe
|
|
|
38
38
|
steps: [
|
|
39
39
|
{ id: "account", metadata: { title: "Account" } },
|
|
40
40
|
{ id: "shipping", metadata: { title: "Shipping" } },
|
|
41
|
-
{ id: "review", metadata: { title: "Review" } }
|
|
41
|
+
{ id: "review", metadata: { title: "Review" } },
|
|
42
42
|
],
|
|
43
43
|
context: {
|
|
44
44
|
email: "",
|
|
45
|
-
shippingId: null
|
|
46
|
-
}
|
|
45
|
+
shippingId: null,
|
|
46
|
+
},
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
checkout.context.update((context) => ({
|
|
50
50
|
...context,
|
|
51
|
-
email: "ada@example.com"
|
|
51
|
+
email: "ada@example.com",
|
|
52
52
|
}));
|
|
53
53
|
|
|
54
54
|
await checkout.navigate.goToNextStep();
|
|
@@ -60,7 +60,7 @@ needed:
|
|
|
60
60
|
```ts
|
|
61
61
|
createLinearJourney({
|
|
62
62
|
steps: ["account", "shipping", "review"],
|
|
63
|
-
context: {}
|
|
63
|
+
context: {},
|
|
64
64
|
});
|
|
65
65
|
```
|
|
66
66
|
|
|
@@ -78,9 +78,9 @@ const result = await checkout.navigate.goToNextStep({
|
|
|
78
78
|
commit: ({ result: shipping, updateContext }) => {
|
|
79
79
|
updateContext((context) => ({
|
|
80
80
|
...context,
|
|
81
|
-
shippingId: shipping.id
|
|
81
|
+
shippingId: shipping.id,
|
|
82
82
|
}));
|
|
83
|
-
}
|
|
83
|
+
},
|
|
84
84
|
});
|
|
85
85
|
|
|
86
86
|
if (!result.ok) {
|
|
@@ -120,16 +120,16 @@ const machine = createLinearJourney({
|
|
|
120
120
|
steps: [
|
|
121
121
|
{
|
|
122
122
|
id: "payment",
|
|
123
|
-
onLeave: ({ snapshot }) => analytics.track("payment_left", snapshot.context)
|
|
123
|
+
onLeave: ({ snapshot }) => analytics.track("payment_left", snapshot.context),
|
|
124
124
|
},
|
|
125
125
|
{
|
|
126
126
|
id: "receipt",
|
|
127
127
|
onEnter: async ({ snapshot, updateContext }) => {
|
|
128
128
|
const receipt = await loadReceipt(snapshot.context);
|
|
129
129
|
updateContext((context) => ({ ...context, receiptId: receipt.id }));
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
]
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
133
|
});
|
|
134
134
|
```
|
|
135
135
|
|
|
@@ -216,7 +216,7 @@ one edge so a single slow third-party call does not set the budget for the whole
|
|
|
216
216
|
|
|
217
217
|
For larger graphs, `withGraphTypes<Bag>()` pins the types once and `GraphStep<Bag>` lets each step live in its own file, and
|
|
218
218
|
`defineWork<Bag, "EVENT">()` reads a work entry's result type off its `run` instead of restating it
|
|
219
|
-
in the bag. See the [Graph guide](https://rxova.
|
|
219
|
+
in the bag. See the [Graph guide](https://rxova.dev/docs/core/usage/graph).
|
|
220
220
|
|
|
221
221
|
## Connectors
|
|
222
222
|
|
|
@@ -234,13 +234,13 @@ machine.context.update(
|
|
|
234
234
|
immerConnector<CheckoutContext>((draft) => {
|
|
235
235
|
draft.cart.items.push(item);
|
|
236
236
|
draft.cart.total += item.price;
|
|
237
|
-
})
|
|
237
|
+
}),
|
|
238
238
|
);
|
|
239
239
|
```
|
|
240
240
|
|
|
241
241
|
It also works with the `updateContext` passed to hooks and transactional commits. Immer remains an
|
|
242
242
|
optional peer, so consumers that do not import this connector do not install or bundle it. See the
|
|
243
|
-
[Immer connector guide](https://rxova.
|
|
243
|
+
[Immer connector guide](https://rxova.dev/docs/core/connectors/immer) for replacement recipes,
|
|
244
244
|
freezing, draftability, and transactional behavior.
|
|
245
245
|
|
|
246
246
|
## Plugins
|
|
@@ -254,9 +254,9 @@ import { createAnalyticsPlugin } from "@rxova/journey-core/plugins";
|
|
|
254
254
|
const machine = createLinearJourney(definition, {
|
|
255
255
|
plugins: [
|
|
256
256
|
createAnalyticsPlugin({
|
|
257
|
-
track: (event) => analytics.track(event.name, event.payload)
|
|
258
|
-
})
|
|
259
|
-
]
|
|
257
|
+
track: (event) => analytics.track(event.name, event.payload),
|
|
258
|
+
}),
|
|
259
|
+
],
|
|
260
260
|
});
|
|
261
261
|
```
|
|
262
262
|
|
|
@@ -266,13 +266,13 @@ transitions and cycles without creating a machine.
|
|
|
266
266
|
|
|
267
267
|
## Documentation
|
|
268
268
|
|
|
269
|
-
- [Quickstart](https://rxova.
|
|
270
|
-
- [Linear journeys](https://rxova.
|
|
271
|
-
- [Async behavior](https://rxova.
|
|
272
|
-
- [Machine API](https://rxova.
|
|
273
|
-
- [Snapshot](https://rxova.
|
|
274
|
-
- [Pre-1.0 migration](https://rxova.
|
|
275
|
-
- [Stability contract](https://rxova.
|
|
269
|
+
- [Quickstart](https://rxova.dev/docs/core/getting-started)
|
|
270
|
+
- [Linear journeys](https://rxova.dev/docs/core/usage/linear)
|
|
271
|
+
- [Async behavior](https://rxova.dev/docs/core/async)
|
|
272
|
+
- [Machine API](https://rxova.dev/docs/core/api/machine-api)
|
|
273
|
+
- [Snapshot](https://rxova.dev/docs/core/snapshot)
|
|
274
|
+
- [Pre-1.0 migration](https://rxova.dev/docs/core/pre-1-0-migration)
|
|
275
|
+
- [Stability contract](https://rxova.dev/docs/core/stability)
|
|
276
276
|
|
|
277
277
|
## License
|
|
278
278
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/connectors/immer/immer.ts"],
|
|
4
|
-
"sourcesContent": ["import { produce } from \"immer\";\nimport type { ContextUpdater } from \"../../core/types\";\nimport type { ImmerContextRecipe } from \"./immer.types\";\n\nexport type { ImmerContextRecipe } from \"./immer.types\";\n\n/**\n * Converts a synchronous Immer recipe into a Journey context updater.\n *\n * Pass the result to `machine.context.update`, a hook's `updateContext`, or a\n * transactional work commit. Immer supplies structural sharing and applies its\n * normal draftability and auto-freezing behavior.\n */\nexport function immerConnector<TContext>(\n recipe: ImmerContextRecipe<TContext
|
|
4
|
+
"sourcesContent": ["import { produce } from \"immer\";\nimport type { ContextUpdater } from \"../../core/types\";\nimport type { ImmerContextRecipe } from \"./immer.types\";\n\nexport type { ImmerContextRecipe } from \"./immer.types\";\n\n/**\n * Converts a synchronous Immer recipe into a Journey context updater.\n *\n * Pass the result to `machine.context.update`, a hook's `updateContext`, or a\n * transactional work commit. Immer supplies structural sharing and applies its\n * normal draftability and auto-freezing behavior.\n */\nexport function immerConnector<TContext>(\n recipe: ImmerContextRecipe<TContext>,\n): ContextUpdater<TContext> {\n return (previous) => produce(previous, recipe);\n}\n"],
|
|
5
5
|
"mappings": "yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,oBAAAE,IAAA,eAAAC,EAAAH,GAAA,IAAAI,EAAwB,iBAajB,SAASF,EACdG,EAC0B,CAC1B,OAAQC,MAAa,WAAQA,EAAUD,CAAM,CAC/C",
|
|
6
6
|
"names": ["immer_exports", "__export", "immerConnector", "__toCommonJS", "import_immer", "recipe", "previous"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/connectors/immer/immer.ts"],
|
|
4
|
-
"sourcesContent": ["import { produce } from \"immer\";\nimport type { ContextUpdater } from \"../../core/types\";\nimport type { ImmerContextRecipe } from \"./immer.types\";\n\nexport type { ImmerContextRecipe } from \"./immer.types\";\n\n/**\n * Converts a synchronous Immer recipe into a Journey context updater.\n *\n * Pass the result to `machine.context.update`, a hook's `updateContext`, or a\n * transactional work commit. Immer supplies structural sharing and applies its\n * normal draftability and auto-freezing behavior.\n */\nexport function immerConnector<TContext>(\n recipe: ImmerContextRecipe<TContext
|
|
4
|
+
"sourcesContent": ["import { produce } from \"immer\";\nimport type { ContextUpdater } from \"../../core/types\";\nimport type { ImmerContextRecipe } from \"./immer.types\";\n\nexport type { ImmerContextRecipe } from \"./immer.types\";\n\n/**\n * Converts a synchronous Immer recipe into a Journey context updater.\n *\n * Pass the result to `machine.context.update`, a hook's `updateContext`, or a\n * transactional work commit. Immer supplies structural sharing and applies its\n * normal draftability and auto-freezing behavior.\n */\nexport function immerConnector<TContext>(\n recipe: ImmerContextRecipe<TContext>,\n): ContextUpdater<TContext> {\n return (previous) => produce(previous, recipe);\n}\n"],
|
|
5
5
|
"mappings": "AAAA,OAAS,WAAAA,MAAe,QAajB,SAASC,EACdC,EAC0B,CAC1B,OAAQC,GAAaH,EAAQG,EAAUD,CAAM,CAC/C",
|
|
6
6
|
"names": ["produce", "immerConnector", "recipe", "previous"]
|
|
7
7
|
}
|
package/dist/core/helpers.d.cts
CHANGED
|
@@ -38,9 +38,3 @@ export declare const LOADING_ASYNC: StepAsyncState;
|
|
|
38
38
|
export declare const hasOwn: (target: object, key: string) => boolean;
|
|
39
39
|
/** Subscriber exceptions are isolated so one listener cannot break the pipeline. */
|
|
40
40
|
export declare function reportListenerError(error: unknown): void;
|
|
41
|
-
/**
|
|
42
|
-
* Object.is over own enumerable keys — for flat snapshot sub-objects. The
|
|
43
|
-
* key check is load-bearing: equal key counts alone would call `{a: undefined}`
|
|
44
|
-
* and `{b: undefined}` equal, since both read `undefined` at every compared key.
|
|
45
|
-
*/
|
|
46
|
-
export declare const shallowEqual: (a: Readonly<Record<string, unknown>>, b: Readonly<Record<string, unknown>>) => boolean;
|
package/dist/core/helpers.d.ts
CHANGED
|
@@ -38,9 +38,3 @@ export declare const LOADING_ASYNC: StepAsyncState;
|
|
|
38
38
|
export declare const hasOwn: (target: object, key: string) => boolean;
|
|
39
39
|
/** Subscriber exceptions are isolated so one listener cannot break the pipeline. */
|
|
40
40
|
export declare function reportListenerError(error: unknown): void;
|
|
41
|
-
/**
|
|
42
|
-
* Object.is over own enumerable keys — for flat snapshot sub-objects. The
|
|
43
|
-
* key check is load-bearing: equal key counts alone would call `{a: undefined}`
|
|
44
|
-
* and `{b: undefined}` equal, since both read `undefined` at every compared key.
|
|
45
|
-
*/
|
|
46
|
-
export declare const shallowEqual: (a: Readonly<Record<string, unknown>>, b: Readonly<Record<string, unknown>>) => boolean;
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var j=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var de=Object.prototype.hasOwnProperty;var ce=(n,e)=>{for(var t in e)j(n,t,{get:e[t],enumerable:!0})},he=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of pe(e))!de.call(n,s)&&s!==t&&j(n,s,{get:()=>e[s],enumerable:!(r=le(e,s))||r.enumerable});return n};var ge=n=>he(j({},"__esModule",{value:!0}),n);var be={};ce(be,{JourneyError:()=>m,analyzeStructure:()=>ue,createGraphJourney:()=>F,createLinearJourney:()=>U,defineWork:()=>ae,isJourneyError:()=>Q,withGraphTypes:()=>oe,withLinearTypes:()=>re});module.exports=ge(be);var m=class extends Error{constructor(e,t,r={},s){super(`journey: ${t}`,s===void 0?void 0:{cause:s}),this.name="JourneyError",this.code=e,this.stepId=r.stepId,this.event=r.event,this.pluginName=r.pluginName}},Q=n=>n instanceof m;var R=(n,e)=>`${n.length}:${n}${e}`,Y=n=>n.label??`${n.event}[${n.index}] (${n.from} -> ${n.to})`,K=n=>n===null?null:{event:n.event,from:n.from,to:n.to,label:n.label??null,index:n.index},x=Object.freeze({isLoading:!1,isSuccess:!0,isError:!1,error:null}),A=Object.freeze({isLoading:!0,isSuccess:!1,isError:!1,error:null}),S=(n,e)=>Object.hasOwn(n,e);function D(n){console.error("[journey] subscriber threw:",n)}var E=(n,e)=>{let t=Object.keys(n);return t.length!==Object.keys(e).length?!1:t.every(r=>S(e,r)&&Object.is(n[r],e[r]))};function C(n){return{getSnapshot:()=>n.store.getSnapshot(),controls:{start:()=>n.start(),pause:()=>n.pause(),resume:()=>n.resume(),complete:e=>n.complete(e),terminate:e=>n.terminate(e),restart:()=>n.restart()},dispose:()=>n.dispose(),navigate:{goToStepById:e=>n.goToStepById(e),goToPreviousStep:e=>n.goToPreviousStep(e),goToNextStep:e=>n.goToNextStep(e),goToLastVisitedStep:()=>n.goToLastVisitedStep()},subscriptions:{subscribe:e=>n.store.subscribe(e),subscribeEvent:(e,t)=>n.store.subscribeEvent(e,t)},context:{update:e=>n.updateContext(e)},async:{clearError:()=>n.clearAsyncError()},plugins:n.pluginApis}}var G=()=>{let n=globalThis;if(typeof n.__DEV__=="boolean")return n.__DEV__;let e=n.process?.env?.NODE_ENV;return e===void 0||e==="development"},q=(n,e)=>{if(!(!G()||typeof console>"u")){if(e===void 0){console.warn(n);return}console.warn("%s",n,e)}};var N=class{constructor(e,t){this.listeners=new Set;this.eventListeners=new Map;this.disposed=!1;this.snapshot=e,this.onListenerError=t}report(e){if(!this.onListenerError){D(e);return}try{this.onListenerError(e)}catch(t){D(t)}}getSnapshot(){return this.snapshot}publish(e){if(!Object.is(this.snapshot,e)){this.snapshot=e;for(let t of[...this.listeners])try{t()}catch(r){this.report(r)}}}subscribe(e){return this.disposed?()=>{}:(this.listeners.add(e),()=>{this.listeners.delete(e)})}subscribeEvent(e,t){if(this.disposed)return()=>{};let r=this.eventListeners.get(e);return r||(r=new Set,this.eventListeners.set(e,r)),r.add(t),()=>{r.delete(t)}}emit(e,t){let r=this.eventListeners.get(e);if(r)for(let s of[...r])try{s(t)}catch(a){this.report(a)}}dispose(){this.disposed=!0,this.listeners.clear(),this.eventListeners.clear()}};var B=n=>typeof n=="object"&&n!==null&&G()?Object.freeze(n):n,fe=Object.freeze({}),Z=Object.freeze({}),w=(n,e)=>e!=null&&E(n,e)?e:Object.freeze(n),I=(n,e,t=Object.is)=>e!==void 0&&e.length===n.length&&n.every((r,s)=>t(r,e[s]))?e:Object.freeze([...n]),ye=(n,e)=>n===void 0?"none":e?"passed":"failed",P=class{constructor(e){this.pluginApis={};this.status="idle";this.timeline=[];this.currentIndex=-1;this.outcome=null;this.visitCounts=new Map;this.entryAsync=x;this.pending=null;this.disposed=!1;this.restoreSeed=null;this.generation=0;this.raiseQueue=[];this.processingRaised=!1;this.lastPluginExtensions={};this.lastSnapshot=null;this.transitionListeners=new Set;this.disposeCallbacks=[];this.snapshotDerivers=new Map;this.config=e,this.frozenStepOrder=Object.freeze([...e.stepIds]),this.restoreSeed=e.restore??null,this.context=B(e.restore?e.restore.context:e.initialContext),this.store=new N(this.buildSnapshot(),e.onListenerError),this.setupPlugins(),this.store.publish(this.buildSnapshot()),e.autoStart&&this.start()}start(){return this.disposed||this.status!=="idle"?!1:(this.setStatus("running"),this.enterInitialStep(),!0)}pause(){return this.disposed||this.status!=="running"||this.pending?!1:(this.setStatus("paused"),!0)}resume(){return this.disposed||this.status!=="paused"?!1:(this.setStatus("running"),!0)}complete(e){return this.disposed||this.status!=="running"||this.pending?!1:(this.outcome=Object.freeze({type:"completed",payload:e}),this.setStatus("completed"),!0)}terminate(e){return this.disposed||this.status==="terminated"?!1:(this.generation+=1,this.pending=null,this.entryAsync=x,this.raiseQueue=[],this.outcome=Object.freeze({type:"terminated",payload:e}),this.setStatus("terminated"),!0)}restart(){return this.disposed||this.status!=="completed"&&this.status!=="terminated"?!1:(this.generation+=1,this.pending=null,this.raiseQueue=[],this.timeline=[],this.currentIndex=-1,this.context=B(this.config.initialContext),this.outcome=null,this.visitCounts=new Map,this.entryAsync=x,this.setStatus("running"),this.enterInitialStep(),!0)}dispose(){if(!this.disposed){this.disposed=!0,this.generation+=1,this.pending=null,this.raiseQueue=[];for(let e of this.disposeCallbacks.splice(0))try{e()}catch{}this.transitionListeners.clear(),this.store.dispose()}}updateContext(e){if(this.disposed)return;let t=this.context;this.context=B(e(t));let r=this.publish();this.store.emit("contextChange",{snapshot:r,previous:t,current:this.context})}clearAsyncError(){this.disposed||!this.entryAsync.isError||(this.entryAsync=x,this.publish())}goToStepById(e){let t=this.checkNavigable();if(t)return this.blocked(t,e);if(!S(this.config.steps,e))return this.blocked({ok:!1,reason:"invalid-target"},e);if(e===this.currentStepId())return this.blocked({ok:!1,reason:"no-op"},e);if(this.config.kind==="graph"){let r=this.config.transitions.find(s=>s.from===this.currentStepId()&&s.to===e&&this.isEnabled(s));return r?this.runNavigation(e,{kind:"append"},this.eventFor(r),r):this.blocked({ok:!1,reason:"invalid-target"},e)}return this.runNavigation(e,{kind:"append"},null,null)}goToPreviousStep(e=1){let t=this.checkNavigable();if(t)return this.blocked(t,null);if(this.currentIndex<=0)return this.blocked({ok:!1,reason:"out-of-bounds"},null);let r=Math.max(0,this.currentIndex-Math.max(1,Math.floor(e))),s=this.timeline[r];return this.runNavigation(s,{kind:"pointer",index:r},null,null,void 0,"backward")}goToNextStep(e){let t=this.checkNavigable();if(t)return this.blocked(t,null);if(this.currentIndex<this.timeline.length-1){let r=this.currentIndex+1,s=this.timeline[r];return this.runNavigation(s,{kind:"pointer",index:r},null,null,e,"forward")}if(this.config.kind==="linear"){let r=this.config.stepIds.indexOf(this.currentStepId()??""),s=this.config.stepIds[r+1];return s===void 0?this.blocked({ok:!1,reason:"out-of-bounds"},null):this.runNavigation(s,{kind:"append"},null,null,e,"forward")}return this.blocked({ok:!1,reason:"out-of-bounds"},null)}goToLastVisitedStep(){let e=this.checkNavigable();if(e)return this.blocked(e,null);let t=this.timeline.length-1;if(this.currentIndex>=t)return this.blocked({ok:!1,reason:"no-op"},null);let r=this.timeline[t];return this.runNavigation(r,{kind:"pointer",index:t},null,null)}goToStepByIndex(e){let t=Number.isInteger(e)?this.config.stepIds[e]:void 0;return t===void 0?this.blocked({ok:!1,reason:"invalid-target"},null):this.goToStepById(t)}send(e,t,r){let s=this.checkNavigable();if(s)return this.blocked(s,null);let a=t===void 0?{type:e}:{type:e,payload:t},u=this.currentStepId(),o=r??(u===null?void 0:this.config.eventWork?.[R(u,e)]);if(o)return this.sendWithWork(e,a,o);let i=this.resolveTransition(e);return i?this.runNavigation(i.to,{kind:"append"},a,i):this.blocked({ok:!1,reason:"no-enabled-transition"},null)}async sendWithWork(e,t,r){let s=this.generation,a=this.currentStepId();if(a===null)return this.blocked({ok:!1,reason:"not-running"},null);let u=this.context,o=!1,i;this.pending={phase:"working",from:a,to:null},this.entryAsync=A,this.publish();try{let d={snapshot:this.store.getSnapshot(),from:a,event:t,handlers:this.config.handlers};if(i=await this.withTimeout(Promise.resolve(r.run(d)),`send work(${r.label??`${e} from ${a}`})`,r.timeoutMs),!this.isCurrent(s))return this.staleResult();let c=r.commit?.({...d,result:i,updateContext:h=>{u=h(u),o=!0}});if(typeof c=="object"&&c!==null&&"then"in c)throw new m("async-commit","send work commit must be synchronous")}catch(d){if(!this.isCurrent(s))return this.staleResult();this.pending=null,this.entryAsync=Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:d});let c=this.publish();return this.store.emit("error",{snapshot:c,error:d,phase:"work",stepId:a}),this.blocked({ok:!1,reason:"error",error:d},null)}if(!this.isCurrent(s))return this.staleResult();let l=this.resolveTransition(e,u,i);return l?this.commitAndSettle(a,l.to,{kind:"append"},t,l,s,u,o,"jump"):(this.pending=null,this.entryAsync=x,this.publish(),this.blocked({ok:!1,reason:"no-enabled-transition"},null))}setupPlugins(){let e={getSnapshot:()=>this.store.getSnapshot(),structure:Object.freeze({kind:this.config.kind,stepIds:Object.freeze([...this.config.stepIds]),initial:this.config.initial,transitions:Object.freeze(this.config.transitions.map(t=>Object.freeze({event:t.event,from:t.from,to:t.to,guarded:t.when!==void 0,label:t.label??null,index:t.index})))}),onTransition:t=>(this.transitionListeners.add(t),()=>this.transitionListeners.delete(t)),onNavigationBlocked:t=>this.store.subscribeEvent("navigationBlocked",t),onStatusChange:t=>this.store.subscribeEvent("statusChange",t),onContextChange:t=>this.store.subscribeEvent("contextChange",t),onError:t=>this.store.subscribeEvent("error",t),onDispose:t=>{this.disposeCallbacks.push(t)},reportError:t=>this.store.report(t)};try{for(let t of this.config.plugins){if(S(this.pluginApis,t.name))throw new m("duplicate-plugin-name",`duplicate plugin name "${t.name}"`,{pluginName:t.name});let r=t.setup(e);this.pluginApis[t.name]=r.api,r.deriveSnapshot&&this.snapshotDerivers.set(t.name,r.deriveSnapshot)}}catch(t){throw this.dispose(),t}}currentStepId(){return this.currentIndex>=0?this.timeline[this.currentIndex]:null}eventFor(e){return{type:e.event}}isEnabled(e,t=this.context,r){if(!e.when)return!0;try{return e.when({context:t,handlers:this.config.handlers,result:r})}catch{return!1}}resolveTransition(e,t=this.context,r){return this.config.transitions.find(s=>s.event===e&&s.from===this.currentStepId()&&this.isEnabled(s,t,r))}checkNavigable(){return this.disposed?{ok:!1,reason:"disposed"}:this.status!=="running"?{ok:!1,reason:"not-running"}:this.pending?{ok:!1,reason:"transitioning"}:null}setStatus(e){let t=this.status;this.status=e;let r=this.publish();this.store.emit("statusChange",{snapshot:r,previous:t,current:e}),this.refreshPluginSnapshot()}refreshPluginSnapshot(){this.snapshotDerivers.size>0&&this.publish()}blocked(e,t){if(e.reason!=="disposed"){let r={snapshot:this.store.getSnapshot(),reason:e.reason,from:this.currentStepId(),to:t};"error"in e&&(r.error=e.error),this.store.emit("navigationBlocked",r)}return Promise.resolve({...e,from:this.currentStepId(),to:t})}hookArgs(e,t,r,s){return{snapshot:this.store.getSnapshot(),from:e,to:t,event:r,transition:s,updateContext:a=>this.updateContext(a),raise:a=>{this.config.kind!=="graph"||this.disposed||this.raiseQueue.push(a)}}}async invokeEffect(e,t,r,s){if(!e)return null;try{return await this.withTimeout(Promise.resolve(e(t)),r,s),null}catch(a){return{error:a}}}withTimeout(e,t,r){let s=r??this.config.defaultTimeoutMs;return s===void 0?e:new Promise((a,u)=>{let o=setTimeout(()=>u(new Error(`journey: ${t} timed out after ${s}ms`)),s);e.then(i=>{clearTimeout(o),a(i)},i=>{clearTimeout(o),u(i)})})}async enterInitialStep(){let e=this.generation,t=this.restoreSeed;if(this.restoreSeed=null,t){let s=t.timeline[t.currentIndex];this.pending={phase:"entering",from:null,to:s},this.timeline=[...t.timeline],this.currentIndex=t.currentIndex;for(let a of t.timeline)this.visitCounts.set(a,(this.visitCounts.get(a)??0)+1);this.commitEntry(null,s,"jump"),await this.runEntryEffects(null,s,null,null,e);return}let r=this.config.startAt??this.config.initial;this.pending={phase:"entering",from:null,to:r},this.timeline=[r],this.currentIndex=0,this.commitEntry(null,r,"jump"),await this.runEntryEffects(null,r,null,null,e)}async runNavigation(e,t,r,s,a,u){let o=this.generation,i=this.currentStepId(),l=this.context,d=!1;if(a&&i!==null&&u){this.pending={phase:"working",from:i,to:e},this.entryAsync=A,this.publish();try{let c={snapshot:this.store.getSnapshot(),from:i,to:e,direction:u},h=await this.withTimeout(Promise.resolve(a.run(c)),`${u} navigation work(${i} -> ${e})`,a.timeoutMs);if(!this.isCurrent(o))return this.staleResult();let f=a.commit?.({...c,result:h,updateContext:y=>{l=y(l),d=!0}});if(typeof f=="object"&&f!==null&&"then"in f)throw new m("async-commit","navigation work commit must be synchronous")}catch(c){if(!this.isCurrent(o))return this.staleResult();this.pending=null,this.entryAsync=Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:c});let h=this.publish();return this.store.emit("error",{snapshot:h,error:c,phase:"work",stepId:i}),this.blocked({ok:!1,reason:"error",error:c},e)}}return this.isCurrent(o)?this.commitAndSettle(i,e,t,r,s,o,l,d,u??"jump"):this.staleResult()}async commitAndSettle(e,t,r,s,a,u,o,i,l){let d=this.context;r.kind==="pointer"?this.currentIndex=r.index:(this.timeline=[...this.timeline.slice(0,this.currentIndex+1),t],this.currentIndex=this.timeline.length-1),i&&(this.context=B(o));let c=e===null?void 0:this.config.steps[e];return this.pending={phase:c?.onLeave?"leaving":"entering",from:e,to:t},this.commitEntry(e,t,l,i?{previous:d,current:o}:void 0,c?.onLeave!==void 0||a?.onTransition!==void 0),await this.runEntryEffects(e,t,s,a,u),{ok:!0,from:e,to:t}}commitEntry(e,t,r,s,a=!1){this.visitCounts.set(t,(this.visitCounts.get(t)??0)+1);let u=this.config.steps[t];this.entryAsync=a||u?.onEnter?A:x;let o=this.publish();s&&this.store.emit("contextChange",{snapshot:o,...s}),e!==null&&this.store.emit("stepLeave",{snapshot:o,from:e,to:t}),this.store.emit("stepEnter",{snapshot:o,from:e,to:t,direction:r})}async runEntryEffects(e,t,r,s,a){let u=e===null?void 0:this.config.steps[e],o=this.config.steps[t],i=K(s),l=[],d=await this.invokeEffect(u?.onLeave,this.hookArgs(e,t,r,i),`onLeave(${e??""})`);if(!this.isCurrent(a))return;d&&e!==null&&l.push({error:d.error,phase:"leave",stepId:e}),this.pending={phase:"entering",from:e,to:t},this.publish();let c=await this.invokeEffect(s?.onTransition,this.hookArgs(e,t,r,i),`onTransition(${s?Y(s):r?.type??""})`,s?.timeoutMs);if(!this.isCurrent(a))return;c&&l.push({error:c.error,phase:"transition",stepId:t});let h=await this.invokeEffect(o?.onEnter,this.hookArgs(e,t,r,i),`onEnter(${t})`);if(!this.isCurrent(a))return;h&&l.push({error:h.error,phase:"enter",stepId:t}),this.entryAsync=l[0]?Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:l[0].error}):x,this.pending=null;let f=this.publish();for(let y of l)this.store.emit("error",{snapshot:f,error:y.error,phase:y.phase,stepId:y.stepId});for(let y of[...this.transitionListeners])try{y({from:e,to:t,snapshot:f})}catch{}this.refreshPluginSnapshot(),this.processRaisedEvents(a)}async processRaisedEvents(e){if(this.processingRaised||!this.isCurrent(e))return;this.processingRaised=!0;let t=0;try{for(;this.raiseQueue.length>0&&this.isCurrent(e);){if(this.status!=="running"){this.raiseQueue=[];return}if(t+=1,t>25){this.raiseQueue=[],this.store.emit("error",{snapshot:this.store.getSnapshot(),error:new Error(`journey: raised-event cascade exceeded ${25} events; queue dropped`),phase:"raise",stepId:this.currentStepId()});return}let r=this.raiseQueue.shift();await this.send(r.type,r.payload)}}finally{this.processingRaised=!1}}isCurrent(e){return!this.disposed&&e===this.generation}staleResult(){let e=this.currentStepId();return this.disposed?{ok:!1,reason:"disposed",from:e,to:null}:{ok:!1,reason:"not-running",from:e,to:null}}publish(){let e=this.buildSnapshot();return this.store.publish(e),e}buildSnapshot(){let e=this.lastSnapshot,t=this.currentStepId(),r={},s=0;for(let h of this.config.stepIds){let f=(this.visitCounts.get(h)??0)>0;r[h]=f,f&&(s+=1)}let a=e?.history,u=a!=null&&E(a.visited,r)?a.visited:Object.freeze(r),o={status:this.status,context:this.context,transition:w({pending:this.pending!==null,phase:this.pending?.phase??null,from:this.pending?.from??null,to:this.pending?.to??null},e?.transition),history:w({timeline:I(this.timeline,a?.timeline),currentIndex:this.currentIndex,visited:u,canGoBack:this.currentIndex>0,canGoForward:this.currentIndex>=0&&this.currentIndex<this.timeline.length-1},a),machine:w({outcome:this.outcome},e?.machine)},i=t===null?null:{id:t,metadata:this.config.steps[t]?.metadata??fe,isFirstTimeVisit:(this.visitCounts.get(t)??0)===1,async:this.entryAsync},l;if(this.config.kind==="linear"){let h=e?.type==="linear"?e:null,f=t===null?-1:this.config.stepIds.indexOf(t);l={...o,type:"linear",currentStep:i===null?null:w({...i,index:f,isFirstStep:f===0,isLastStep:f===this.config.stepIds.length-1},h?.currentStep),steps:w({totalSteps:this.config.stepIds.length,stepOrder:this.frozenStepOrder,visitedStepCount:s},h?.steps),plugins:Z}}else{let h=[],f=[],y=[],g=[],p=new Map,T=new Set,b=!1;if(t!==null)for(let v of this.config.transitions){if(v.from!==t)continue;b=!0,h.includes(v.event)||h.push(v.event);let J=p.get(v.event)??0;p.set(v.event,J+1);let O=this.isEnabled(v),V=O&&!T.has(v.event);V&&T.add(v.event),g.push(Object.freeze({event:v.event,to:v.to,priority:J,guard:ye(v.when,O),enabled:O,selected:V})),O&&(f.includes(v.event)||f.push(v.event),y.includes(v.to)||y.push(v.to))}let k=e?.type==="graph"?e:null;l={...o,type:"graph",currentStep:i===null?null:w({...i,isTerminal:!b},k?.currentStep),steps:w({totalSteps:this.config.stepIds.length,visitedStepCount:s},k?.steps),declaredEvents:I(h,k?.declaredEvents),availableEvents:I(f,k?.availableEvents),availableSteps:I(y,k?.availableSteps),outgoingTransitions:I(g,k?.outgoingTransitions,(v,J)=>E(v,J)),plugins:Z}}if(this.snapshotDerivers.size>0){let h={};for(let[y,g]of this.snapshotDerivers)try{h[y]=g(l,this.lastPluginExtensions[y])}catch(p){this.store.report(p),S(this.lastPluginExtensions,y)&&(h[y]=this.lastPluginExtensions[y])}this.lastPluginExtensions=h;let f=e?.plugins;l={...l,plugins:f!=null&&E(f,h)?f:Object.freeze(h)}}let d=Object.freeze(l),c=e!==null&&E(d,e)?e:d;return this.lastSnapshot=c,c}};var ee=["context","transition","status"];function te(n){return typeof n!="number"||!Number.isFinite(n)?0:Math.max(0,Math.trunc(n))}function ne(n,e){return{status:n.status,context:n.context,timeline:n.history.timeline,currentIndex:n.history.currentIndex,savedAt:e}}var me=new Set(["idle","running","paused","completed","terminated"]),ve=["__proto__","constructor","prototype"];function W(n,e=0){if(e>50||n===null||typeof n!="object")return n;if(Array.isArray(n))return n.map(r=>W(r,e+1));let t={};for(let[r,s]of Object.entries(n))ve.includes(r)||(t[r]=W(s,e+1));return t}function $(n){if(n===null)return null;let e;try{e=JSON.parse(n)}catch{return null}if(typeof e!="object"||e===null)return null;let t=e;return typeof t.status!="string"||!me.has(t.status)||!Array.isArray(t.timeline)||!t.timeline.every(r=>typeof r=="string")||typeof t.currentIndex!="number"||!Number.isInteger(t.currentIndex)||typeof t.savedAt!="number"||!Number.isFinite(t.savedAt)?null:{status:t.status,context:W(t.context),timeline:t.timeline,currentIndex:t.currentIndex,savedAt:t.savedAt}}function z(n){if(n.storage)return n.storage;let e;try{e=globalThis.localStorage}catch(t){throw new m("storage-unavailable","localStorage access was blocked by the environment; pass persist.storage explicitly",{},t)}if(!e)throw new m("storage-unavailable","persist.storage is required when localStorage is unavailable");return e}function L(n,e){let t;try{t=z(n).getItem(n.key)}catch{return null}let r=$(t);if(!r||r.status!=="running"&&r.status!=="paused"||!Number.isInteger(r.currentIndex)||r.currentIndex<0||r.currentIndex>=r.timeline.length)return null;for(let s of r.timeline)if(typeof s!="string"||!e(s))return null;return r}var _={status:"idle",lastSavedAt:null,error:null};function Te(n){let e=n.now??Date.now,t=te(n.debounceMs),r=new Set(n.saveOn??ee),s=0;return{name:"persistence",setup(a){s+=1,s>1&&q(`journey: persistence plugin instance shared by ${s} machines; they overwrite key "${n.key}". Create one per machine.`);let u=null,o=_,i=null,l=!1,d=p=>{u=p,o={status:"saved",lastSavedAt:p.savedAt,error:null}},c=p=>{o={...o,status:"error",error:p},a.reportError(p)},h=()=>{let p=ne(a.getSnapshot(),e());o={...o,status:"saving"};let T;try{T=n.storage.setItem(n.key,JSON.stringify(p))}catch(b){throw o={...o,status:"error",error:b},b}if(T!==void 0)return T.then(()=>d(p),c);d(p)},f=()=>{i!==null&&(clearTimeout(i),i=null)},y=()=>{i=null;try{let p=h()}catch(p){c(p)}},g=p=>{if(!(l||!r.has(p))){if(t===0){h();return}f(),o={...o,status:"pending"},i=setTimeout(y,t)}};return a.onContextChange(()=>g("context")),a.onTransition(()=>g("transition")),a.onStatusChange(({current:p})=>{if(p==="terminated"&&n.clearOnTerminate){f(),u=null,o=_,n.storage.removeItem(n.key);return}g("status")}),a.onDispose(()=>{l=!0,f()}),{api:{inspectPersistedState:()=>u,getPersistenceState:()=>o,readPersisted:()=>$(n.storage.getItem(n.key)),clearPersisted:()=>{f(),u=null,o=_;try{n.storage.removeItem(n.key)}catch(p){c(p)}},flushPersisted:async()=>{f();try{await h()}catch(p){c(p)}}},deriveSnapshot:(p,T)=>T===o?T:o}}}}function M(n){return Te({key:n.key,storage:z(n)})}function U(n,e={}){if(n.steps.length===0)throw new m("empty-definition","a linear journey needs at least one step");let t=[],r={};for(let o of n.steps){let i=typeof o=="string"?{id:o}:o;if(S(r,i.id))throw new m("duplicate-step-id",`duplicate step id "${i.id}"`,{stepId:i.id});t.push(i.id);let l={metadata:i.metadata??{}};i.onEnter&&(l.onEnter=i.onEnter),i.onLeave&&(l.onLeave=i.onLeave),r[i.id]=l}if(e.startAt!==void 0&&!S(r,e.startAt))throw new m("unknown-step",`startAt references unknown step "${e.startAt}"`,{stepId:e.startAt});let s=e.persist&&e.startAt===void 0?L(e.persist,o=>S(r,o)):null,a=new P({kind:"linear",stepIds:t,steps:r,initial:t[0],...e.startAt!==void 0?{startAt:e.startAt}:{},initialContext:n.context,...s?{restore:{context:s.context,timeline:s.timeline,currentIndex:s.currentIndex}}:{},transitions:[],handlers:void 0,autoStart:e.autoStart??!0,defaultTimeoutMs:e.defaultTimeoutMs,...e.onListenerError!==void 0?{onListenerError:e.onListenerError}:{},plugins:[...e.persist?[M(e.persist)]:[],...e.plugins??[]]}),u=C(a);return{...u,navigate:{...u.navigate,goToStepByIndex:o=>a.goToStepByIndex(o)}}}var re=()=>(n,e={})=>U(n,e);var se=(n,e,t)=>{if(typeof n!="string"||n.length===0)throw new m("invalid-label",`${e} must declare "label" as a non-empty string`,t);return n},ie=(n,e,t)=>{if(typeof n!="number"||!Number.isFinite(n)||n<=0)throw new m("invalid-timeout",`${e} must declare "timeoutMs" as a finite number greater than 0`,t);return n};function H(n){let e=Object.keys(n.steps);if(e.length===0)throw new m("empty-definition","a graph journey needs at least one step");if(!e.includes(n.initial))throw new m("unknown-initial-step",`initial step "${n.initial}" is not a declared step`,{stepId:n.initial});let t={};for(let u of e){let o=n.steps[u],i={metadata:o.metadata??{}};o.onEnter&&(i.onEnter=o.onEnter),o.onLeave&&(i.onLeave=o.onLeave),t[u]=i}let r=[],s={},a=(u,o,i,l)=>{if(!e.includes(i.to))throw new m("dangling-transition",`transition "${u}" references unknown step "${i.to}"`,{event:u,stepId:i.to});let d=`transition "${u}"[${l}] on step "${o}"`,c={event:u,from:o,to:i.to,index:l};i.when&&(c.when=i.when),i.onTransition&&(c.onTransition=i.onTransition),i.label!==void 0&&(c.label=se(i.label,d,{event:u,stepId:o})),i.timeoutMs!==void 0&&(c.timeoutMs=ie(i.timeoutMs,d,{event:u,stepId:o})),r.push(c)};for(let u of e){let o=n.steps[u]?.on;if(o)for(let[i,l]of Object.entries(o)){if(l===void 0)continue;if(typeof l=="string"){a(i,u,{to:l},0);continue}if(Array.isArray(l)){l.forEach((f,y)=>a(i,u,f,y));continue}let d=l,c=`work on "${i}" on step "${u}"`,h={run:d.run};d.commit&&(h.commit=d.commit),d.label!==void 0&&(h.label=se(d.label,c,{event:i,stepId:u})),d.timeoutMs!==void 0&&(h.timeoutMs=ie(d.timeoutMs,c,{event:i,stepId:u})),s[R(u,i)]=h,d.candidates.forEach((f,y)=>a(i,u,f,y))}}return{stepIds:e,steps:t,transitions:r,eventWork:s}}function F(n,e={}){let{stepIds:t,steps:r,transitions:s,eventWork:a}=H(n);if(e.startAt!==void 0&&!S(r,e.startAt))throw new m("unknown-step",`startAt references unknown step "${e.startAt}"`,{stepId:e.startAt});let u=e.persist&&e.startAt===void 0?L(e.persist,l=>S(r,l)):null,o=new P({kind:"graph",stepIds:t,steps:r,initial:n.initial,...e.startAt!==void 0?{startAt:e.startAt}:{},initialContext:n.context,...u?{restore:{context:u.context,timeline:u.timeline,currentIndex:u.currentIndex}}:{},transitions:s,...Object.keys(a).length>0?{eventWork:a}:{},handlers:e.handlers??n.handlers,autoStart:e.autoStart??!0,defaultTimeoutMs:e.defaultTimeoutMs,...e.onListenerError!==void 0?{onListenerError:e.onListenerError}:{},plugins:[...e.persist?[M(e.persist)]:[],...e.plugins??[]]});return{...C(o),send:(l,d)=>o.send(l,d)}}var oe=()=>(n,e={})=>F(n,e);var ae=()=>n=>n;function Se(n){let e=[],t=[...n.stepIds],r=new Set,s=new Set;n.transitions.forEach((g,p)=>{let T=`${g.from} ${g.event}`;if(s.has(T)){r.add(p),e.push({code:"shadowed-transition",severity:"warning",from:g.from,event:g.event,message:`Transition "${g.from}.${g.event}" is shadowed by an earlier unconditional candidate.`});return}g.guarded||s.add(T)});let a=n.transitions.filter((g,p)=>!r.has(p)),u=g=>a.filter(p=>p.from===g),o=new Set,i=[n.initial];for(;i.length>0;){let g=i.pop();if(!o.has(g)){o.add(g);for(let p of u(g))i.push(p.to)}}for(let g of t)o.has(g)||e.push({code:"unreachable-step",severity:"warning",stepId:g,message:`Step "${g}" is unreachable from the initial step "${n.initial}".`});let l=t.filter(g=>u(g).length===0),d=new Set,c=new Set,h=[],f=g=>{c.add(g),h.push(g);for(let p of u(g)){let T=h.indexOf(p.to);if(T>=0){let b=[...h.slice(T),p.to],k=b.join(" ");d.has(k)||(d.add(k),e.push({code:"cycle-detected",severity:"warning",from:p.from,event:p.event,steps:b,message:`Cycle detected: ${b.join(" -> ")}.`}));continue}c.has(p.to)||f(p.to)}h.pop()};f(n.initial);let y=l.some(g=>o.has(g));return y||e.push({code:"no-terminal-path",severity:"warning",stepId:n.initial,message:`No terminal step is reachable from the initial step "${n.initial}".`}),{issues:e,summary:{stepCount:t.length,reachableStepCount:o.size,unreachableStepCount:t.length-o.size,terminalStepIds:l,cycleCount:d.size,shadowedTransitionCount:r.size,terminalPathExists:y}}}function ue(n){let{stepIds:e,transitions:t}=H(n),r={kind:"graph",stepIds:e,initial:n.initial,transitions:t.map(s=>({event:s.event,from:s.from,to:s.to,guarded:s.when!==void 0,label:s.label??null,index:s.index}))};return Se(r)}0&&(module.exports={JourneyError,analyzeStructure,createGraphJourney,createLinearJourney,defineWork,isJourneyError,withGraphTypes,withLinearTypes});
|
|
1
|
+
"use strict";var j=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var pe=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var de=(n,e)=>{for(var t in e)j(n,t,{get:e[t],enumerable:!0})},he=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of pe(e))!ce.call(n,s)&&s!==t&&j(n,s,{get:()=>e[s],enumerable:!(r=le(e,s))||r.enumerable});return n};var fe=n=>he(j({},"__esModule",{value:!0}),n);var be={};de(be,{JourneyError:()=>m,analyzeStructure:()=>ue,createGraphJourney:()=>F,createLinearJourney:()=>H,defineWork:()=>ae,isJourneyError:()=>Q,withGraphTypes:()=>oe,withLinearTypes:()=>re});module.exports=fe(be);var m=class extends Error{constructor(e,t,r={},s){super(`journey: ${t}`,s===void 0?void 0:{cause:s}),this.name="JourneyError",this.code=e,this.stepId=r.stepId,this.event=r.event,this.pluginName=r.pluginName}},Q=n=>n instanceof m;var A=(n,e)=>`${n.length}:${n}${e}`,Y=n=>n.label??`${n.event}[${n.index}] (${n.from} -> ${n.to})`,K=n=>n===null?null:{event:n.event,from:n.from,to:n.to,label:n.label??null,index:n.index},x=Object.freeze({isLoading:!1,isSuccess:!0,isError:!1,error:null}),R=Object.freeze({isLoading:!0,isSuccess:!1,isError:!1,error:null}),S=(n,e)=>Object.hasOwn(n,e);function D(n){console.error("[journey] subscriber threw:",n)}function C(n){return{getSnapshot:()=>n.store.getSnapshot(),controls:{start:()=>n.start(),pause:()=>n.pause(),resume:()=>n.resume(),complete:e=>n.complete(e),terminate:e=>n.terminate(e),restart:()=>n.restart()},dispose:()=>n.dispose(),navigate:{goToStepById:e=>n.goToStepById(e),goToPreviousStep:e=>n.goToPreviousStep(e),goToNextStep:e=>n.goToNextStep(e),goToLastVisitedStep:()=>n.goToLastVisitedStep()},subscriptions:{subscribe:e=>n.store.subscribe(e),subscribeEvent:(e,t)=>n.store.subscribeEvent(e,t)},context:{update:e=>n.updateContext(e)},async:{clearError:()=>n.clearAsyncError()},plugins:n.pluginApis}}var G=()=>{let n=globalThis;if(typeof n.__DEV__=="boolean")return n.__DEV__;let e=n.process?.env?.NODE_ENV;return e===void 0||e==="development"},q=(n,e)=>{if(!(!G()||typeof console>"u")){if(e===void 0){console.warn(n);return}console.warn("%s",n,e)}};var w=(n,e)=>{if(Object.is(n,e))return!0;if(typeof n!="object"||n===null||typeof e!="object"||e===null||Array.isArray(n)!==Array.isArray(e))return!1;let t=n,r=e,s=Object.keys(t);return s.length!==Object.keys(r).length?!1:s.every(a=>Object.hasOwn(r,a)&&Object.is(t[a],r[a]))};var N=class{constructor(e,t){this.listeners=new Set;this.eventListeners=new Map;this.disposed=!1;this.snapshot=e,this.onListenerError=t}report(e){if(!this.onListenerError){D(e);return}try{this.onListenerError(e)}catch(t){D(t)}}getSnapshot(){return this.snapshot}publish(e){if(!Object.is(this.snapshot,e)){this.snapshot=e;for(let t of[...this.listeners])try{t()}catch(r){this.report(r)}}}subscribe(e){return this.disposed?()=>{}:(this.listeners.add(e),()=>{this.listeners.delete(e)})}subscribeEvent(e,t){if(this.disposed)return()=>{};let r=this.eventListeners.get(e);return r||(r=new Set,this.eventListeners.set(e,r)),r.add(t),()=>{r.delete(t)}}emit(e,t){let r=this.eventListeners.get(e);if(r)for(let s of[...r])try{s(t)}catch(a){this.report(a)}}dispose(){this.disposed=!0,this.listeners.clear(),this.eventListeners.clear()}};var B=n=>typeof n=="object"&&n!==null&&G()?Object.freeze(n):n,ge=Object.freeze({}),Z=Object.freeze({}),E=(n,e)=>e!=null&&w(n,e)?e:Object.freeze(n),P=(n,e,t=Object.is)=>e!==void 0&&e.length===n.length&&n.every((r,s)=>t(r,e[s]))?e:Object.freeze([...n]),ye=(n,e)=>n===void 0?"none":e?"passed":"failed",I=class{constructor(e){this.pluginApis={};this.status="idle";this.timeline=[];this.currentIndex=-1;this.outcome=null;this.visitCounts=new Map;this.entryAsync=x;this.pending=null;this.disposed=!1;this.restoreSeed=null;this.generation=0;this.raiseQueue=[];this.processingRaised=!1;this.lastPluginExtensions={};this.lastSnapshot=null;this.transitionListeners=new Set;this.disposeCallbacks=[];this.snapshotDerivers=new Map;this.config=e,this.frozenStepOrder=Object.freeze([...e.stepIds]),this.restoreSeed=e.restore??null,this.context=B(e.restore?e.restore.context:e.initialContext),this.store=new N(this.buildSnapshot(),e.onListenerError),this.setupPlugins(),this.store.publish(this.buildSnapshot()),e.autoStart&&this.start()}start(){return this.disposed||this.status!=="idle"?!1:(this.setStatus("running"),this.enterInitialStep(),!0)}pause(){return this.disposed||this.status!=="running"||this.pending?!1:(this.setStatus("paused"),!0)}resume(){return this.disposed||this.status!=="paused"?!1:(this.setStatus("running"),!0)}complete(e){return this.disposed||this.status!=="running"||this.pending?!1:(this.outcome=Object.freeze({type:"completed",payload:e}),this.setStatus("completed"),!0)}terminate(e){return this.disposed||this.status==="terminated"?!1:(this.generation+=1,this.pending=null,this.entryAsync=x,this.raiseQueue=[],this.outcome=Object.freeze({type:"terminated",payload:e}),this.setStatus("terminated"),!0)}restart(){return this.disposed||this.status!=="completed"&&this.status!=="terminated"?!1:(this.generation+=1,this.pending=null,this.raiseQueue=[],this.timeline=[],this.currentIndex=-1,this.context=B(this.config.initialContext),this.outcome=null,this.visitCounts=new Map,this.entryAsync=x,this.setStatus("running"),this.enterInitialStep(),!0)}dispose(){if(!this.disposed){this.disposed=!0,this.generation+=1,this.pending=null,this.raiseQueue=[];for(let e of this.disposeCallbacks.splice(0))try{e()}catch{}this.transitionListeners.clear(),this.store.dispose()}}updateContext(e){if(this.disposed)return;let t=this.context;this.context=B(e(t));let r=this.publish();this.store.emit("contextChange",{snapshot:r,previous:t,current:this.context})}clearAsyncError(){this.disposed||!this.entryAsync.isError||(this.entryAsync=x,this.publish())}goToStepById(e){let t=this.checkNavigable();if(t)return this.blocked(t,e);if(!S(this.config.steps,e))return this.blocked({ok:!1,reason:"invalid-target"},e);if(e===this.currentStepId())return this.blocked({ok:!1,reason:"no-op"},e);if(this.config.kind==="graph"){let r=this.config.transitions.find(s=>s.from===this.currentStepId()&&s.to===e&&this.isEnabled(s));return r?this.runNavigation(e,{kind:"append"},this.eventFor(r),r):this.blocked({ok:!1,reason:"invalid-target"},e)}return this.runNavigation(e,{kind:"append"},null,null)}goToPreviousStep(e=1){let t=this.checkNavigable();if(t)return this.blocked(t,null);if(this.currentIndex<=0)return this.blocked({ok:!1,reason:"out-of-bounds"},null);let r=Math.max(0,this.currentIndex-Math.max(1,Math.floor(e))),s=this.timeline[r];return this.runNavigation(s,{kind:"pointer",index:r},null,null,void 0,"backward")}goToNextStep(e){let t=this.checkNavigable();if(t)return this.blocked(t,null);if(this.currentIndex<this.timeline.length-1){let r=this.currentIndex+1,s=this.timeline[r];return this.runNavigation(s,{kind:"pointer",index:r},null,null,e,"forward")}if(this.config.kind==="linear"){let r=this.config.stepIds.indexOf(this.currentStepId()??""),s=this.config.stepIds[r+1];return s===void 0?this.blocked({ok:!1,reason:"out-of-bounds"},null):this.runNavigation(s,{kind:"append"},null,null,e,"forward")}return this.blocked({ok:!1,reason:"out-of-bounds"},null)}goToLastVisitedStep(){let e=this.checkNavigable();if(e)return this.blocked(e,null);let t=this.timeline.length-1;if(this.currentIndex>=t)return this.blocked({ok:!1,reason:"no-op"},null);let r=this.timeline[t];return this.runNavigation(r,{kind:"pointer",index:t},null,null)}goToStepByIndex(e){let t=Number.isInteger(e)?this.config.stepIds[e]:void 0;return t===void 0?this.blocked({ok:!1,reason:"invalid-target"},null):this.goToStepById(t)}send(e,t,r){let s=this.checkNavigable();if(s)return this.blocked(s,null);let a=t===void 0?{type:e}:{type:e,payload:t},u=this.currentStepId(),o=r??(u===null?void 0:this.config.eventWork?.[A(u,e)]);if(o)return this.sendWithWork(e,a,o);let i=this.resolveTransition(e);return i?this.runNavigation(i.to,{kind:"append"},a,i):this.blocked({ok:!1,reason:"no-enabled-transition"},null)}async sendWithWork(e,t,r){let s=this.generation,a=this.currentStepId();if(a===null)return this.blocked({ok:!1,reason:"not-running"},null);let u=this.context,o=!1,i;this.pending={phase:"working",from:a,to:null},this.entryAsync=R,this.publish();try{let c={snapshot:this.store.getSnapshot(),from:a,event:t,handlers:this.config.handlers};if(i=await this.withTimeout(Promise.resolve(r.run(c)),`send work(${r.label??`${e} from ${a}`})`,r.timeoutMs),!this.isCurrent(s))return this.staleResult();let d=r.commit?.({...c,result:i,updateContext:h=>{u=h(u),o=!0}});if(typeof d=="object"&&d!==null&&"then"in d)throw new m("async-commit","send work commit must be synchronous")}catch(c){if(!this.isCurrent(s))return this.staleResult();this.pending=null,this.entryAsync=Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:c});let d=this.publish();return this.store.emit("error",{snapshot:d,error:c,phase:"work",stepId:a}),this.blocked({ok:!1,reason:"error",error:c},null)}if(!this.isCurrent(s))return this.staleResult();let l=this.resolveTransition(e,u,i);return l?this.commitAndSettle(a,l.to,{kind:"append"},t,l,s,u,o,"jump"):(this.pending=null,this.entryAsync=x,this.publish(),this.blocked({ok:!1,reason:"no-enabled-transition"},null))}setupPlugins(){let e={getSnapshot:()=>this.store.getSnapshot(),structure:Object.freeze({kind:this.config.kind,stepIds:Object.freeze([...this.config.stepIds]),initial:this.config.initial,transitions:Object.freeze(this.config.transitions.map(t=>Object.freeze({event:t.event,from:t.from,to:t.to,guarded:t.when!==void 0,label:t.label??null,index:t.index})))}),onTransition:t=>(this.transitionListeners.add(t),()=>this.transitionListeners.delete(t)),onNavigationBlocked:t=>this.store.subscribeEvent("navigationBlocked",t),onStatusChange:t=>this.store.subscribeEvent("statusChange",t),onContextChange:t=>this.store.subscribeEvent("contextChange",t),onError:t=>this.store.subscribeEvent("error",t),onDispose:t=>{this.disposeCallbacks.push(t)},reportError:t=>this.store.report(t)};try{for(let t of this.config.plugins){if(S(this.pluginApis,t.name))throw new m("duplicate-plugin-name",`duplicate plugin name "${t.name}"`,{pluginName:t.name});let r=t.setup(e);this.pluginApis[t.name]=r.api,r.deriveSnapshot&&this.snapshotDerivers.set(t.name,r.deriveSnapshot)}}catch(t){throw this.dispose(),t}}currentStepId(){return this.currentIndex>=0?this.timeline[this.currentIndex]:null}eventFor(e){return{type:e.event}}isEnabled(e,t=this.context,r){if(!e.when)return!0;try{return e.when({context:t,handlers:this.config.handlers,result:r})}catch{return!1}}resolveTransition(e,t=this.context,r){return this.config.transitions.find(s=>s.event===e&&s.from===this.currentStepId()&&this.isEnabled(s,t,r))}checkNavigable(){return this.disposed?{ok:!1,reason:"disposed"}:this.status!=="running"?{ok:!1,reason:"not-running"}:this.pending?{ok:!1,reason:"transitioning"}:null}setStatus(e){let t=this.status;this.status=e;let r=this.publish();this.store.emit("statusChange",{snapshot:r,previous:t,current:e}),this.refreshPluginSnapshot()}refreshPluginSnapshot(){this.snapshotDerivers.size>0&&this.publish()}blocked(e,t){if(e.reason!=="disposed"){let r={snapshot:this.store.getSnapshot(),reason:e.reason,from:this.currentStepId(),to:t};"error"in e&&(r.error=e.error),this.store.emit("navigationBlocked",r)}return Promise.resolve({...e,from:this.currentStepId(),to:t})}hookArgs(e,t,r,s){return{snapshot:this.store.getSnapshot(),from:e,to:t,event:r,transition:s,updateContext:a=>this.updateContext(a),raise:a=>{this.config.kind!=="graph"||this.disposed||this.raiseQueue.push(a)}}}async invokeEffect(e,t,r,s){if(!e)return null;try{return await this.withTimeout(Promise.resolve(e(t)),r,s),null}catch(a){return{error:a}}}withTimeout(e,t,r){let s=r??this.config.defaultTimeoutMs;return s===void 0?e:new Promise((a,u)=>{let o=setTimeout(()=>u(new Error(`journey: ${t} timed out after ${s}ms`)),s);e.then(i=>{clearTimeout(o),a(i)},i=>{clearTimeout(o),u(i)})})}async enterInitialStep(){let e=this.generation,t=this.restoreSeed;if(this.restoreSeed=null,t){let s=t.timeline[t.currentIndex];this.pending={phase:"entering",from:null,to:s},this.timeline=[...t.timeline],this.currentIndex=t.currentIndex;for(let a of t.timeline)this.visitCounts.set(a,(this.visitCounts.get(a)??0)+1);this.commitEntry(null,s,"jump"),await this.runEntryEffects(null,s,null,null,e);return}let r=this.config.startAt??this.config.initial;this.pending={phase:"entering",from:null,to:r},this.timeline=[r],this.currentIndex=0,this.commitEntry(null,r,"jump"),await this.runEntryEffects(null,r,null,null,e)}async runNavigation(e,t,r,s,a,u){let o=this.generation,i=this.currentStepId(),l=this.context,c=!1;if(a&&i!==null&&u){this.pending={phase:"working",from:i,to:e},this.entryAsync=R,this.publish();try{let d={snapshot:this.store.getSnapshot(),from:i,to:e,direction:u},h=await this.withTimeout(Promise.resolve(a.run(d)),`${u} navigation work(${i} -> ${e})`,a.timeoutMs);if(!this.isCurrent(o))return this.staleResult();let g=a.commit?.({...d,result:h,updateContext:y=>{l=y(l),c=!0}});if(typeof g=="object"&&g!==null&&"then"in g)throw new m("async-commit","navigation work commit must be synchronous")}catch(d){if(!this.isCurrent(o))return this.staleResult();this.pending=null,this.entryAsync=Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:d});let h=this.publish();return this.store.emit("error",{snapshot:h,error:d,phase:"work",stepId:i}),this.blocked({ok:!1,reason:"error",error:d},e)}}return this.isCurrent(o)?this.commitAndSettle(i,e,t,r,s,o,l,c,u??"jump"):this.staleResult()}async commitAndSettle(e,t,r,s,a,u,o,i,l){let c=this.context;r.kind==="pointer"?this.currentIndex=r.index:(this.timeline=[...this.timeline.slice(0,this.currentIndex+1),t],this.currentIndex=this.timeline.length-1),i&&(this.context=B(o));let d=e===null?void 0:this.config.steps[e];return this.pending={phase:d?.onLeave?"leaving":"entering",from:e,to:t},this.commitEntry(e,t,l,i?{previous:c,current:o}:void 0,d?.onLeave!==void 0||a?.onTransition!==void 0),await this.runEntryEffects(e,t,s,a,u),{ok:!0,from:e,to:t}}commitEntry(e,t,r,s,a=!1){this.visitCounts.set(t,(this.visitCounts.get(t)??0)+1);let u=this.config.steps[t];this.entryAsync=a||u?.onEnter?R:x;let o=this.publish();s&&this.store.emit("contextChange",{snapshot:o,...s}),e!==null&&this.store.emit("stepLeave",{snapshot:o,from:e,to:t}),this.store.emit("stepEnter",{snapshot:o,from:e,to:t,direction:r})}async runEntryEffects(e,t,r,s,a){let u=e===null?void 0:this.config.steps[e],o=this.config.steps[t],i=K(s),l=[],c=await this.invokeEffect(u?.onLeave,this.hookArgs(e,t,r,i),`onLeave(${e??""})`);if(!this.isCurrent(a))return;c&&e!==null&&l.push({error:c.error,phase:"leave",stepId:e}),this.pending={phase:"entering",from:e,to:t},this.publish();let d=await this.invokeEffect(s?.onTransition,this.hookArgs(e,t,r,i),`onTransition(${s?Y(s):r?.type??""})`,s?.timeoutMs);if(!this.isCurrent(a))return;d&&l.push({error:d.error,phase:"transition",stepId:t});let h=await this.invokeEffect(o?.onEnter,this.hookArgs(e,t,r,i),`onEnter(${t})`);if(!this.isCurrent(a))return;h&&l.push({error:h.error,phase:"enter",stepId:t}),this.entryAsync=l[0]?Object.freeze({isLoading:!1,isSuccess:!1,isError:!0,error:l[0].error}):x,this.pending=null;let g=this.publish();for(let y of l)this.store.emit("error",{snapshot:g,error:y.error,phase:y.phase,stepId:y.stepId});for(let y of[...this.transitionListeners])try{y({from:e,to:t,snapshot:g})}catch{}this.refreshPluginSnapshot(),this.processRaisedEvents(a)}async processRaisedEvents(e){if(this.processingRaised||!this.isCurrent(e))return;this.processingRaised=!0;let t=0;try{for(;this.raiseQueue.length>0&&this.isCurrent(e);){if(this.status!=="running"){this.raiseQueue=[];return}if(t+=1,t>25){this.raiseQueue=[],this.store.emit("error",{snapshot:this.store.getSnapshot(),error:new Error(`journey: raised-event cascade exceeded ${25} events; queue dropped`),phase:"raise",stepId:this.currentStepId()});return}let r=this.raiseQueue.shift();await this.send(r.type,r.payload)}}finally{this.processingRaised=!1}}isCurrent(e){return!this.disposed&&e===this.generation}staleResult(){let e=this.currentStepId();return this.disposed?{ok:!1,reason:"disposed",from:e,to:null}:{ok:!1,reason:"not-running",from:e,to:null}}publish(){let e=this.buildSnapshot();return this.store.publish(e),e}buildSnapshot(){let e=this.lastSnapshot,t=this.currentStepId(),r={},s=0;for(let h of this.config.stepIds){let g=(this.visitCounts.get(h)??0)>0;r[h]=g,g&&(s+=1)}let a=e?.history,u=a!=null&&w(a.visited,r)?a.visited:Object.freeze(r),o={status:this.status,context:this.context,transition:E({pending:this.pending!==null,phase:this.pending?.phase??null,from:this.pending?.from??null,to:this.pending?.to??null},e?.transition),history:E({timeline:P(this.timeline,a?.timeline),currentIndex:this.currentIndex,visited:u,canGoBack:this.currentIndex>0,canGoForward:this.currentIndex>=0&&this.currentIndex<this.timeline.length-1},a),machine:E({outcome:this.outcome},e?.machine)},i=t===null?null:{id:t,metadata:this.config.steps[t]?.metadata??ge,isFirstTimeVisit:(this.visitCounts.get(t)??0)===1,async:this.entryAsync},l;if(this.config.kind==="linear"){let h=e?.type==="linear"?e:null,g=t===null?-1:this.config.stepIds.indexOf(t);l={...o,type:"linear",currentStep:i===null?null:E({...i,index:g,isFirstStep:g===0,isLastStep:g===this.config.stepIds.length-1},h?.currentStep),steps:E({totalSteps:this.config.stepIds.length,stepOrder:this.frozenStepOrder,visitedStepCount:s},h?.steps),plugins:Z}}else{let h=[],g=[],y=[],f=[],p=new Map,v=new Set,b=!1;if(t!==null)for(let T of this.config.transitions){if(T.from!==t)continue;b=!0,h.includes(T.event)||h.push(T.event);let O=p.get(T.event)??0;p.set(T.event,O+1);let J=this.isEnabled(T),V=J&&!v.has(T.event);V&&v.add(T.event),f.push(Object.freeze({event:T.event,to:T.to,priority:O,guard:ye(T.when,J),enabled:J,selected:V})),J&&(g.includes(T.event)||g.push(T.event),y.includes(T.to)||y.push(T.to))}let k=e?.type==="graph"?e:null;l={...o,type:"graph",currentStep:i===null?null:E({...i,isTerminal:!b},k?.currentStep),steps:E({totalSteps:this.config.stepIds.length,visitedStepCount:s},k?.steps),declaredEvents:P(h,k?.declaredEvents),availableEvents:P(g,k?.availableEvents),availableSteps:P(y,k?.availableSteps),outgoingTransitions:P(f,k?.outgoingTransitions,(T,O)=>w(T,O)),plugins:Z}}if(this.snapshotDerivers.size>0){let h={};for(let[y,f]of this.snapshotDerivers)try{h[y]=f(l,this.lastPluginExtensions[y])}catch(p){this.store.report(p),S(this.lastPluginExtensions,y)&&(h[y]=this.lastPluginExtensions[y])}this.lastPluginExtensions=h;let g=e?.plugins;l={...l,plugins:g!=null&&w(g,h)?g:Object.freeze(h)}}let c=Object.freeze(l),d=e!==null&&w(c,e)?e:c;return this.lastSnapshot=d,d}};var ee=["context","transition","status"];function te(n){return typeof n!="number"||!Number.isFinite(n)?0:Math.max(0,Math.trunc(n))}function ne(n,e){return{status:n.status,context:n.context,timeline:n.history.timeline,currentIndex:n.history.currentIndex,savedAt:e}}var me=new Set(["idle","running","paused","completed","terminated"]),Te=["__proto__","constructor","prototype"];function $(n,e=0){if(e>50||n===null||typeof n!="object")return n;if(Array.isArray(n))return n.map(r=>$(r,e+1));let t={};for(let[r,s]of Object.entries(n))Te.includes(r)||(t[r]=$(s,e+1));return t}function W(n){if(n===null)return null;let e;try{e=JSON.parse(n)}catch{return null}if(typeof e!="object"||e===null)return null;let t=e;return typeof t.status!="string"||!me.has(t.status)||!Array.isArray(t.timeline)||!t.timeline.every(r=>typeof r=="string")||typeof t.currentIndex!="number"||!Number.isInteger(t.currentIndex)||typeof t.savedAt!="number"||!Number.isFinite(t.savedAt)?null:{status:t.status,context:$(t.context),timeline:t.timeline,currentIndex:t.currentIndex,savedAt:t.savedAt}}function z(n){if(n.storage)return n.storage;let e;try{e=globalThis.localStorage}catch(t){throw new m("storage-unavailable","localStorage access was blocked by the environment; pass persist.storage explicitly",{},t)}if(!e)throw new m("storage-unavailable","persist.storage is required when localStorage is unavailable");return e}function L(n,e){let t;try{t=z(n).getItem(n.key)}catch{return null}let r=W(t);if(!r||r.status!=="running"&&r.status!=="paused"||!Number.isInteger(r.currentIndex)||r.currentIndex<0||r.currentIndex>=r.timeline.length)return null;for(let s of r.timeline)if(typeof s!="string"||!e(s))return null;return r}var _={status:"idle",lastSavedAt:null,error:null};function ve(n){let e=n.now??Date.now,t=te(n.debounceMs),r=new Set(n.saveOn??ee),s=0;return{name:"persistence",setup(a){s+=1,s>1&&q(`journey: persistence plugin instance shared by ${s} machines; they overwrite key "${n.key}". Create one per machine.`);let u=null,o=_,i=null,l=!1,c=p=>{u=p,o={status:"saved",lastSavedAt:p.savedAt,error:null}},d=p=>{o={...o,status:"error",error:p},a.reportError(p)},h=()=>{let p=ne(a.getSnapshot(),e());o={...o,status:"saving"};let v;try{v=n.storage.setItem(n.key,JSON.stringify(p))}catch(b){throw o={...o,status:"error",error:b},b}if(v!==void 0)return v.then(()=>c(p),d);c(p)},g=()=>{i!==null&&(clearTimeout(i),i=null)},y=()=>{i=null;try{let p=h()}catch(p){d(p)}},f=p=>{if(!(l||!r.has(p))){if(t===0){h();return}g(),o={...o,status:"pending"},i=setTimeout(y,t)}};return a.onContextChange(()=>f("context")),a.onTransition(()=>f("transition")),a.onStatusChange(({current:p})=>{if(p==="terminated"&&n.clearOnTerminate){g(),u=null,o=_,n.storage.removeItem(n.key);return}f("status")}),a.onDispose(()=>{l=!0,g()}),{api:{inspectPersistedState:()=>u,getPersistenceState:()=>o,readPersisted:()=>W(n.storage.getItem(n.key)),clearPersisted:()=>{g(),u=null,o=_;try{n.storage.removeItem(n.key)}catch(p){d(p)}},flushPersisted:async()=>{g();try{await h()}catch(p){d(p)}}},deriveSnapshot:(p,v)=>v===o?v:o}}}}function M(n){return ve({key:n.key,storage:z(n)})}function H(n,e={}){if(n.steps.length===0)throw new m("empty-definition","a linear journey needs at least one step");let t=[],r={};for(let o of n.steps){let i=typeof o=="string"?{id:o}:o;if(S(r,i.id))throw new m("duplicate-step-id",`duplicate step id "${i.id}"`,{stepId:i.id});t.push(i.id);let l={metadata:i.metadata??{}};i.onEnter&&(l.onEnter=i.onEnter),i.onLeave&&(l.onLeave=i.onLeave),r[i.id]=l}if(e.startAt!==void 0&&!S(r,e.startAt))throw new m("unknown-step",`startAt references unknown step "${e.startAt}"`,{stepId:e.startAt});let s=e.persist&&e.startAt===void 0?L(e.persist,o=>S(r,o)):null,a=new I({kind:"linear",stepIds:t,steps:r,initial:t[0],...e.startAt!==void 0?{startAt:e.startAt}:{},initialContext:n.context,...s?{restore:{context:s.context,timeline:s.timeline,currentIndex:s.currentIndex}}:{},transitions:[],handlers:void 0,autoStart:e.autoStart??!0,defaultTimeoutMs:e.defaultTimeoutMs,...e.onListenerError!==void 0?{onListenerError:e.onListenerError}:{},plugins:[...e.persist?[M(e.persist)]:[],...e.plugins??[]]}),u=C(a);return{...u,navigate:{...u.navigate,goToStepByIndex:o=>a.goToStepByIndex(o)}}}var re=()=>(n,e={})=>H(n,e);var se=(n,e,t)=>{if(typeof n!="string"||n.length===0)throw new m("invalid-label",`${e} must declare "label" as a non-empty string`,t);return n},ie=(n,e,t)=>{if(typeof n!="number"||!Number.isFinite(n)||n<=0)throw new m("invalid-timeout",`${e} must declare "timeoutMs" as a finite number greater than 0`,t);return n};function U(n){let e=Object.keys(n.steps);if(e.length===0)throw new m("empty-definition","a graph journey needs at least one step");if(!e.includes(n.initial))throw new m("unknown-initial-step",`initial step "${n.initial}" is not a declared step`,{stepId:n.initial});let t={};for(let u of e){let o=n.steps[u],i={metadata:o.metadata??{}};o.onEnter&&(i.onEnter=o.onEnter),o.onLeave&&(i.onLeave=o.onLeave),t[u]=i}let r=[],s={},a=(u,o,i,l)=>{if(!e.includes(i.to))throw new m("dangling-transition",`transition "${u}" references unknown step "${i.to}"`,{event:u,stepId:i.to});let c=`transition "${u}"[${l}] on step "${o}"`,d={event:u,from:o,to:i.to,index:l};i.when&&(d.when=i.when),i.onTransition&&(d.onTransition=i.onTransition),i.label!==void 0&&(d.label=se(i.label,c,{event:u,stepId:o})),i.timeoutMs!==void 0&&(d.timeoutMs=ie(i.timeoutMs,c,{event:u,stepId:o})),r.push(d)};for(let u of e){let o=n.steps[u]?.on;if(o)for(let[i,l]of Object.entries(o)){if(l===void 0)continue;if(typeof l=="string"){a(i,u,{to:l},0);continue}if(Array.isArray(l)){l.forEach((g,y)=>a(i,u,g,y));continue}let c=l,d=`work on "${i}" on step "${u}"`,h={run:c.run};c.commit&&(h.commit=c.commit),c.label!==void 0&&(h.label=se(c.label,d,{event:i,stepId:u})),c.timeoutMs!==void 0&&(h.timeoutMs=ie(c.timeoutMs,d,{event:i,stepId:u})),s[A(u,i)]=h,c.candidates.forEach((g,y)=>a(i,u,g,y))}}return{stepIds:e,steps:t,transitions:r,eventWork:s}}function F(n,e={}){let{stepIds:t,steps:r,transitions:s,eventWork:a}=U(n);if(e.startAt!==void 0&&!S(r,e.startAt))throw new m("unknown-step",`startAt references unknown step "${e.startAt}"`,{stepId:e.startAt});let u=e.persist&&e.startAt===void 0?L(e.persist,l=>S(r,l)):null,o=new I({kind:"graph",stepIds:t,steps:r,initial:n.initial,...e.startAt!==void 0?{startAt:e.startAt}:{},initialContext:n.context,...u?{restore:{context:u.context,timeline:u.timeline,currentIndex:u.currentIndex}}:{},transitions:s,...Object.keys(a).length>0?{eventWork:a}:{},handlers:e.handlers??n.handlers,autoStart:e.autoStart??!0,defaultTimeoutMs:e.defaultTimeoutMs,...e.onListenerError!==void 0?{onListenerError:e.onListenerError}:{},plugins:[...e.persist?[M(e.persist)]:[],...e.plugins??[]]});return{...C(o),send:(l,c)=>o.send(l,c)}}var oe=()=>(n,e={})=>F(n,e);var ae=()=>n=>n;function Se(n){let e=[],t=[...n.stepIds],r=new Set,s=new Set;n.transitions.forEach((f,p)=>{let v=`${f.from} ${f.event}`;if(s.has(v)){r.add(p),e.push({code:"shadowed-transition",severity:"warning",from:f.from,event:f.event,message:`Transition "${f.from}.${f.event}" is shadowed by an earlier unconditional candidate.`});return}f.guarded||s.add(v)});let a=n.transitions.filter((f,p)=>!r.has(p)),u=f=>a.filter(p=>p.from===f),o=new Set,i=[n.initial];for(;i.length>0;){let f=i.pop();if(!o.has(f)){o.add(f);for(let p of u(f))i.push(p.to)}}for(let f of t)o.has(f)||e.push({code:"unreachable-step",severity:"warning",stepId:f,message:`Step "${f}" is unreachable from the initial step "${n.initial}".`});let l=t.filter(f=>u(f).length===0),c=new Set,d=new Set,h=[],g=f=>{d.add(f),h.push(f);for(let p of u(f)){let v=h.indexOf(p.to);if(v>=0){let b=[...h.slice(v),p.to],k=b.join(" ");c.has(k)||(c.add(k),e.push({code:"cycle-detected",severity:"warning",from:p.from,event:p.event,steps:b,message:`Cycle detected: ${b.join(" -> ")}.`}));continue}d.has(p.to)||g(p.to)}h.pop()};g(n.initial);let y=l.some(f=>o.has(f));return y||e.push({code:"no-terminal-path",severity:"warning",stepId:n.initial,message:`No terminal step is reachable from the initial step "${n.initial}".`}),{issues:e,summary:{stepCount:t.length,reachableStepCount:o.size,unreachableStepCount:t.length-o.size,terminalStepIds:l,cycleCount:c.size,shadowedTransitionCount:r.size,terminalPathExists:y}}}function ue(n){let{stepIds:e,transitions:t}=U(n),r={kind:"graph",stepIds:e,initial:n.initial,transitions:t.map(s=>({event:s.event,from:s.from,to:s.to,guarded:s.when!==void 0,label:s.label??null,index:s.index}))};return Se(r)}0&&(module.exports={JourneyError,analyzeStructure,createGraphJourney,createLinearJourney,defineWork,isJourneyError,withGraphTypes,withLinearTypes});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|