@rxova/journey-core 1.0.0-rc.3 → 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.
Files changed (158) hide show
  1. package/README.md +185 -189
  2. package/dist/connectors/immer/immer.cjs +2 -0
  3. package/dist/connectors/immer/immer.cjs.map +7 -0
  4. package/dist/connectors/immer/immer.d.cts +11 -0
  5. package/dist/connectors/immer/immer.d.ts +11 -0
  6. package/dist/connectors/immer/immer.js +2 -0
  7. package/dist/connectors/immer/immer.js.map +7 -0
  8. package/dist/connectors/immer/immer.types.d.cts +9 -0
  9. package/dist/connectors/immer/immer.types.d.ts +9 -0
  10. package/dist/core/errors.d.cts +57 -0
  11. package/dist/core/errors.d.ts +57 -0
  12. package/dist/core/helpers.d.cts +40 -0
  13. package/dist/core/helpers.d.ts +40 -0
  14. package/dist/core/machine.d.cts +9 -0
  15. package/dist/core/machine.d.ts +9 -0
  16. package/dist/core/runtime.d.cts +115 -0
  17. package/dist/core/runtime.d.ts +115 -0
  18. package/dist/core/runtime.types.d.cts +112 -0
  19. package/dist/core/runtime.types.d.ts +112 -0
  20. package/dist/core/store.d.cts +31 -0
  21. package/dist/core/store.d.ts +31 -0
  22. package/dist/core/types.d.cts +481 -0
  23. package/dist/core/types.d.ts +481 -0
  24. package/dist/diagnostics/diagnostics.helpers.d.cts +17 -0
  25. package/dist/diagnostics/diagnostics.helpers.d.ts +17 -0
  26. package/dist/diagnostics/diagnostics.types.d.cts +22 -0
  27. package/dist/diagnostics/diagnostics.types.d.ts +22 -0
  28. package/dist/graph/bag.types.d.cts +91 -0
  29. package/dist/graph/bag.types.d.ts +91 -0
  30. package/dist/graph/graph.d.cts +63 -0
  31. package/dist/graph/graph.d.ts +63 -0
  32. package/dist/graph/graph.types.d.cts +212 -0
  33. package/dist/graph/graph.types.d.ts +212 -0
  34. package/dist/graph/work.d.cts +81 -0
  35. package/dist/graph/work.d.ts +81 -0
  36. package/dist/index.cjs +1 -1
  37. package/dist/index.cjs.map +4 -4
  38. package/dist/index.d.cts +13 -5
  39. package/dist/index.d.ts +13 -5
  40. package/dist/index.js +1 -1
  41. package/dist/index.js.map +4 -4
  42. package/dist/linear/linear.d.cts +33 -0
  43. package/dist/linear/linear.d.ts +33 -0
  44. package/dist/linear/linear.types.d.cts +28 -0
  45. package/dist/linear/linear.types.d.ts +28 -0
  46. package/dist/plugins/analytics/analytics.d.cts +8 -0
  47. package/dist/plugins/analytics/analytics.d.ts +8 -0
  48. package/dist/plugins/analytics/analytics.helpers.d.cts +2 -0
  49. package/dist/plugins/analytics/analytics.helpers.d.ts +2 -0
  50. package/dist/plugins/analytics/analytics.types.d.cts +27 -0
  51. package/dist/plugins/analytics/analytics.types.d.ts +27 -0
  52. package/dist/plugins/execution-paths/execution-paths.d.cts +7 -4
  53. package/dist/plugins/execution-paths/execution-paths.d.ts +7 -4
  54. package/dist/plugins/execution-paths/execution-paths.types.d.cts +21 -0
  55. package/dist/plugins/execution-paths/execution-paths.types.d.ts +21 -0
  56. package/dist/plugins/index.cjs +2 -0
  57. package/dist/plugins/index.cjs.map +7 -0
  58. package/dist/plugins/index.d.cts +19 -0
  59. package/dist/plugins/index.d.ts +19 -0
  60. package/dist/plugins/index.js +2 -0
  61. package/dist/plugins/index.js.map +7 -0
  62. package/dist/plugins/persistence/persistence.d.cts +16 -0
  63. package/dist/plugins/persistence/persistence.d.ts +16 -0
  64. package/dist/plugins/persistence/persistence.helpers.d.cts +34 -0
  65. package/dist/plugins/persistence/persistence.helpers.d.ts +34 -0
  66. package/dist/plugins/persistence/persistence.types.d.cts +63 -0
  67. package/dist/plugins/persistence/persistence.types.d.ts +63 -0
  68. package/dist/plugins/replay/replay.d.cts +7 -0
  69. package/dist/plugins/replay/replay.d.ts +7 -0
  70. package/dist/plugins/replay/replay.helpers.d.cts +22 -0
  71. package/dist/plugins/replay/replay.helpers.d.ts +22 -0
  72. package/dist/plugins/replay/replay.types.d.cts +28 -0
  73. package/dist/plugins/replay/replay.types.d.ts +28 -0
  74. package/package.json +61 -80
  75. package/dist/journey-builder/index.d.cts +0 -5
  76. package/dist/journey-builder/index.d.ts +0 -5
  77. package/dist/journey-builder/types.d.cts +0 -126
  78. package/dist/journey-builder/types.d.ts +0 -126
  79. package/dist/journey-machine/async-state.d.cts +0 -12
  80. package/dist/journey-machine/async-state.d.ts +0 -12
  81. package/dist/journey-machine/computed.d.cts +0 -2
  82. package/dist/journey-machine/computed.d.ts +0 -2
  83. package/dist/journey-machine/controls.d.cts +0 -17
  84. package/dist/journey-machine/controls.d.ts +0 -17
  85. package/dist/journey-machine/helpers.d.cts +0 -52
  86. package/dist/journey-machine/helpers.d.ts +0 -52
  87. package/dist/journey-machine/index.d.cts +0 -3
  88. package/dist/journey-machine/index.d.ts +0 -3
  89. package/dist/journey-machine/navigation.d.cts +0 -32
  90. package/dist/journey-machine/navigation.d.ts +0 -32
  91. package/dist/journey-machine/plugin-controller.d.cts +0 -15
  92. package/dist/journey-machine/plugin-controller.d.ts +0 -15
  93. package/dist/journey-machine/resolve-journey-definition.d.cts +0 -2
  94. package/dist/journey-machine/resolve-journey-definition.d.ts +0 -2
  95. package/dist/journey-machine/runtime.d.cts +0 -33
  96. package/dist/journey-machine/runtime.d.ts +0 -33
  97. package/dist/journey-machine/send.d.cts +0 -9
  98. package/dist/journey-machine/send.d.ts +0 -9
  99. package/dist/plugins/analytics/index.cjs +0 -2
  100. package/dist/plugins/analytics/index.cjs.map +0 -7
  101. package/dist/plugins/analytics/index.d.cts +0 -25
  102. package/dist/plugins/analytics/index.d.ts +0 -25
  103. package/dist/plugins/analytics/index.js +0 -2
  104. package/dist/plugins/analytics/index.js.map +0 -7
  105. package/dist/plugins/autosave/index.cjs +0 -2
  106. package/dist/plugins/autosave/index.cjs.map +0 -7
  107. package/dist/plugins/autosave/index.d.cts +0 -17
  108. package/dist/plugins/autosave/index.d.ts +0 -17
  109. package/dist/plugins/autosave/index.js +0 -2
  110. package/dist/plugins/autosave/index.js.map +0 -7
  111. package/dist/plugins/diagnostics/diagnostics.d.cts +0 -3
  112. package/dist/plugins/diagnostics/diagnostics.d.ts +0 -3
  113. package/dist/plugins/diagnostics/index.cjs +0 -2
  114. package/dist/plugins/diagnostics/index.cjs.map +0 -7
  115. package/dist/plugins/diagnostics/index.d.cts +0 -15
  116. package/dist/plugins/diagnostics/index.d.ts +0 -15
  117. package/dist/plugins/diagnostics/index.js +0 -2
  118. package/dist/plugins/diagnostics/index.js.map +0 -7
  119. package/dist/plugins/execution-paths/index.cjs +0 -2
  120. package/dist/plugins/execution-paths/index.cjs.map +0 -7
  121. package/dist/plugins/execution-paths/index.d.cts +0 -18
  122. package/dist/plugins/execution-paths/index.d.ts +0 -18
  123. package/dist/plugins/execution-paths/index.js +0 -2
  124. package/dist/plugins/execution-paths/index.js.map +0 -7
  125. package/dist/plugins/persistence/controller.d.cts +0 -17
  126. package/dist/plugins/persistence/controller.d.ts +0 -17
  127. package/dist/plugins/persistence/index.cjs +0 -2
  128. package/dist/plugins/persistence/index.cjs.map +0 -7
  129. package/dist/plugins/persistence/index.d.cts +0 -12
  130. package/dist/plugins/persistence/index.d.ts +0 -12
  131. package/dist/plugins/persistence/index.js +0 -2
  132. package/dist/plugins/persistence/index.js.map +0 -7
  133. package/dist/plugins/replay/index.cjs +0 -2
  134. package/dist/plugins/replay/index.cjs.map +0 -7
  135. package/dist/plugins/replay/index.d.cts +0 -27
  136. package/dist/plugins/replay/index.d.ts +0 -27
  137. package/dist/plugins/replay/index.js +0 -2
  138. package/dist/plugins/replay/index.js.map +0 -7
  139. package/dist/types/analytics.types.d.cts +0 -33
  140. package/dist/types/analytics.types.d.ts +0 -33
  141. package/dist/types/autosave.types.d.cts +0 -23
  142. package/dist/types/autosave.types.d.ts +0 -23
  143. package/dist/types/diagnostics.types.d.cts +0 -38
  144. package/dist/types/diagnostics.types.d.ts +0 -38
  145. package/dist/types/index.d.cts +0 -9
  146. package/dist/types/index.d.ts +0 -9
  147. package/dist/types/journey.types.d.cts +0 -191
  148. package/dist/types/journey.types.d.ts +0 -191
  149. package/dist/types/machine.types.d.cts +0 -104
  150. package/dist/types/machine.types.d.ts +0 -104
  151. package/dist/types/observation.types.d.cts +0 -83
  152. package/dist/types/observation.types.d.ts +0 -83
  153. package/dist/types/persistence.types.d.cts +0 -34
  154. package/dist/types/persistence.types.d.ts +0 -34
  155. package/dist/types/replay.types.d.cts +0 -35
  156. package/dist/types/replay.types.d.ts +0 -35
  157. package/dist/types/transitions.types.d.cts +0 -122
  158. package/dist/types/transitions.types.d.ts +0 -122
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Machine-readable reasons a journey can refuse to build or operate.
3
+ *
4
+ * Closed on purpose: consumers should be able to `switch` over it exhaustively.
5
+ * Adding a member is a minor change; removing or repurposing one is not done
6
+ * within a major.
7
+ */
8
+ export type JourneyErrorCode =
9
+ /** A definition declared no steps. */
10
+ "empty-definition"
11
+ /** The same step id was declared twice. */
12
+ | "duplicate-step-id"
13
+ /** A step id was referenced that the definition does not declare. */
14
+ | "unknown-step"
15
+ /** `initial` names a step the definition does not declare. */
16
+ | "unknown-initial-step"
17
+ /** A transition's `from` or `to` names a step that does not exist. */
18
+ | "dangling-transition"
19
+ /** Two plugins claimed the same `name`. */
20
+ | "duplicate-plugin-name"
21
+ /** Persistence was requested but no usable storage could be resolved. */
22
+ | "storage-unavailable"
23
+ /** Navigation work's `commit` returned a promise; it must be synchronous. */
24
+ | "async-commit"
25
+ /** A transition or work entry declared `label` as something other than a non-empty string. */
26
+ | "invalid-label"
27
+ /** A transition or work entry declared `timeoutMs` as something other than a positive finite number. */
28
+ | "invalid-timeout";
29
+ export type JourneyErrorDetails = {
30
+ /** The offending step id, where one caused the failure. */
31
+ readonly stepId?: string;
32
+ /** The offending event name, for transition failures. */
33
+ readonly event?: string;
34
+ /** The offending plugin name, for plugin failures. */
35
+ readonly pluginName?: string;
36
+ };
37
+ /**
38
+ * Every error core throws itself.
39
+ *
40
+ * Before this existed, distinguishing "duplicate plugin name" from "unknown step
41
+ * in transition" meant matching on the message text — which quietly made every
42
+ * message a compatibility promise. `code` is the stable contract; `message` is
43
+ * for humans and may be reworded in any release.
44
+ *
45
+ * Errors surfaced through `NavigationResult.error` and the `error` subscription
46
+ * event stay `unknown`: those carry whatever the caller's own work threw, which
47
+ * core cannot constrain.
48
+ */
49
+ export declare class JourneyError extends Error {
50
+ readonly code: JourneyErrorCode;
51
+ readonly stepId: string | undefined;
52
+ readonly event: string | undefined;
53
+ readonly pluginName: string | undefined;
54
+ constructor(code: JourneyErrorCode, message: string, details?: JourneyErrorDetails, cause?: unknown);
55
+ }
56
+ /** Narrowing helper, so consumers need not import the class to test for it. */
57
+ export declare const isJourneyError: (value: unknown) => value is JourneyError;
@@ -0,0 +1,40 @@
1
+ import type { RuntimeTransition } from "./runtime.types.js";
2
+ import type { StepAsyncState, TransitionInfo } from "./types.js";
3
+ /** Hard cap on events processed from one raise cascade before it is dropped. */
4
+ export declare const MAX_RAISED_EVENTS = 25;
5
+ /**
6
+ * Key for definition-declared send work. Work belongs to an (origin step,
7
+ * event) pair, not to an event alone — the same event name can be declared
8
+ * from several steps with different work on each. Length-prefixing the step id
9
+ * keeps the key injective without reserving a separator character.
10
+ */
11
+ export declare const eventWorkKey: (from: string, event: string) => string;
12
+ /**
13
+ * How one edge is named in errors and timeout messages.
14
+ *
15
+ * A declared label wins outright — that is the point of declaring one. Without
16
+ * it the fallback still has to distinguish candidates that share an event and
17
+ * a target and differ only by guard, so it carries the declaration index:
18
+ * `submit[1] (login -> twofa)`.
19
+ */
20
+ export declare const describeTransition: (transition: RuntimeTransition) => string;
21
+ /**
22
+ * The public, generics-free view of an edge handed to step hooks. Built once
23
+ * per navigation and shared by the three hooks it runs — and left unfrozen,
24
+ * like the hook args it rides on, since it does not outlive them.
25
+ */
26
+ export declare const transitionInfo: (transition: RuntimeTransition | null) => TransitionInfo | null;
27
+ export declare const SUCCESS_ASYNC: StepAsyncState;
28
+ export declare const LOADING_ASYNC: StepAsyncState;
29
+ /**
30
+ * Own-property membership, for every guard that asks "is this a declared id?".
31
+ *
32
+ * `in` walks the prototype chain, so `"toString" in steps` is true for any
33
+ * object literal. Using it to validate step ids let `toString`, `constructor`,
34
+ * `__proto__`, `hasOwnProperty` and friends pass as declared steps — including
35
+ * ids arriving from a persisted record or a route parameter, which are not
36
+ * developer-authored. Own-property checks are the only correct test here.
37
+ */
38
+ export declare const hasOwn: (target: object, key: string) => boolean;
39
+ /** Subscriber exceptions are isolated so one listener cannot break the pipeline. */
40
+ export declare function reportListenerError(error: unknown): void;
@@ -0,0 +1,40 @@
1
+ import type { RuntimeTransition } from "./runtime.types.js";
2
+ import type { StepAsyncState, TransitionInfo } from "./types.js";
3
+ /** Hard cap on events processed from one raise cascade before it is dropped. */
4
+ export declare const MAX_RAISED_EVENTS = 25;
5
+ /**
6
+ * Key for definition-declared send work. Work belongs to an (origin step,
7
+ * event) pair, not to an event alone — the same event name can be declared
8
+ * from several steps with different work on each. Length-prefixing the step id
9
+ * keeps the key injective without reserving a separator character.
10
+ */
11
+ export declare const eventWorkKey: (from: string, event: string) => string;
12
+ /**
13
+ * How one edge is named in errors and timeout messages.
14
+ *
15
+ * A declared label wins outright — that is the point of declaring one. Without
16
+ * it the fallback still has to distinguish candidates that share an event and
17
+ * a target and differ only by guard, so it carries the declaration index:
18
+ * `submit[1] (login -> twofa)`.
19
+ */
20
+ export declare const describeTransition: (transition: RuntimeTransition) => string;
21
+ /**
22
+ * The public, generics-free view of an edge handed to step hooks. Built once
23
+ * per navigation and shared by the three hooks it runs — and left unfrozen,
24
+ * like the hook args it rides on, since it does not outlive them.
25
+ */
26
+ export declare const transitionInfo: (transition: RuntimeTransition | null) => TransitionInfo | null;
27
+ export declare const SUCCESS_ASYNC: StepAsyncState;
28
+ export declare const LOADING_ASYNC: StepAsyncState;
29
+ /**
30
+ * Own-property membership, for every guard that asks "is this a declared id?".
31
+ *
32
+ * `in` walks the prototype chain, so `"toString" in steps` is true for any
33
+ * object literal. Using it to validate step ids let `toString`, `constructor`,
34
+ * `__proto__`, `hasOwnProperty` and friends pass as declared steps — including
35
+ * ids arriving from a persisted record or a route parameter, which are not
36
+ * developer-authored. Own-property checks are the only correct test here.
37
+ */
38
+ export declare const hasOwn: (target: object, key: string) => boolean;
39
+ /** Subscriber exceptions are isolated so one listener cannot break the pipeline. */
40
+ export declare function reportListenerError(error: unknown): void;
@@ -0,0 +1,9 @@
1
+ import type { JourneyRuntime } from "./runtime.js";
2
+ import type { JourneyMachineBase } from "./types.js";
3
+ /**
4
+ * Builds the stable machine surface over a runtime. The object (and every
5
+ * nested group) is created once — all changing state lives in the snapshot.
6
+ */
7
+ export declare function buildMachineSurface(runtime: JourneyRuntime): JourneyMachineBase<unknown, string> & {
8
+ plugins: Readonly<Record<string, unknown>>;
9
+ };
@@ -0,0 +1,9 @@
1
+ import type { JourneyRuntime } from "./runtime.js";
2
+ import type { JourneyMachineBase } from "./types.js";
3
+ /**
4
+ * Builds the stable machine surface over a runtime. The object (and every
5
+ * nested group) is created once — all changing state lives in the snapshot.
6
+ */
7
+ export declare function buildMachineSurface(runtime: JourneyRuntime): JourneyMachineBase<unknown, string> & {
8
+ plugins: Readonly<Record<string, unknown>>;
9
+ };
@@ -0,0 +1,115 @@
1
+ import { JourneyStore } from "./store.js";
2
+ import type { AnyNavigationWork, AnySendWork, RuntimeConfig } from "./runtime.types.js";
3
+ import type { ContextUpdater, NavigationResult } from "./types.js";
4
+ export declare class JourneyRuntime {
5
+ readonly store: JourneyStore<unknown, string>;
6
+ readonly pluginApis: Record<string, unknown>;
7
+ private readonly config;
8
+ private status;
9
+ private timeline;
10
+ private currentIndex;
11
+ private context;
12
+ private outcome;
13
+ private visitCounts;
14
+ private entryAsync;
15
+ private pending;
16
+ private disposed;
17
+ /** One-shot seed for the first start(); restart() always enters fresh. */
18
+ private restoreSeed;
19
+ /** Bumped by terminate/restart/dispose so stale hook continuations bail out. */
20
+ private generation;
21
+ private raiseQueue;
22
+ private processingRaised;
23
+ private lastPluginExtensions;
24
+ /** The last built snapshot — the sharing baseline for buildSnapshot(). */
25
+ private lastSnapshot;
26
+ private readonly frozenStepOrder;
27
+ /**
28
+ * Per-step registration stacks, innermost last. Resolution is last-wins, but
29
+ * a stack (rather than a single slot) is what lets an unregister restore the
30
+ * registration it shadowed — two owners guarding one step is the normal case
31
+ * for component-scoped wrappers, and dropping to "ungated" when the newer one
32
+ * unmounts would fail silently.
33
+ */
34
+ private readonly transitionListeners;
35
+ private readonly disposeCallbacks;
36
+ private readonly snapshotDerivers;
37
+ constructor(config: RuntimeConfig);
38
+ start(): boolean;
39
+ pause(): boolean;
40
+ resume(): boolean;
41
+ complete(payload?: unknown): boolean;
42
+ terminate(payload?: unknown): boolean;
43
+ restart(): boolean;
44
+ dispose(): void;
45
+ updateContext(updater: ContextUpdater<unknown>): void;
46
+ clearAsyncError(): void;
47
+ goToStepById(id: string): Promise<NavigationResult>;
48
+ goToPreviousStep(n?: number): Promise<NavigationResult>;
49
+ goToNextStep(work?: AnyNavigationWork): Promise<NavigationResult>;
50
+ goToLastVisitedStep(): Promise<NavigationResult>;
51
+ /** Linear-only: declared-order index navigation, delegating to `goToStepById`. */
52
+ goToStepByIndex(index: number): Promise<NavigationResult>;
53
+ /** Graph-only primary verb; also drives raised events. */
54
+ send(type: string, payload?: unknown, work?: AnySendWork): Promise<NavigationResult>;
55
+ /**
56
+ * Work-carrying send: the async runs *before* routing, so its `commit` can
57
+ * stage the very context the guards are then evaluated against. Guards stay
58
+ * sync and pure — the work supplies facts, the definition still picks the
59
+ * edge.
60
+ *
61
+ * The machine holds its position for the whole `working` phase (`pending.to`
62
+ * is null: there is no target yet). If no candidate is enabled once the
63
+ * context is staged, the staged context is discarded and nothing is
64
+ * published — either the send routed and committed, or neither happened.
65
+ */
66
+ private sendWithWork;
67
+ private setupPlugins;
68
+ private currentStepId;
69
+ private eventFor;
70
+ /**
71
+ * `context` is explicit so a work-carrying `send` can evaluate guards against
72
+ * the context its `commit` just staged, rather than the committed one.
73
+ * `result` is the work's run result during that same routing pass; outside a
74
+ * work send (plain sends, snapshot introspection) guards see it as undefined.
75
+ */
76
+ private isEnabled;
77
+ /** First enabled candidate for `event` from the current step, in declaration order. */
78
+ private resolveTransition;
79
+ private checkNavigable;
80
+ private setStatus;
81
+ /** Re-derives `snapshot.plugins` after plugin taps ran post-publish. */
82
+ private refreshPluginSnapshot;
83
+ private blocked;
84
+ private hookArgs;
85
+ private invokeEffect;
86
+ /**
87
+ * `overrideMs` is the declaring edge's own budget. It wins over
88
+ * `defaultTimeoutMs` so that one slow third-party call does not force every
89
+ * other edge onto the slow one's budget; `undefined` falls back to the
90
+ * global, and a global of `undefined` means no bound at all.
91
+ */
92
+ private withTimeout;
93
+ /** Entry on start()/restart(): no onLeave, `from` is null, event is null. */
94
+ private enterInitialStep;
95
+ private runNavigation;
96
+ /**
97
+ * Publishes the position change and any staged context in one snapshot, then
98
+ * awaits the post-commit effects. Shared by plain navigation and by a
99
+ * work-carrying `send`, which reaches here only once its target is resolved.
100
+ */
101
+ private commitAndSettle;
102
+ /** Shared commit bookkeeping for navigations and the initial entry. */
103
+ private commitEntry;
104
+ /** Post-commit effects: step `onLeave`, transition effect, then step `onEnter`. */
105
+ private runEntryEffects;
106
+ /**
107
+ * Raised events run FIFO after the transition settles; a cascade longer than
108
+ * {@link MAX_RAISED_EVENTS} is dropped and surfaced as an `error` event.
109
+ */
110
+ private processRaisedEvents;
111
+ private isCurrent;
112
+ private staleResult;
113
+ private publish;
114
+ private buildSnapshot;
115
+ }
@@ -0,0 +1,115 @@
1
+ import { JourneyStore } from "./store.js";
2
+ import type { AnyNavigationWork, AnySendWork, RuntimeConfig } from "./runtime.types.js";
3
+ import type { ContextUpdater, NavigationResult } from "./types.js";
4
+ export declare class JourneyRuntime {
5
+ readonly store: JourneyStore<unknown, string>;
6
+ readonly pluginApis: Record<string, unknown>;
7
+ private readonly config;
8
+ private status;
9
+ private timeline;
10
+ private currentIndex;
11
+ private context;
12
+ private outcome;
13
+ private visitCounts;
14
+ private entryAsync;
15
+ private pending;
16
+ private disposed;
17
+ /** One-shot seed for the first start(); restart() always enters fresh. */
18
+ private restoreSeed;
19
+ /** Bumped by terminate/restart/dispose so stale hook continuations bail out. */
20
+ private generation;
21
+ private raiseQueue;
22
+ private processingRaised;
23
+ private lastPluginExtensions;
24
+ /** The last built snapshot — the sharing baseline for buildSnapshot(). */
25
+ private lastSnapshot;
26
+ private readonly frozenStepOrder;
27
+ /**
28
+ * Per-step registration stacks, innermost last. Resolution is last-wins, but
29
+ * a stack (rather than a single slot) is what lets an unregister restore the
30
+ * registration it shadowed — two owners guarding one step is the normal case
31
+ * for component-scoped wrappers, and dropping to "ungated" when the newer one
32
+ * unmounts would fail silently.
33
+ */
34
+ private readonly transitionListeners;
35
+ private readonly disposeCallbacks;
36
+ private readonly snapshotDerivers;
37
+ constructor(config: RuntimeConfig);
38
+ start(): boolean;
39
+ pause(): boolean;
40
+ resume(): boolean;
41
+ complete(payload?: unknown): boolean;
42
+ terminate(payload?: unknown): boolean;
43
+ restart(): boolean;
44
+ dispose(): void;
45
+ updateContext(updater: ContextUpdater<unknown>): void;
46
+ clearAsyncError(): void;
47
+ goToStepById(id: string): Promise<NavigationResult>;
48
+ goToPreviousStep(n?: number): Promise<NavigationResult>;
49
+ goToNextStep(work?: AnyNavigationWork): Promise<NavigationResult>;
50
+ goToLastVisitedStep(): Promise<NavigationResult>;
51
+ /** Linear-only: declared-order index navigation, delegating to `goToStepById`. */
52
+ goToStepByIndex(index: number): Promise<NavigationResult>;
53
+ /** Graph-only primary verb; also drives raised events. */
54
+ send(type: string, payload?: unknown, work?: AnySendWork): Promise<NavigationResult>;
55
+ /**
56
+ * Work-carrying send: the async runs *before* routing, so its `commit` can
57
+ * stage the very context the guards are then evaluated against. Guards stay
58
+ * sync and pure — the work supplies facts, the definition still picks the
59
+ * edge.
60
+ *
61
+ * The machine holds its position for the whole `working` phase (`pending.to`
62
+ * is null: there is no target yet). If no candidate is enabled once the
63
+ * context is staged, the staged context is discarded and nothing is
64
+ * published — either the send routed and committed, or neither happened.
65
+ */
66
+ private sendWithWork;
67
+ private setupPlugins;
68
+ private currentStepId;
69
+ private eventFor;
70
+ /**
71
+ * `context` is explicit so a work-carrying `send` can evaluate guards against
72
+ * the context its `commit` just staged, rather than the committed one.
73
+ * `result` is the work's run result during that same routing pass; outside a
74
+ * work send (plain sends, snapshot introspection) guards see it as undefined.
75
+ */
76
+ private isEnabled;
77
+ /** First enabled candidate for `event` from the current step, in declaration order. */
78
+ private resolveTransition;
79
+ private checkNavigable;
80
+ private setStatus;
81
+ /** Re-derives `snapshot.plugins` after plugin taps ran post-publish. */
82
+ private refreshPluginSnapshot;
83
+ private blocked;
84
+ private hookArgs;
85
+ private invokeEffect;
86
+ /**
87
+ * `overrideMs` is the declaring edge's own budget. It wins over
88
+ * `defaultTimeoutMs` so that one slow third-party call does not force every
89
+ * other edge onto the slow one's budget; `undefined` falls back to the
90
+ * global, and a global of `undefined` means no bound at all.
91
+ */
92
+ private withTimeout;
93
+ /** Entry on start()/restart(): no onLeave, `from` is null, event is null. */
94
+ private enterInitialStep;
95
+ private runNavigation;
96
+ /**
97
+ * Publishes the position change and any staged context in one snapshot, then
98
+ * awaits the post-commit effects. Shared by plain navigation and by a
99
+ * work-carrying `send`, which reaches here only once its target is resolved.
100
+ */
101
+ private commitAndSettle;
102
+ /** Shared commit bookkeeping for navigations and the initial entry. */
103
+ private commitEntry;
104
+ /** Post-commit effects: step `onLeave`, transition effect, then step `onEnter`. */
105
+ private runEntryEffects;
106
+ /**
107
+ * Raised events run FIFO after the transition settles; a cascade longer than
108
+ * {@link MAX_RAISED_EVENTS} is dropped and surfaced as an `error` event.
109
+ */
110
+ private processRaisedEvents;
111
+ private isCurrent;
112
+ private staleResult;
113
+ private publish;
114
+ private buildSnapshot;
115
+ }
@@ -0,0 +1,112 @@
1
+ import type { AnyJourneyPlugin, ContextUpdater, JourneyEventObject, JourneySnapshot, NavigationDirection, NavigationWork, NavigationResult, StepHookArgs } from "./types.js";
2
+ /** Internal, kind-agnostic hook shapes (public typing lives in the creators). */
3
+ export type AnyHookArgs = StepHookArgs<unknown, string, JourneyEventObject>;
4
+ export type AnyOnEffect = (args: AnyHookArgs) => void | Promise<void>;
5
+ export type AnyNavigationWork = NavigationWork<unknown, string, JourneySnapshot, unknown>;
6
+ /**
7
+ * Send work runs before routing, so unlike navigation work it has no `to` or
8
+ * `direction` to report — the target is not chosen yet. It carries the event
9
+ * that triggered it and the machine's handlers instead.
10
+ */
11
+ export type AnySendWorkArgs = {
12
+ readonly snapshot: JourneySnapshot;
13
+ readonly from: string;
14
+ readonly event: JourneyEventObject;
15
+ readonly handlers: unknown;
16
+ };
17
+ export type AnySendWork = {
18
+ readonly run: (args: AnySendWorkArgs) => unknown;
19
+ readonly commit?: (args: AnySendWorkArgs & {
20
+ readonly result: unknown;
21
+ readonly updateContext: (updater: ContextUpdater<unknown>) => void;
22
+ }) => unknown;
23
+ /** Per-entry budget for `run`; falls back to `defaultTimeoutMs` when unset. */
24
+ readonly timeoutMs?: number;
25
+ /** Name used for this work in timeout and error messages. */
26
+ readonly label?: string;
27
+ };
28
+ export type RuntimeStep = {
29
+ readonly metadata: unknown;
30
+ readonly onEnter?: AnyOnEffect;
31
+ readonly onLeave?: AnyOnEffect;
32
+ };
33
+ export type RuntimeTransition = {
34
+ readonly event: string;
35
+ readonly from: string;
36
+ readonly to: string;
37
+ /**
38
+ * Position among the candidates `from` declares for `event`. Identifies an
39
+ * unlabelled edge in errors, where `event` and `to` may be shared by several
40
+ * candidates that differ only by guard.
41
+ */
42
+ readonly index: number;
43
+ /** The edge's declared name, used in place of the positional description. */
44
+ readonly label?: string;
45
+ /** Per-edge budget for `onTransition`; falls back to `defaultTimeoutMs`. */
46
+ readonly timeoutMs?: number;
47
+ /**
48
+ * `result` is the run result while routing a work send, and undefined
49
+ * everywhere else (plain sends, snapshot introspection).
50
+ */
51
+ readonly when?: (args: {
52
+ context: unknown;
53
+ handlers: unknown;
54
+ result?: unknown;
55
+ }) => boolean;
56
+ readonly onTransition?: AnyOnEffect;
57
+ };
58
+ export type RuntimeConfig = {
59
+ readonly kind: "linear" | "graph";
60
+ /** Declaration order (linear: the navigation order; graph: for totals only). */
61
+ readonly stepIds: readonly string[];
62
+ readonly steps: Readonly<Record<string, RuntimeStep>>;
63
+ readonly initial: string;
64
+ /** Overrides `initial` for the entry on start()/restart(). */
65
+ readonly startAt?: string;
66
+ readonly initialContext: unknown;
67
+ /** Graph only: flattened transitions map in declaration order. */
68
+ readonly transitions: readonly RuntimeTransition[];
69
+ /**
70
+ * Graph only: work declared on an event in the definition, keyed by
71
+ * {@link eventWorkKey} — two steps may declare different work for the same
72
+ * event name, so the origin step is part of the key.
73
+ */
74
+ readonly eventWork?: Readonly<Record<string, AnySendWork>>;
75
+ readonly handlers: unknown;
76
+ readonly autoStart: boolean;
77
+ readonly defaultTimeoutMs: number | undefined;
78
+ /** Routes isolated subscriber failures; defaults to the console reporter. */
79
+ readonly onListenerError?: (error: unknown) => void;
80
+ /**
81
+ * Seeds the first `start()` from a persisted record instead of a fresh
82
+ * entry at `startAt ?? initial`. Consumed once — `restart()` always goes
83
+ * fresh. Factories only pass a record that validated against the definition.
84
+ */
85
+ readonly restore?: {
86
+ readonly context: unknown;
87
+ readonly timeline: readonly string[];
88
+ readonly currentIndex: number;
89
+ };
90
+ readonly plugins: readonly AnyJourneyPlugin[];
91
+ };
92
+ /**
93
+ * The reason half of a failed navigation. `from`/`to` are deliberately absent:
94
+ * `blocked()` is the single place that knows both, and it fills them in when
95
+ * building the public `NavigationResult`. Deriving this straight from
96
+ * `NavigationResult` would force every internal call site to repeat them.
97
+ */
98
+ export type NavigationFailure = Omit<Extract<NavigationResult, {
99
+ ok: false;
100
+ }>, "from" | "to">;
101
+ export type TimelineOp = {
102
+ readonly kind: "pointer";
103
+ readonly index: number;
104
+ } | {
105
+ readonly kind: "append";
106
+ };
107
+ export type WorkDirection = NavigationDirection;
108
+ export type TransitionListener = (info: {
109
+ from: string | null;
110
+ to: string;
111
+ snapshot: JourneySnapshot;
112
+ }) => void;
@@ -0,0 +1,112 @@
1
+ import type { AnyJourneyPlugin, ContextUpdater, JourneyEventObject, JourneySnapshot, NavigationDirection, NavigationWork, NavigationResult, StepHookArgs } from "./types.js";
2
+ /** Internal, kind-agnostic hook shapes (public typing lives in the creators). */
3
+ export type AnyHookArgs = StepHookArgs<unknown, string, JourneyEventObject>;
4
+ export type AnyOnEffect = (args: AnyHookArgs) => void | Promise<void>;
5
+ export type AnyNavigationWork = NavigationWork<unknown, string, JourneySnapshot, unknown>;
6
+ /**
7
+ * Send work runs before routing, so unlike navigation work it has no `to` or
8
+ * `direction` to report — the target is not chosen yet. It carries the event
9
+ * that triggered it and the machine's handlers instead.
10
+ */
11
+ export type AnySendWorkArgs = {
12
+ readonly snapshot: JourneySnapshot;
13
+ readonly from: string;
14
+ readonly event: JourneyEventObject;
15
+ readonly handlers: unknown;
16
+ };
17
+ export type AnySendWork = {
18
+ readonly run: (args: AnySendWorkArgs) => unknown;
19
+ readonly commit?: (args: AnySendWorkArgs & {
20
+ readonly result: unknown;
21
+ readonly updateContext: (updater: ContextUpdater<unknown>) => void;
22
+ }) => unknown;
23
+ /** Per-entry budget for `run`; falls back to `defaultTimeoutMs` when unset. */
24
+ readonly timeoutMs?: number;
25
+ /** Name used for this work in timeout and error messages. */
26
+ readonly label?: string;
27
+ };
28
+ export type RuntimeStep = {
29
+ readonly metadata: unknown;
30
+ readonly onEnter?: AnyOnEffect;
31
+ readonly onLeave?: AnyOnEffect;
32
+ };
33
+ export type RuntimeTransition = {
34
+ readonly event: string;
35
+ readonly from: string;
36
+ readonly to: string;
37
+ /**
38
+ * Position among the candidates `from` declares for `event`. Identifies an
39
+ * unlabelled edge in errors, where `event` and `to` may be shared by several
40
+ * candidates that differ only by guard.
41
+ */
42
+ readonly index: number;
43
+ /** The edge's declared name, used in place of the positional description. */
44
+ readonly label?: string;
45
+ /** Per-edge budget for `onTransition`; falls back to `defaultTimeoutMs`. */
46
+ readonly timeoutMs?: number;
47
+ /**
48
+ * `result` is the run result while routing a work send, and undefined
49
+ * everywhere else (plain sends, snapshot introspection).
50
+ */
51
+ readonly when?: (args: {
52
+ context: unknown;
53
+ handlers: unknown;
54
+ result?: unknown;
55
+ }) => boolean;
56
+ readonly onTransition?: AnyOnEffect;
57
+ };
58
+ export type RuntimeConfig = {
59
+ readonly kind: "linear" | "graph";
60
+ /** Declaration order (linear: the navigation order; graph: for totals only). */
61
+ readonly stepIds: readonly string[];
62
+ readonly steps: Readonly<Record<string, RuntimeStep>>;
63
+ readonly initial: string;
64
+ /** Overrides `initial` for the entry on start()/restart(). */
65
+ readonly startAt?: string;
66
+ readonly initialContext: unknown;
67
+ /** Graph only: flattened transitions map in declaration order. */
68
+ readonly transitions: readonly RuntimeTransition[];
69
+ /**
70
+ * Graph only: work declared on an event in the definition, keyed by
71
+ * {@link eventWorkKey} — two steps may declare different work for the same
72
+ * event name, so the origin step is part of the key.
73
+ */
74
+ readonly eventWork?: Readonly<Record<string, AnySendWork>>;
75
+ readonly handlers: unknown;
76
+ readonly autoStart: boolean;
77
+ readonly defaultTimeoutMs: number | undefined;
78
+ /** Routes isolated subscriber failures; defaults to the console reporter. */
79
+ readonly onListenerError?: (error: unknown) => void;
80
+ /**
81
+ * Seeds the first `start()` from a persisted record instead of a fresh
82
+ * entry at `startAt ?? initial`. Consumed once — `restart()` always goes
83
+ * fresh. Factories only pass a record that validated against the definition.
84
+ */
85
+ readonly restore?: {
86
+ readonly context: unknown;
87
+ readonly timeline: readonly string[];
88
+ readonly currentIndex: number;
89
+ };
90
+ readonly plugins: readonly AnyJourneyPlugin[];
91
+ };
92
+ /**
93
+ * The reason half of a failed navigation. `from`/`to` are deliberately absent:
94
+ * `blocked()` is the single place that knows both, and it fills them in when
95
+ * building the public `NavigationResult`. Deriving this straight from
96
+ * `NavigationResult` would force every internal call site to repeat them.
97
+ */
98
+ export type NavigationFailure = Omit<Extract<NavigationResult, {
99
+ ok: false;
100
+ }>, "from" | "to">;
101
+ export type TimelineOp = {
102
+ readonly kind: "pointer";
103
+ readonly index: number;
104
+ } | {
105
+ readonly kind: "append";
106
+ };
107
+ export type WorkDirection = NavigationDirection;
108
+ export type TransitionListener = (info: {
109
+ from: string | null;
110
+ to: string;
111
+ snapshot: JourneySnapshot;
112
+ }) => void;
@@ -0,0 +1,31 @@
1
+ import type { JourneyEventPayloads, JourneySnapshot, JourneySubscriptionEvent, Unsubscribe } from "./types.js";
2
+ /**
3
+ * Snapshot holder + subscription hub. Snapshots are immutable and rebuilt by
4
+ * the runtime; the store only distributes them.
5
+ */
6
+ export declare class JourneyStore<TContext, TStepId extends string> {
7
+ private snapshot;
8
+ private readonly listeners;
9
+ private readonly eventListeners;
10
+ private disposed;
11
+ private readonly onListenerError;
12
+ constructor(initial: JourneySnapshot<TContext, TStepId>, onListenerError?: (error: unknown) => void);
13
+ /**
14
+ * Isolation stays unconditional; the configured reporter only routes the
15
+ * report. Internal, but reachable from the runtime so plugin-boundary
16
+ * failures land in the same place as subscriber failures.
17
+ */
18
+ report(error: unknown): void;
19
+ getSnapshot(): JourneySnapshot<TContext, TStepId>;
20
+ /** Replaces the snapshot and notifies every subscriber. */
21
+ publish(next: JourneySnapshot<TContext, TStepId>): void;
22
+ /**
23
+ * Notifies on every committed snapshot. Deriving a slice and skipping
24
+ * unchanged values is the caller's job — in React that is `useSelector`,
25
+ * which has to own the comparison anyway to keep render identity stable.
26
+ */
27
+ subscribe(listener: () => void): Unsubscribe;
28
+ subscribeEvent<TEvent extends JourneySubscriptionEvent>(event: TEvent, listener: (payload: JourneyEventPayloads<TContext, TStepId>[TEvent]) => void): Unsubscribe;
29
+ emit<TEvent extends JourneySubscriptionEvent>(event: TEvent, payload: JourneyEventPayloads<TContext, TStepId>[TEvent]): void;
30
+ dispose(): void;
31
+ }