@rxova/journey-core 1.0.0-rc.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/README.md +182 -186
  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 +46 -0
  13. package/dist/core/helpers.d.ts +46 -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 +78 -79
  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
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/plugins/diagnostics/index.ts", "../../../src/journey-machine/helpers.ts", "../../../src/journey-machine/resolve-journey-definition.ts", "../../../src/plugins/diagnostics/diagnostics.ts"],
4
- "sourcesContent": ["import { getJourneyDiagnostics } from \"./diagnostics\";\n\nimport type {\n JourneyDiagnosticsOptions,\n JourneyDiagnosticsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyMachine,\n JourneyMachinePlugin\n} from \"../../types\";\n\nexport type JourneyDiagnosticsMachineExtension<\n TStepId extends string,\n TEventType extends string\n> = {\n getDiagnostics: (\n options?: JourneyDiagnosticsOptions\n ) => JourneyDiagnosticsResult<TStepId, TEventType>;\n};\n\nexport type JourneyDiagnosticsMachine<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> &\n JourneyDiagnosticsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;\n\n/** Creates a plugin that augments a machine with structural diagnostics helpers. */\nexport const createDiagnosticsPlugin = () =>\n ({\n name: \"diagnostics\",\n setup: ({ journey, options }) => ({\n augmentMachine: () => ({\n getDiagnostics: (diagnosticsOptions?: JourneyDiagnosticsOptions) =>\n getJourneyDiagnostics(journey, {\n requireExplicitCompletion:\n diagnosticsOptions?.requireExplicitCompletion ?? options.requireExplicitCompletion\n })\n })\n })\n }) satisfies JourneyMachinePlugin;\n\nexport { getJourneyDiagnostics } from \"./diagnostics\";\n", "import type {\n JourneyAsyncState,\n JourneyEvent,\n JourneyGoToEvent,\n JourneyJsonObject,\n JourneyJsonValue,\n JourneyPayloadFor,\n JourneyResolvedTransition,\n JourneySendEvent,\n JourneySendResult,\n JourneySnapshot,\n JourneyStatus,\n JourneyStepAsyncState,\n JourneyTerminal,\n JourneyTransition,\n JourneyTransitionArgs\n} from \"../types\";\n\nexport const assertStepExists = <TStepId extends string>(\n steps: Record<TStepId, unknown>,\n stepId: TStepId,\n message: string\n) => {\n if (!(stepId in steps)) {\n throw new Error(message);\n }\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n\nconst cloneSerializableValue = <T extends JourneyJsonValue>(value: T): T => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneSerializableValue(entry)) as T;\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneSerializableValue(entryValue as JourneyJsonValue)\n ])\n ) as T;\n }\n\n return value;\n};\n\ntype SerializableCheckState = {\n readonly seen: WeakSet<object>;\n};\n\nconst describeValue = (value: unknown): string => {\n if (value === null) {\n return \"null\";\n }\n\n if (Array.isArray(value)) {\n return \"array\";\n }\n\n if (typeof value === \"object\") {\n const constructorName = (value as { constructor?: { name?: string } }).constructor?.name;\n return constructorName && constructorName !== \"Object\" ? constructorName : \"object\";\n }\n\n return typeof value;\n};\n\nfunction assertSerializableValue(\n value: unknown,\n label: string,\n state: SerializableCheckState,\n path: readonly string[] = []\n): asserts value is JourneyJsonValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return;\n }\n\n const pathLabel = path.length === 0 ? label : `${label}.${path.join(\".\")}`;\n\n if (value === undefined) {\n throw new Error(`${pathLabel} must be JSON-serializable. Received undefined.`);\n }\n\n if (typeof value === \"bigint\" || typeof value === \"symbol\" || typeof value === \"function\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${typeof value}.`);\n }\n\n if (typeof value !== \"object\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${describeValue(value)}.`);\n }\n\n if (state.seen.has(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Circular references are not supported.`\n );\n }\n\n state.seen.add(value);\n\n if (Array.isArray(value)) {\n for (const [index, entryValue] of value.entries()) {\n assertSerializableValue(entryValue, label, state, [...path, String(index)]);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Received non-plain ${describeValue(value)}.`\n );\n }\n\n for (const [key, entryValue] of Object.entries(value)) {\n assertSerializableValue(entryValue, label, state, [...path, key]);\n }\n}\n\nexport function assertSerializableContext<TContext extends JourneyJsonObject>(\n context: TContext,\n label = \"Journey context\"\n): TContext {\n assertSerializableValue(context, label, { seen: new WeakSet() });\n return context;\n}\n\nexport const cloneContext = <TContext extends JourneyJsonObject>(context: TContext): TContext =>\n cloneSerializableValue(assertSerializableContext(context));\n\nconst cloneDefinitionValueFallback = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneDefinitionValueFallback(entry));\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime());\n }\n\n if (value instanceof Map) {\n return new Map(\n [...value.entries()].map(([key, entryValue]) => [\n cloneDefinitionValueFallback(key),\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n if (value instanceof Set) {\n return new Set([...value].map((entry) => cloneDefinitionValueFallback(entry)));\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n return value;\n};\n\nexport const cloneMetaValue = <T>(value: T): T => {\n if ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n return value;\n }\n\n if (typeof structuredClone === \"function\") {\n try {\n return structuredClone(value);\n } catch {\n return cloneDefinitionValueFallback(value) as T;\n }\n } else {\n return cloneDefinitionValueFallback(value) as T;\n }\n};\n\nconst freezeSnapshotValue = (value: unknown) => {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n freezeSnapshotValue(item);\n }\n Object.freeze(value);\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n for (const entryValue of Object.values(value)) {\n freezeSnapshotValue(entryValue);\n }\n Object.freeze(value);\n};\n\nexport const normalizeStepCount = (steps?: number): number => {\n if (typeof steps !== \"number\" || !Number.isFinite(steps)) {\n return 1;\n }\n return Math.max(1, Math.trunc(steps));\n};\n\nexport const now = (): number => Date.now();\n\nconst unique = <T>(items: readonly T[]): T[] => [...new Set(items)];\n\nconst normalizeVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n stepIds: readonly TStepId[]\n): Record<TStepId, boolean> =>\n Object.fromEntries(stepIds.map((stepId) => [stepId, visited[stepId] === true])) as Record<\n TStepId,\n boolean\n >;\n\nexport const buildVisitedFromTimeline = <TStepId extends string>(\n timeline: readonly TStepId[],\n stepIds?: readonly TStepId[]\n): Record<TStepId, boolean> => {\n const resolvedStepIds = stepIds ?? unique(timeline);\n const visited = Object.fromEntries(resolvedStepIds.map((stepId) => [stepId, false])) as Record<\n TStepId,\n boolean\n >;\n\n for (const stepId of timeline) {\n visited[stepId] = true;\n }\n\n return visited;\n};\n\nexport const appendVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n current: TStepId\n): Record<TStepId, boolean> => ({\n ...visited,\n [current]: true\n});\n\nexport const isPromiseLike = <T>(value: T | PromiseLike<T>): value is PromiseLike<T> =>\n typeof value === \"object\" &&\n value !== null &&\n \"then\" in value &&\n typeof (value as { then: unknown }).then === \"function\";\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value);\n\nexport const validateFiniteTimeout = (timeoutMs: unknown, label: string) => {\n if (timeoutMs !== undefined && !isFiniteNumber(timeoutMs)) {\n throw new Error(`${label} must define a finite numeric \"timeoutMs\" when provided.`);\n }\n};\n\nexport class JourneyTimeoutError extends Error {\n override name = \"JourneyTimeoutError\";\n\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class JourneyDisposedError extends Error {\n override name = \"JourneyDisposedError\";\n readonly operation: string;\n\n constructor(operation: string) {\n super(`Journey machine has been disposed; \"${operation}\" can no longer be used.`);\n this.operation = operation;\n }\n}\n\ntype DiagnosticGlobal = typeof globalThis & {\n __DEV__?: unknown;\n process?: {\n env?: {\n NODE_ENV?: string;\n };\n };\n};\n\nexport const isDevelopmentEnvironment = (): boolean => {\n const diagnosticGlobal = globalThis as DiagnosticGlobal;\n if (typeof diagnosticGlobal.__DEV__ === \"boolean\") {\n return diagnosticGlobal.__DEV__;\n }\n\n const nodeEnv = diagnosticGlobal.process?.env?.NODE_ENV;\n return nodeEnv === undefined || nodeEnv === \"development\";\n};\n\nexport const warnInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.warn(message);\n return;\n }\n\n console.warn(message, detail);\n};\n\nexport const errorInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.error(message);\n return;\n }\n\n console.error(message, detail);\n};\n\nexport const withTimeout = async <T>(\n promise: PromiseLike<T>,\n timeoutMs: number | undefined,\n buildError: () => Error\n): Promise<T> => {\n if (!isFiniteNumber(timeoutMs) || timeoutMs <= 0) {\n return await promise;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(buildError());\n }, timeoutMs);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n }\n );\n });\n};\n\nexport const withAbortSignal = async <T>(\n promise: PromiseLike<T>,\n signal: AbortSignal\n): Promise<T> => {\n if (signal.aborted) {\n throw signal.reason;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(signal.reason);\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n }\n );\n });\n};\n\nexport const buildIdleStepAsyncState = (): JourneyStepAsyncState => ({\n phase: \"idle\",\n eventType: null,\n transitionId: null,\n error: null\n});\n\nexport const buildInitialAsyncState = <TStepId extends string>(\n steps: Record<TStepId, unknown>\n): JourneyAsyncState<TStepId> => {\n const byStep = Object.fromEntries(\n Object.keys(steps).map((stepId) => [stepId, buildIdleStepAsyncState()])\n ) as Record<TStepId, JourneyStepAsyncState>;\n\n return {\n isLoading: false,\n byStep\n };\n};\n\nexport const isGoToStepByIdEvent = <\n TStepId extends string,\n TEventMap extends Record<string, unknown>\n>(\n event: JourneySendEvent<TStepId, TEventMap>\n): event is JourneyGoToEvent<TStepId, JourneyPayloadFor<TEventMap, \"goToStepById\">> =>\n event.type === \"goToStepById\" && \"stepId\" in event;\n\nexport const isTerminalTarget = <TStepId extends string>(\n target: TStepId | JourneyTerminal\n): target is JourneyTerminal => target === \"COMPLETE\" || target === \"TERMINATED\";\n\nexport const resolveTransitionTarget = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transition: JourneyTransition<TContext, TStepId, TEventMap, THandlers>\n): TStepId | JourneyTerminal =>\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : (transition.to as TStepId | JourneyTerminal);\n\nexport const validateJourneyTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[],\n steps: Record<TStepId, unknown>\n) => {\n const stepRegistry = steps as Record<string, unknown>;\n const allowedKeys = new Set([\n \"from\",\n \"event\",\n \"to\",\n \"when\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"id\",\n \"label\",\n \"timeoutMs\"\n ]);\n\n for (const [index, transition] of transitions.entries()) {\n if (!transition || typeof transition !== \"object\") {\n throw new Error(`Journey transition at index ${index} must be an object.`);\n }\n\n for (const key of Object.keys(transition)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at index ${index} contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (typeof transition.from !== \"string\" || typeof transition.event !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define string \"from\" and \"event\".`\n );\n }\n\n if (transition.from !== \"*\" && !(transition.from in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} references unknown from step \"${transition.from}\".`\n );\n }\n\n validateFiniteTimeout(transition.timeoutMs, `Journey transition at index ${index}`);\n\n if (transition.when !== undefined && typeof transition.when !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"when\" as a function when provided.`\n );\n }\n\n if (transition.updateContext !== undefined && typeof transition.updateContext !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (transition.onEnter !== undefined && typeof transition.onEnter !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (transition.onLeave !== undefined && typeof transition.onLeave !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n if (transition.id !== undefined && typeof transition.id !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"id\" as a string when provided.`\n );\n }\n\n if (transition.label !== undefined && typeof transition.label !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"label\" as a string when provided.`\n );\n }\n\n if (transition.event === \"completeJourney\" || transition.event === \"terminateJourney\") {\n if (\"to\" in transition && transition.to !== undefined) {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" cannot define \"to\".`\n );\n }\n continue;\n }\n\n if (typeof transition.to !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" must define string \"to\".`\n );\n }\n\n if (!isTerminalTarget(transition.to) && !(transition.to in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} points to unknown step \"${transition.to}\".`\n );\n }\n }\n};\n\nexport const buildSendResult = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n transitioned: boolean,\n options: {\n transitionId?: string;\n label?: string;\n error?: unknown;\n } = {}\n): JourneySendResult<TContext, TStepId> => ({\n transitioned,\n ...(options.transitionId !== undefined ? { transitionId: options.transitionId } : {}),\n ...(options.label !== undefined ? { label: options.label } : {}),\n ...(\"error\" in options ? { error: options.error } : {}),\n snapshot\n});\n\nexport const buildSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n timeline: readonly TStepId[],\n index: number,\n context: TContext,\n status: JourneyStatus,\n asyncState: JourneyAsyncState<TStepId>,\n visited?: Record<TStepId, boolean>\n): JourneySnapshot<TContext, TStepId> => {\n if (timeline.length === 0) {\n throw new Error(\"Journey timeline cannot be empty.\");\n }\n\n const safeIndex = Math.max(0, Math.min(Math.trunc(index), timeline.length - 1));\n const currentStepId = timeline[safeIndex] as TStepId;\n const stepIds = unique(\n visited ? ([...(Object.keys(visited) as TStepId[]), ...timeline] as const) : timeline\n );\n\n return {\n status,\n currentStepId,\n history: {\n timeline: [...timeline],\n index: safeIndex\n },\n context: cloneContext(context),\n visited: visited\n ? normalizeVisited(visited, stepIds)\n : buildVisitedFromTimeline(timeline, stepIds),\n async: cloneSerializableValue(\n asyncState as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n};\n\nexport const stabilizeSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>\n): JourneySnapshot<TContext, TStepId> => {\n const stableSnapshot: JourneySnapshot<TContext, TStepId> = {\n ...snapshot,\n history: {\n timeline: [...snapshot.history.timeline],\n index: snapshot.history.index\n },\n context: cloneContext(snapshot.context),\n visited: { ...snapshot.visited },\n async: cloneSerializableValue(\n snapshot.async as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n\n freezeSnapshotValue(stableSnapshot);\n return stableSnapshot;\n};\n\nexport const selectTransition = async <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>,\n TTransition extends {\n from: TStepId | \"*\";\n event: string;\n when?: (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>;\n timeoutMs?: number;\n id?: string;\n label?: string;\n }\n>(\n transitions: readonly TTransition[],\n snapshot: JourneySnapshot<TContext, TStepId>,\n event: JourneyEvent<TStepId, TEventMap>,\n signal: AbortSignal,\n handlers: THandlers,\n hooks?: {\n onAsyncGuardStart?: (transition: TTransition) => void;\n onAsyncGuardSuccess?: (transition: TTransition) => void;\n onAsyncGuardError?: (transition: TTransition, error: unknown) => void;\n },\n defaultTimeoutMs?: number\n): Promise<TTransition | null> => {\n for (const transition of transitions) {\n const fromMatches = transition.from === \"*\" || transition.from === snapshot.currentStepId;\n const eventMatches = transition.event === event.type;\n\n if (!fromMatches || !eventMatches) {\n continue;\n }\n\n if (!transition.when) {\n return transition;\n }\n\n let guardResult: boolean | Promise<boolean>;\n if (signal.aborted) {\n throw signal.reason;\n }\n\n guardResult = (\n transition.when as (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>\n )({\n snapshot,\n context: snapshot.context,\n from: snapshot.currentStepId,\n timeline: snapshot.history.timeline,\n index: snapshot.history.index,\n event,\n signal,\n handlers\n });\n\n const asyncGuard = isPromiseLike(guardResult);\n const asyncGuardPromise = asyncGuard ? (guardResult as PromiseLike<boolean>) : null;\n\n let allowed: boolean;\n try {\n if (asyncGuard) {\n hooks?.onAsyncGuardStart?.(transition);\n allowed = await withTimeout(\n withAbortSignal(asyncGuardPromise as PromiseLike<boolean>, signal),\n transition.timeoutMs ?? defaultTimeoutMs,\n () =>\n new JourneyTimeoutError(\n `Transition guard timed out after ${transition.timeoutMs ?? defaultTimeoutMs}ms (event: ${event.type}, transition: ${transition.id ?? \"<anonymous>\"}).`\n )\n );\n } else {\n allowed = guardResult as boolean;\n }\n } catch (error) {\n if (asyncGuard) {\n hooks?.onAsyncGuardError?.(transition, error);\n }\n throw error;\n }\n\n if (asyncGuard) {\n hooks?.onAsyncGuardSuccess?.(transition);\n }\n\n if (allowed) {\n return transition;\n }\n }\n\n return null;\n};\n\nexport const transitionSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n nextCurrent: TStepId,\n nextContext: TContext\n): JourneySnapshot<TContext, TStepId> => {\n const baseTimeline = snapshot.history.timeline.slice(0, snapshot.history.index + 1);\n let nextTimeline = baseTimeline;\n if (nextCurrent !== snapshot.currentStepId) {\n nextTimeline = [...baseTimeline, nextCurrent];\n }\n\n const nextIndex = nextTimeline.length - 1;\n const visited = appendVisited(snapshot.visited, nextCurrent);\n\n return buildSnapshot(\n nextTimeline,\n nextIndex,\n nextContext,\n snapshot.status,\n snapshot.async,\n visited\n );\n};\n", "import { validateFiniteTimeout } from \"./helpers\";\n\nimport type {\n JourneyDefinition,\n JourneyJsonObject,\n JourneyResolvedDefinition,\n JourneyResolvedTransition,\n JourneyTransition,\n JourneyTransitionGraph\n} from \"../types\";\n\nconst hashTransitionDescriptor = (value: string) => {\n let hash = 2166136261;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n};\n\nconst buildResolvedTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyTransition<TContext, TStepId, TEventMap, THandlers>[]\n): JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[] => {\n const transitionRouteCounts = new Map<string, number>();\n const usedIds = new Set<string>();\n\n return transitions.map((transition) => {\n const target =\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : String(transition.to);\n const routeKey = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target\n });\n const ordinal = (transitionRouteCounts.get(routeKey) ?? 0) + 1;\n transitionRouteCounts.set(routeKey, ordinal);\n\n const descriptor = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target,\n ordinal\n });\n\n let suffix = 0;\n const id = (() => {\n let candidate = hashTransitionDescriptor(descriptor);\n while (usedIds.has(candidate)) {\n suffix += 1;\n candidate = hashTransitionDescriptor(`${descriptor}:${suffix}`);\n }\n return candidate;\n })();\n usedIds.add(id);\n\n return {\n ...transition,\n id,\n ...(transition.label !== undefined ? { label: transition.label } : {})\n } as JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>;\n });\n};\n\nexport const resolveJourneyDefinition = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>\n): JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers> => {\n type TEventType = string;\n const resolvedTransitions: JourneyTransition<TContext, TStepId, TEventMap, THandlers>[] = [];\n const { transitions } = journey;\n\n if (transitions === undefined) {\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n }\n\n if (Array.isArray(transitions)) {\n if (transitions.length === 0) {\n throw new Error(\n \"Journey linear transitions must include the initial step as the first item.\"\n );\n }\n\n const [initialStep, ...linearEntries] = transitions;\n if (typeof initialStep !== \"string\") {\n throw new Error(\"Journey linear transitions at index 0 must be a step id string.\");\n }\n\n if (!(initialStep in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${initialStep}\".`);\n }\n\n // Resolve initial: use journey.initial if provided (start from middle), otherwise array[0]\n const resolvedInitial = (journey.initial ?? initialStep) as TStepId;\n\n if (journey.initial !== undefined) {\n const allStepIds = transitions.map((entry) =>\n typeof entry === \"string\" ? entry : entry.step\n );\n if (!allStepIds.includes(journey.initial)) {\n throw new Error(\n `Journey initial step \"${journey.initial}\" does not exist in linear transitions.`\n );\n }\n }\n\n let previousStep = initialStep as TStepId;\n const seenSteps = new Set<string>([initialStep]);\n for (const [offset, entry] of linearEntries.entries()) {\n const index = offset + 1;\n if (typeof entry === \"string\") {\n if (!(entry in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry}\".`);\n }\n\n if (seenSteps.has(entry)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry}\" at index ${index}.`\n );\n }\n seenSteps.add(entry);\n\n resolvedTransitions.push({\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry as TStepId;\n continue;\n }\n\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(\n `Journey linear transitions at index ${index} must be a step id string or step config object.`\n );\n }\n\n const allowedKeys = new Set([\n \"step\",\n \"label\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"timeoutMs\"\n ]);\n for (const key of Object.keys(entry)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey linear transition object at index ${index} contains unsupported field \"${key}\". Allowed fields are \"step\", \"label\", \"updateContext\", \"onEnter\", \"onLeave\", and \"timeoutMs\".`\n );\n }\n }\n\n if (typeof entry.step !== \"string\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define string \"step\".`\n );\n }\n\n if (!(entry.step in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry.step}\".`);\n }\n\n if (seenSteps.has(entry.step)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry.step}\" at index ${index}.`\n );\n }\n seenSteps.add(entry.step);\n\n if (entry.updateContext !== undefined && typeof entry.updateContext !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (entry.onEnter !== undefined && typeof entry.onEnter !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (entry.onLeave !== undefined && typeof entry.onLeave !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n validateFiniteTimeout(entry.timeoutMs, `Journey linear transition object at index ${index}`);\n\n resolvedTransitions.push({\n ...(entry.label !== undefined ? { label: entry.label } : {}),\n ...(entry.timeoutMs !== undefined ? { timeoutMs: entry.timeoutMs } : {}),\n ...(entry.updateContext !== undefined ? { updateContext: entry.updateContext } : {}),\n ...(entry.onEnter !== undefined ? { onEnter: entry.onEnter } : {}),\n ...(entry.onLeave !== undefined ? { onLeave: entry.onLeave } : {}),\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry.step as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry.step as TStepId;\n }\n\n return {\n ...journey,\n initial: resolvedInitial,\n transitions: buildResolvedTransitions(resolvedTransitions)\n };\n }\n\n if (!transitions || typeof transitions !== \"object\") {\n throw new Error(\"Journey transitions must be an array or an object map when provided.\");\n }\n\n const transitionGraph = transitions as JourneyTransitionGraph<\n TContext,\n TStepId,\n TEventMap,\n THandlers\n >;\n\n const orderedGraphEntries = [\n ...Object.entries(transitionGraph).filter(([fromKey]) => fromKey !== \"global\"),\n ...(transitionGraph.global ? ([[\"global\", transitionGraph.global]] as const) : [])\n ];\n\n for (const [fromKey, eventMap] of orderedGraphEntries) {\n if (fromKey !== \"global\" && !(fromKey in journey.steps)) {\n throw new Error(`Journey transitions reference unknown step \"${fromKey}\".`);\n }\n\n if (!eventMap || typeof eventMap !== \"object\" || Array.isArray(eventMap)) {\n throw new Error(`Journey transitions for \"${fromKey}\" must be an event map object.`);\n }\n\n for (const [event, rawEdges] of Object.entries(eventMap) as Array<\n [TEventType, (typeof eventMap)[TEventType] | true]\n >) {\n const isTerminal = event === \"completeJourney\" || event === \"terminateJourney\";\n const edges =\n isTerminal && (rawEdges === true || (Array.isArray(rawEdges) && rawEdges.length === 0))\n ? [{}]\n : rawEdges;\n\n if (!Array.isArray(edges)) {\n throw new Error(`Journey transitions for \"${fromKey}.${event}\" must be an array.`);\n }\n\n for (const [index, edge] of edges.entries()) {\n if (!edge || typeof edge !== \"object\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must be an object.`\n );\n }\n\n const allowedKeys = new Set(\n isTerminal\n ? [\"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n : [\"to\", \"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n );\n for (const key of Object.keys(edge)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (!isTerminal && typeof (edge as { to?: unknown }).to !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define string \"to\".`\n );\n }\n\n if ((edge as { when?: unknown }).when !== undefined && typeof edge.when !== \"function\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"when\" as a function when provided.`\n );\n }\n\n if (\n (edge as { updateContext?: unknown }).updateContext !== undefined &&\n typeof edge.updateContext !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onEnter?: unknown }).onEnter !== undefined &&\n typeof edge.onEnter !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onLeave?: unknown }).onLeave !== undefined &&\n typeof edge.onLeave !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onLeave\" as a function when provided.`\n );\n }\n\n if ((edge as { label?: unknown }).label !== undefined && typeof edge.label !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"label\" as a string when provided.`\n );\n }\n\n validateFiniteTimeout(\n (edge as { timeoutMs?: unknown }).timeoutMs,\n `Journey transition at \"${fromKey}.${event}[${index}]\"`\n );\n\n resolvedTransitions.push({\n ...edge,\n from: (fromKey === \"global\" ? \"*\" : fromKey) as TStepId | \"*\",\n event\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n }\n }\n }\n\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n};\n", "/* eslint-disable no-redeclare */\nimport { resolveTransitionTarget } from \"../../journey-machine/helpers\";\nimport { resolveJourneyDefinition } from \"../../journey-machine/resolve-journey-definition\";\n\nimport type {\n JourneyDefinition,\n JourneyDiagnosticsIssue,\n JourneyDiagnosticsOptions,\n JourneyDiagnosticsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyMode\n} from \"../../types\";\n\nconst buildShadowKey = (from: string, event: string) => `${from}\\u0000${event}`;\n\n/** Analyzes a journey definition for structural diagnostics such as dead ends and cycles. */\nexport function getJourneyDiagnostics<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyDiagnosticsOptions\n): JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>>;\nexport function getJourneyDiagnostics<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options: JourneyDiagnosticsOptions = {}\n): JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>> {\n type TEventType = JourneyFullEventType<TEventMap>;\n const resolvedJourney = resolveJourneyDefinition(journey);\n const mode: JourneyMode =\n journey.transitions === undefined\n ? \"headless\"\n : Array.isArray(journey.transitions)\n ? \"linear\"\n : \"graph\";\n const stepIds = Object.keys(resolvedJourney.steps) as TStepId[];\n const issues: JourneyDiagnosticsIssue<TStepId, TEventType>[] = [];\n const requireExplicitCompletion = options.requireExplicitCompletion ?? false;\n const graphChecksSkipped = mode === \"headless\";\n\n if (graphChecksSkipped) {\n return {\n issues,\n summary: {\n mode,\n stepCount: stepIds.length,\n reachableStepCount: stepIds.length > 0 ? 1 : 0,\n unreachableStepCount: 0,\n deadEndCount: 0,\n cycleCount: 0,\n shadowedTransitionCount: 0,\n graphChecksSkipped: true,\n terminalPathExists: false\n }\n };\n }\n\n const shadowedTransitionIndexes = new Set<number>();\n const unconditionalTransitionByKey = new Map<string, { transitionId: string | null }>();\n\n resolvedJourney.transitions.forEach((transition, index) => {\n const key = buildShadowKey(transition.from, transition.event);\n const blocker = unconditionalTransitionByKey.get(key);\n\n if (blocker) {\n shadowedTransitionIndexes.add(index);\n issues.push({\n code: \"shadowed-transition\",\n severity: \"warning\",\n from: transition.from,\n eventType: transition.event as TEventType,\n transitionId: transition.id,\n ...(transition.label !== undefined ? { label: transition.label } : {}),\n message:\n blocker.transitionId === null\n ? `Transition \"${transition.from}.${transition.event}\" is shadowed by an earlier unconditional transition.`\n : `Transition \"${transition.from}.${transition.event}\" is shadowed by unconditional transition \"${blocker.transitionId}\".`\n });\n return;\n }\n\n if (transition.when === undefined) {\n unconditionalTransitionByKey.set(key, {\n transitionId: transition.id ?? null\n });\n }\n });\n\n const activeTransitions = resolvedJourney.transitions.filter(\n (_, index) => !shadowedTransitionIndexes.has(index)\n );\n const isImplicitlyTerminalStep = (stepId: TStepId) =>\n mode === \"linear\" &&\n Array.isArray(journey.transitions) &&\n journey.transitions[journey.transitions.length - 1] !== undefined &&\n (typeof journey.transitions[journey.transitions.length - 1] === \"string\"\n ? journey.transitions[journey.transitions.length - 1]\n : journey.transitions[journey.transitions.length - 1].step) === stepId &&\n !requireExplicitCompletion;\n\n const getOutgoingTransitions = (stepId: TStepId) =>\n activeTransitions.filter((transition) => transition.from === \"*\" || transition.from === stepId);\n\n const reachable = new Set<TStepId>();\n const markReachable = (stepId: TStepId) => {\n if (reachable.has(stepId)) {\n return;\n }\n\n reachable.add(stepId);\n for (const transition of getOutgoingTransitions(stepId)) {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n continue;\n }\n markReachable(target);\n }\n };\n markReachable(resolvedJourney.initial);\n\n for (const stepId of stepIds) {\n if (reachable.has(stepId)) {\n continue;\n }\n\n issues.push({\n code: \"unreachable-step\",\n severity: \"warning\",\n stepId,\n message: `Step \"${stepId}\" is unreachable from the initial step \"${resolvedJourney.initial}\".`\n });\n }\n\n for (const stepId of reachable) {\n if (isImplicitlyTerminalStep(stepId)) {\n continue;\n }\n\n if (getOutgoingTransitions(stepId).length > 0) {\n continue;\n }\n\n issues.push({\n code: \"dead-end-step\",\n severity: \"error\",\n stepId,\n message: `Step \"${stepId}\" is reachable but has no outgoing transitions or terminal exit.`\n });\n }\n\n const cycleKeys = new Set<string>();\n const visitedForCycles = new Set<TStepId>();\n const stack: TStepId[] = [];\n\n const walkCycles = (stepId: TStepId) => {\n visitedForCycles.add(stepId);\n stack.push(stepId);\n\n for (const transition of getOutgoingTransitions(stepId)) {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n continue;\n }\n\n const stackIndex = stack.indexOf(target);\n if (stackIndex >= 0) {\n const cycleSteps = [...stack.slice(stackIndex), target];\n const cycleKey = cycleSteps.join(\"\\u0000\");\n if (!cycleKeys.has(cycleKey)) {\n cycleKeys.add(cycleKey);\n issues.push({\n code: \"cycle-detected\",\n severity: \"warning\",\n from: transition.from,\n eventType: transition.event as TEventType,\n transitionId: transition.id,\n ...(transition.label !== undefined ? { label: transition.label } : {}),\n steps: cycleSteps,\n message: `Cycle detected: ${cycleSteps.join(\" -> \")}.`\n });\n }\n continue;\n }\n\n if (!visitedForCycles.has(target)) {\n walkCycles(target);\n }\n }\n\n stack.pop();\n };\n\n walkCycles(resolvedJourney.initial);\n\n const terminalMemo = new Map<TStepId, boolean>();\n const canReachTerminal = (stepId: TStepId, pending = new Set<TStepId>()): boolean => {\n const memoized = terminalMemo.get(stepId);\n if (memoized !== undefined) {\n return memoized;\n }\n\n if (isImplicitlyTerminalStep(stepId)) {\n terminalMemo.set(stepId, true);\n return true;\n }\n\n if (pending.has(stepId)) {\n return false;\n }\n\n pending.add(stepId);\n const terminalReachable = getOutgoingTransitions(stepId).some((transition) => {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n return true;\n }\n return canReachTerminal(target, pending);\n });\n pending.delete(stepId);\n terminalMemo.set(stepId, terminalReachable);\n return terminalReachable;\n };\n\n const terminalPathExists = canReachTerminal(resolvedJourney.initial);\n if (!terminalPathExists) {\n issues.push({\n code: \"no-terminal-path\",\n severity: \"warning\",\n stepId: resolvedJourney.initial,\n message: `No terminal path is reachable from the initial step \"${resolvedJourney.initial}\".`\n });\n }\n\n return {\n issues,\n summary: {\n mode,\n stepCount: stepIds.length,\n reachableStepCount: reachable.size,\n unreachableStepCount: stepIds.length - reachable.size,\n deadEndCount: issues.filter((issue) => issue.code === \"dead-end-step\").length,\n cycleCount: issues.filter((issue) => issue.code === \"cycle-detected\").length,\n shadowedTransitionCount: issues.filter((issue) => issue.code === \"shadowed-transition\")\n .length,\n graphChecksSkipped: false,\n terminalPathExists\n }\n };\n}\n/* eslint-enable no-redeclare */\n"],
5
- "mappings": "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",
6
- "names": ["diagnostics_exports", "__export", "createDiagnosticsPlugin", "getJourneyDiagnostics", "__toCommonJS", "isFiniteNumber", "value", "validateFiniteTimeout", "timeoutMs", "label", "resolveTransitionTarget", "transition", "hashTransitionDescriptor", "value", "hash", "index", "buildResolvedTransitions", "transitions", "transitionRouteCounts", "usedIds", "transition", "target", "routeKey", "ordinal", "descriptor", "suffix", "id", "candidate", "resolveJourneyDefinition", "journey", "resolvedTransitions", "initialStep", "linearEntries", "resolvedInitial", "entry", "previousStep", "seenSteps", "offset", "allowedKeys", "key", "validateFiniteTimeout", "transitionGraph", "orderedGraphEntries", "fromKey", "eventMap", "event", "rawEdges", "isTerminal", "edges", "edge", "buildShadowKey", "from", "event", "getJourneyDiagnostics", "journey", "options", "resolvedJourney", "resolveJourneyDefinition", "mode", "stepIds", "issues", "requireExplicitCompletion", "shadowedTransitionIndexes", "unconditionalTransitionByKey", "transition", "index", "key", "blocker", "activeTransitions", "_", "isImplicitlyTerminalStep", "stepId", "getOutgoingTransitions", "reachable", "markReachable", "target", "resolveTransitionTarget", "cycleKeys", "visitedForCycles", "stack", "walkCycles", "stackIndex", "cycleSteps", "cycleKey", "terminalMemo", "canReachTerminal", "pending", "memoized", "terminalReachable", "terminalPathExists", "issue", "createDiagnosticsPlugin", "journey", "options", "diagnosticsOptions", "getJourneyDiagnostics"]
7
- }
@@ -1,15 +0,0 @@
1
- import type { JourneyDiagnosticsOptions, JourneyDiagnosticsResult, JourneyFullEventType, JourneyJsonObject, JourneyMachine } from "../../types";
2
- export type JourneyDiagnosticsMachineExtension<TStepId extends string, TEventType extends string> = {
3
- getDiagnostics: (options?: JourneyDiagnosticsOptions) => JourneyDiagnosticsResult<TStepId, TEventType>;
4
- };
5
- export type JourneyDiagnosticsMachine<TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> & JourneyDiagnosticsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;
6
- /** Creates a plugin that augments a machine with structural diagnostics helpers. */
7
- export declare const createDiagnosticsPlugin: () => {
8
- name: string;
9
- setup: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>>({ journey, options }: import("../../types").JourneyMachinePluginSetupContext<TContext, TStepId, TEventMap, TStepMeta, THandlers>) => {
10
- augmentMachine: () => {
11
- getDiagnostics: (diagnosticsOptions?: JourneyDiagnosticsOptions) => JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>>;
12
- };
13
- };
14
- };
15
- export { getJourneyDiagnostics } from "./diagnostics";
@@ -1,15 +0,0 @@
1
- import type { JourneyDiagnosticsOptions, JourneyDiagnosticsResult, JourneyFullEventType, JourneyJsonObject, JourneyMachine } from "../../types";
2
- export type JourneyDiagnosticsMachineExtension<TStepId extends string, TEventType extends string> = {
3
- getDiagnostics: (options?: JourneyDiagnosticsOptions) => JourneyDiagnosticsResult<TStepId, TEventType>;
4
- };
5
- export type JourneyDiagnosticsMachine<TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> & JourneyDiagnosticsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;
6
- /** Creates a plugin that augments a machine with structural diagnostics helpers. */
7
- export declare const createDiagnosticsPlugin: () => {
8
- name: string;
9
- setup: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>>({ journey, options }: import("../../types").JourneyMachinePluginSetupContext<TContext, TStepId, TEventMap, TStepMeta, THandlers>) => {
10
- augmentMachine: () => {
11
- getDiagnostics: (diagnosticsOptions?: JourneyDiagnosticsOptions) => JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>>;
12
- };
13
- };
14
- };
15
- export { getJourneyDiagnostics } from "./diagnostics";
@@ -1,2 +0,0 @@
1
- var D=t=>typeof t=="number"&&Number.isFinite(t),E=(t,s)=>{if(t!==void 0&&!D(t))throw new Error(`${s} must define a finite numeric "timeoutMs" when provided.`)};var J=t=>t.event==="completeJourney"?"COMPLETE":t.event==="terminateJourney"?"TERMINATED":t.to;var O=t=>{let s=2166136261;for(let i=0;i<t.length;i+=1)s^=t.charCodeAt(i),s=Math.imul(s,16777619);return(s>>>0).toString(16).padStart(8,"0")},v=t=>{let s=new Map,i=new Set;return t.map(d=>{let T=d.event==="completeJourney"?"COMPLETE":d.event==="terminateJourney"?"TERMINATED":String(d.to),o=JSON.stringify({from:d.from,event:d.event,target:T}),f=(s.get(o)??0)+1;s.set(o,f);let u=JSON.stringify({from:d.from,event:d.event,target:T,ordinal:f}),p=0,l=(()=>{let y=O(u);for(;i.has(y);)p+=1,y=O(`${u}:${p}`);return y})();return i.add(l),{...d,id:l,...d.label!==void 0?{label:d.label}:{}}})},A=t=>{let s=[],{transitions:i}=t;if(i===void 0)return{...t,transitions:v(s)};if(Array.isArray(i)){if(i.length===0)throw new Error("Journey linear transitions must include the initial step as the first item.");let[o,...f]=i;if(typeof o!="string")throw new Error("Journey linear transitions at index 0 must be a step id string.");if(!(o in t.steps))throw new Error(`Journey linear transitions reference unknown step "${o}".`);let u=t.initial??o;if(t.initial!==void 0&&!i.map(e=>typeof e=="string"?e:e.step).includes(t.initial))throw new Error(`Journey initial step "${t.initial}" does not exist in linear transitions.`);let p=o,l=new Set([o]);for(let[y,e]of f.entries()){let r=y+1;if(typeof e=="string"){if(!(e in t.steps))throw new Error(`Journey linear transitions reference unknown step "${e}".`);if(l.has(e))throw new Error(`Journey linear transitions contain duplicate step "${e}" at index ${r}.`);l.add(e),s.push({from:p,event:"goToNextStep",to:e}),p=e;continue}if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`Journey linear transitions at index ${r} must be a step id string or step config object.`);let w=new Set(["step","label","updateContext","onEnter","onLeave","timeoutMs"]);for(let x of Object.keys(e))if(!w.has(x))throw new Error(`Journey linear transition object at index ${r} contains unsupported field "${x}". Allowed fields are "step", "label", "updateContext", "onEnter", "onLeave", and "timeoutMs".`);if(typeof e.step!="string")throw new Error(`Journey linear transition object at index ${r} must define string "step".`);if(!(e.step in t.steps))throw new Error(`Journey linear transitions reference unknown step "${e.step}".`);if(l.has(e.step))throw new Error(`Journey linear transitions contain duplicate step "${e.step}" at index ${r}.`);if(l.add(e.step),e.updateContext!==void 0&&typeof e.updateContext!="function")throw new Error(`Journey linear transition object at index ${r} must define "updateContext" as a function when provided.`);if(e.onEnter!==void 0&&typeof e.onEnter!="function")throw new Error(`Journey linear transition object at index ${r} must define "onEnter" as a function when provided.`);if(e.onLeave!==void 0&&typeof e.onLeave!="function")throw new Error(`Journey linear transition object at index ${r} must define "onLeave" as a function when provided.`);E(e.timeoutMs,`Journey linear transition object at index ${r}`),s.push({...e.label!==void 0?{label:e.label}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},...e.updateContext!==void 0?{updateContext:e.updateContext}:{},...e.onEnter!==void 0?{onEnter:e.onEnter}:{},...e.onLeave!==void 0?{onLeave:e.onLeave}:{},from:p,event:"goToNextStep",to:e.step}),p=e.step}return{...t,initial:u,transitions:v(s)}}if(!i||typeof i!="object")throw new Error("Journey transitions must be an array or an object map when provided.");let d=i,T=[...Object.entries(d).filter(([o])=>o!=="global"),...d.global?[["global",d.global]]:[]];for(let[o,f]of T){if(o!=="global"&&!(o in t.steps))throw new Error(`Journey transitions reference unknown step "${o}".`);if(!f||typeof f!="object"||Array.isArray(f))throw new Error(`Journey transitions for "${o}" must be an event map object.`);for(let[u,p]of Object.entries(f)){let l=u==="completeJourney"||u==="terminateJourney",y=l&&(p===!0||Array.isArray(p)&&p.length===0)?[{}]:p;if(!Array.isArray(y))throw new Error(`Journey transitions for "${o}.${u}" must be an array.`);for(let[e,r]of y.entries()){if(!r||typeof r!="object")throw new Error(`Journey transition at "${o}.${u}[${e}]" must be an object.`);let w=new Set(l?["when","updateContext","onEnter","onLeave","label","timeoutMs"]:["to","when","updateContext","onEnter","onLeave","label","timeoutMs"]);for(let x of Object.keys(r))if(!w.has(x))throw new Error(`Journey transition at "${o}.${u}[${e}]" contains unsupported field "${x}".`);if(!l&&typeof r.to!="string")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define string "to".`);if(r.when!==void 0&&typeof r.when!="function")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define "when" as a function when provided.`);if(r.updateContext!==void 0&&typeof r.updateContext!="function")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define "updateContext" as a function when provided.`);if(r.onEnter!==void 0&&typeof r.onEnter!="function")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define "onEnter" as a function when provided.`);if(r.onLeave!==void 0&&typeof r.onLeave!="function")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define "onLeave" as a function when provided.`);if(r.label!==void 0&&typeof r.label!="string")throw new Error(`Journey transition at "${o}.${u}[${e}]" must define "label" as a string when provided.`);E(r.timeoutMs,`Journey transition at "${o}.${u}[${e}]"`),s.push({...r,from:o==="global"?"*":o,event:u})}}}return{...t,transitions:v(s)}};var j=(t,s)=>`${t}\0${s}`;function I(t,s={}){let i=A(t),d=t.transitions===void 0?"headless":Array.isArray(t.transitions)?"linear":"graph",T=Object.keys(i.steps),o=[],f=s.requireExplicitCompletion??!1;if(d==="headless")return{issues:o,summary:{mode:d,stepCount:T.length,reachableStepCount:T.length>0?1:0,unreachableStepCount:0,deadEndCount:0,cycleCount:0,shadowedTransitionCount:0,graphChecksSkipped:!0,terminalPathExists:!1}};let p=new Set,l=new Map;i.transitions.forEach((n,a)=>{let c=j(n.from,n.event),m=l.get(c);if(m){p.add(a),o.push({code:"shadowed-transition",severity:"warning",from:n.from,eventType:n.event,transitionId:n.id,...n.label!==void 0?{label:n.label}:{},message:m.transitionId===null?`Transition "${n.from}.${n.event}" is shadowed by an earlier unconditional transition.`:`Transition "${n.from}.${n.event}" is shadowed by unconditional transition "${m.transitionId}".`});return}n.when===void 0&&l.set(c,{transitionId:n.id??null})});let y=i.transitions.filter((n,a)=>!p.has(a)),e=n=>d==="linear"&&Array.isArray(t.transitions)&&t.transitions[t.transitions.length-1]!==void 0&&(typeof t.transitions[t.transitions.length-1]=="string"?t.transitions[t.transitions.length-1]:t.transitions[t.transitions.length-1].step)===n&&!f,r=n=>y.filter(a=>a.from==="*"||a.from===n),w=new Set,x=n=>{if(!w.has(n)){w.add(n);for(let a of r(n)){let c=J(a);c==="COMPLETE"||c==="TERMINATED"||x(c)}}};x(i.initial);for(let n of T)w.has(n)||o.push({code:"unreachable-step",severity:"warning",stepId:n,message:`Step "${n}" is unreachable from the initial step "${i.initial}".`});for(let n of w)e(n)||r(n).length>0||o.push({code:"dead-end-step",severity:"error",stepId:n,message:`Step "${n}" is reachable but has no outgoing transitions or terminal exit.`});let C=new Set,M=new Set,h=[],$=n=>{M.add(n),h.push(n);for(let a of r(n)){let c=J(a);if(c==="COMPLETE"||c==="TERMINATED")continue;let m=h.indexOf(c);if(m>=0){let b=[...h.slice(m),c],S=b.join("\0");C.has(S)||(C.add(S),o.push({code:"cycle-detected",severity:"warning",from:a.from,eventType:a.event,transitionId:a.id,...a.label!==void 0?{label:a.label}:{},steps:b,message:`Cycle detected: ${b.join(" -> ")}.`}));continue}M.has(c)||$(c)}h.pop()};$(i.initial);let g=new Map,k=(n,a=new Set)=>{let c=g.get(n);if(c!==void 0)return c;if(e(n))return g.set(n,!0),!0;if(a.has(n))return!1;a.add(n);let m=r(n).some(b=>{let S=J(b);return S==="COMPLETE"||S==="TERMINATED"?!0:k(S,a)});return a.delete(n),g.set(n,m),m},R=k(i.initial);return R||o.push({code:"no-terminal-path",severity:"warning",stepId:i.initial,message:`No terminal path is reachable from the initial step "${i.initial}".`}),{issues:o,summary:{mode:d,stepCount:T.length,reachableStepCount:w.size,unreachableStepCount:T.length-w.size,deadEndCount:o.filter(n=>n.code==="dead-end-step").length,cycleCount:o.filter(n=>n.code==="cycle-detected").length,shadowedTransitionCount:o.filter(n=>n.code==="shadowed-transition").length,graphChecksSkipped:!1,terminalPathExists:R}}}var F=()=>({name:"diagnostics",setup:({journey:t,options:s})=>({augmentMachine:()=>({getDiagnostics:i=>I(t,{requireExplicitCompletion:i?.requireExplicitCompletion??s.requireExplicitCompletion})})})});export{F as createDiagnosticsPlugin,I as getJourneyDiagnostics};
2
- //# sourceMappingURL=index.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/journey-machine/helpers.ts", "../../../src/journey-machine/resolve-journey-definition.ts", "../../../src/plugins/diagnostics/diagnostics.ts", "../../../src/plugins/diagnostics/index.ts"],
4
- "sourcesContent": ["import type {\n JourneyAsyncState,\n JourneyEvent,\n JourneyGoToEvent,\n JourneyJsonObject,\n JourneyJsonValue,\n JourneyPayloadFor,\n JourneyResolvedTransition,\n JourneySendEvent,\n JourneySendResult,\n JourneySnapshot,\n JourneyStatus,\n JourneyStepAsyncState,\n JourneyTerminal,\n JourneyTransition,\n JourneyTransitionArgs\n} from \"../types\";\n\nexport const assertStepExists = <TStepId extends string>(\n steps: Record<TStepId, unknown>,\n stepId: TStepId,\n message: string\n) => {\n if (!(stepId in steps)) {\n throw new Error(message);\n }\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n\nconst cloneSerializableValue = <T extends JourneyJsonValue>(value: T): T => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneSerializableValue(entry)) as T;\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneSerializableValue(entryValue as JourneyJsonValue)\n ])\n ) as T;\n }\n\n return value;\n};\n\ntype SerializableCheckState = {\n readonly seen: WeakSet<object>;\n};\n\nconst describeValue = (value: unknown): string => {\n if (value === null) {\n return \"null\";\n }\n\n if (Array.isArray(value)) {\n return \"array\";\n }\n\n if (typeof value === \"object\") {\n const constructorName = (value as { constructor?: { name?: string } }).constructor?.name;\n return constructorName && constructorName !== \"Object\" ? constructorName : \"object\";\n }\n\n return typeof value;\n};\n\nfunction assertSerializableValue(\n value: unknown,\n label: string,\n state: SerializableCheckState,\n path: readonly string[] = []\n): asserts value is JourneyJsonValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return;\n }\n\n const pathLabel = path.length === 0 ? label : `${label}.${path.join(\".\")}`;\n\n if (value === undefined) {\n throw new Error(`${pathLabel} must be JSON-serializable. Received undefined.`);\n }\n\n if (typeof value === \"bigint\" || typeof value === \"symbol\" || typeof value === \"function\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${typeof value}.`);\n }\n\n if (typeof value !== \"object\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${describeValue(value)}.`);\n }\n\n if (state.seen.has(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Circular references are not supported.`\n );\n }\n\n state.seen.add(value);\n\n if (Array.isArray(value)) {\n for (const [index, entryValue] of value.entries()) {\n assertSerializableValue(entryValue, label, state, [...path, String(index)]);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Received non-plain ${describeValue(value)}.`\n );\n }\n\n for (const [key, entryValue] of Object.entries(value)) {\n assertSerializableValue(entryValue, label, state, [...path, key]);\n }\n}\n\nexport function assertSerializableContext<TContext extends JourneyJsonObject>(\n context: TContext,\n label = \"Journey context\"\n): TContext {\n assertSerializableValue(context, label, { seen: new WeakSet() });\n return context;\n}\n\nexport const cloneContext = <TContext extends JourneyJsonObject>(context: TContext): TContext =>\n cloneSerializableValue(assertSerializableContext(context));\n\nconst cloneDefinitionValueFallback = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneDefinitionValueFallback(entry));\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime());\n }\n\n if (value instanceof Map) {\n return new Map(\n [...value.entries()].map(([key, entryValue]) => [\n cloneDefinitionValueFallback(key),\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n if (value instanceof Set) {\n return new Set([...value].map((entry) => cloneDefinitionValueFallback(entry)));\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n return value;\n};\n\nexport const cloneMetaValue = <T>(value: T): T => {\n if ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n return value;\n }\n\n if (typeof structuredClone === \"function\") {\n try {\n return structuredClone(value);\n } catch {\n return cloneDefinitionValueFallback(value) as T;\n }\n } else {\n return cloneDefinitionValueFallback(value) as T;\n }\n};\n\nconst freezeSnapshotValue = (value: unknown) => {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n freezeSnapshotValue(item);\n }\n Object.freeze(value);\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n for (const entryValue of Object.values(value)) {\n freezeSnapshotValue(entryValue);\n }\n Object.freeze(value);\n};\n\nexport const normalizeStepCount = (steps?: number): number => {\n if (typeof steps !== \"number\" || !Number.isFinite(steps)) {\n return 1;\n }\n return Math.max(1, Math.trunc(steps));\n};\n\nexport const now = (): number => Date.now();\n\nconst unique = <T>(items: readonly T[]): T[] => [...new Set(items)];\n\nconst normalizeVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n stepIds: readonly TStepId[]\n): Record<TStepId, boolean> =>\n Object.fromEntries(stepIds.map((stepId) => [stepId, visited[stepId] === true])) as Record<\n TStepId,\n boolean\n >;\n\nexport const buildVisitedFromTimeline = <TStepId extends string>(\n timeline: readonly TStepId[],\n stepIds?: readonly TStepId[]\n): Record<TStepId, boolean> => {\n const resolvedStepIds = stepIds ?? unique(timeline);\n const visited = Object.fromEntries(resolvedStepIds.map((stepId) => [stepId, false])) as Record<\n TStepId,\n boolean\n >;\n\n for (const stepId of timeline) {\n visited[stepId] = true;\n }\n\n return visited;\n};\n\nexport const appendVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n current: TStepId\n): Record<TStepId, boolean> => ({\n ...visited,\n [current]: true\n});\n\nexport const isPromiseLike = <T>(value: T | PromiseLike<T>): value is PromiseLike<T> =>\n typeof value === \"object\" &&\n value !== null &&\n \"then\" in value &&\n typeof (value as { then: unknown }).then === \"function\";\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value);\n\nexport const validateFiniteTimeout = (timeoutMs: unknown, label: string) => {\n if (timeoutMs !== undefined && !isFiniteNumber(timeoutMs)) {\n throw new Error(`${label} must define a finite numeric \"timeoutMs\" when provided.`);\n }\n};\n\nexport class JourneyTimeoutError extends Error {\n override name = \"JourneyTimeoutError\";\n\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class JourneyDisposedError extends Error {\n override name = \"JourneyDisposedError\";\n readonly operation: string;\n\n constructor(operation: string) {\n super(`Journey machine has been disposed; \"${operation}\" can no longer be used.`);\n this.operation = operation;\n }\n}\n\ntype DiagnosticGlobal = typeof globalThis & {\n __DEV__?: unknown;\n process?: {\n env?: {\n NODE_ENV?: string;\n };\n };\n};\n\nexport const isDevelopmentEnvironment = (): boolean => {\n const diagnosticGlobal = globalThis as DiagnosticGlobal;\n if (typeof diagnosticGlobal.__DEV__ === \"boolean\") {\n return diagnosticGlobal.__DEV__;\n }\n\n const nodeEnv = diagnosticGlobal.process?.env?.NODE_ENV;\n return nodeEnv === undefined || nodeEnv === \"development\";\n};\n\nexport const warnInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.warn(message);\n return;\n }\n\n console.warn(message, detail);\n};\n\nexport const errorInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.error(message);\n return;\n }\n\n console.error(message, detail);\n};\n\nexport const withTimeout = async <T>(\n promise: PromiseLike<T>,\n timeoutMs: number | undefined,\n buildError: () => Error\n): Promise<T> => {\n if (!isFiniteNumber(timeoutMs) || timeoutMs <= 0) {\n return await promise;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(buildError());\n }, timeoutMs);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n }\n );\n });\n};\n\nexport const withAbortSignal = async <T>(\n promise: PromiseLike<T>,\n signal: AbortSignal\n): Promise<T> => {\n if (signal.aborted) {\n throw signal.reason;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(signal.reason);\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n }\n );\n });\n};\n\nexport const buildIdleStepAsyncState = (): JourneyStepAsyncState => ({\n phase: \"idle\",\n eventType: null,\n transitionId: null,\n error: null\n});\n\nexport const buildInitialAsyncState = <TStepId extends string>(\n steps: Record<TStepId, unknown>\n): JourneyAsyncState<TStepId> => {\n const byStep = Object.fromEntries(\n Object.keys(steps).map((stepId) => [stepId, buildIdleStepAsyncState()])\n ) as Record<TStepId, JourneyStepAsyncState>;\n\n return {\n isLoading: false,\n byStep\n };\n};\n\nexport const isGoToStepByIdEvent = <\n TStepId extends string,\n TEventMap extends Record<string, unknown>\n>(\n event: JourneySendEvent<TStepId, TEventMap>\n): event is JourneyGoToEvent<TStepId, JourneyPayloadFor<TEventMap, \"goToStepById\">> =>\n event.type === \"goToStepById\" && \"stepId\" in event;\n\nexport const isTerminalTarget = <TStepId extends string>(\n target: TStepId | JourneyTerminal\n): target is JourneyTerminal => target === \"COMPLETE\" || target === \"TERMINATED\";\n\nexport const resolveTransitionTarget = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transition: JourneyTransition<TContext, TStepId, TEventMap, THandlers>\n): TStepId | JourneyTerminal =>\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : (transition.to as TStepId | JourneyTerminal);\n\nexport const validateJourneyTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[],\n steps: Record<TStepId, unknown>\n) => {\n const stepRegistry = steps as Record<string, unknown>;\n const allowedKeys = new Set([\n \"from\",\n \"event\",\n \"to\",\n \"when\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"id\",\n \"label\",\n \"timeoutMs\"\n ]);\n\n for (const [index, transition] of transitions.entries()) {\n if (!transition || typeof transition !== \"object\") {\n throw new Error(`Journey transition at index ${index} must be an object.`);\n }\n\n for (const key of Object.keys(transition)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at index ${index} contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (typeof transition.from !== \"string\" || typeof transition.event !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define string \"from\" and \"event\".`\n );\n }\n\n if (transition.from !== \"*\" && !(transition.from in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} references unknown from step \"${transition.from}\".`\n );\n }\n\n validateFiniteTimeout(transition.timeoutMs, `Journey transition at index ${index}`);\n\n if (transition.when !== undefined && typeof transition.when !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"when\" as a function when provided.`\n );\n }\n\n if (transition.updateContext !== undefined && typeof transition.updateContext !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (transition.onEnter !== undefined && typeof transition.onEnter !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (transition.onLeave !== undefined && typeof transition.onLeave !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n if (transition.id !== undefined && typeof transition.id !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"id\" as a string when provided.`\n );\n }\n\n if (transition.label !== undefined && typeof transition.label !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"label\" as a string when provided.`\n );\n }\n\n if (transition.event === \"completeJourney\" || transition.event === \"terminateJourney\") {\n if (\"to\" in transition && transition.to !== undefined) {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" cannot define \"to\".`\n );\n }\n continue;\n }\n\n if (typeof transition.to !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" must define string \"to\".`\n );\n }\n\n if (!isTerminalTarget(transition.to) && !(transition.to in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} points to unknown step \"${transition.to}\".`\n );\n }\n }\n};\n\nexport const buildSendResult = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n transitioned: boolean,\n options: {\n transitionId?: string;\n label?: string;\n error?: unknown;\n } = {}\n): JourneySendResult<TContext, TStepId> => ({\n transitioned,\n ...(options.transitionId !== undefined ? { transitionId: options.transitionId } : {}),\n ...(options.label !== undefined ? { label: options.label } : {}),\n ...(\"error\" in options ? { error: options.error } : {}),\n snapshot\n});\n\nexport const buildSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n timeline: readonly TStepId[],\n index: number,\n context: TContext,\n status: JourneyStatus,\n asyncState: JourneyAsyncState<TStepId>,\n visited?: Record<TStepId, boolean>\n): JourneySnapshot<TContext, TStepId> => {\n if (timeline.length === 0) {\n throw new Error(\"Journey timeline cannot be empty.\");\n }\n\n const safeIndex = Math.max(0, Math.min(Math.trunc(index), timeline.length - 1));\n const currentStepId = timeline[safeIndex] as TStepId;\n const stepIds = unique(\n visited ? ([...(Object.keys(visited) as TStepId[]), ...timeline] as const) : timeline\n );\n\n return {\n status,\n currentStepId,\n history: {\n timeline: [...timeline],\n index: safeIndex\n },\n context: cloneContext(context),\n visited: visited\n ? normalizeVisited(visited, stepIds)\n : buildVisitedFromTimeline(timeline, stepIds),\n async: cloneSerializableValue(\n asyncState as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n};\n\nexport const stabilizeSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>\n): JourneySnapshot<TContext, TStepId> => {\n const stableSnapshot: JourneySnapshot<TContext, TStepId> = {\n ...snapshot,\n history: {\n timeline: [...snapshot.history.timeline],\n index: snapshot.history.index\n },\n context: cloneContext(snapshot.context),\n visited: { ...snapshot.visited },\n async: cloneSerializableValue(\n snapshot.async as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n\n freezeSnapshotValue(stableSnapshot);\n return stableSnapshot;\n};\n\nexport const selectTransition = async <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>,\n TTransition extends {\n from: TStepId | \"*\";\n event: string;\n when?: (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>;\n timeoutMs?: number;\n id?: string;\n label?: string;\n }\n>(\n transitions: readonly TTransition[],\n snapshot: JourneySnapshot<TContext, TStepId>,\n event: JourneyEvent<TStepId, TEventMap>,\n signal: AbortSignal,\n handlers: THandlers,\n hooks?: {\n onAsyncGuardStart?: (transition: TTransition) => void;\n onAsyncGuardSuccess?: (transition: TTransition) => void;\n onAsyncGuardError?: (transition: TTransition, error: unknown) => void;\n },\n defaultTimeoutMs?: number\n): Promise<TTransition | null> => {\n for (const transition of transitions) {\n const fromMatches = transition.from === \"*\" || transition.from === snapshot.currentStepId;\n const eventMatches = transition.event === event.type;\n\n if (!fromMatches || !eventMatches) {\n continue;\n }\n\n if (!transition.when) {\n return transition;\n }\n\n let guardResult: boolean | Promise<boolean>;\n if (signal.aborted) {\n throw signal.reason;\n }\n\n guardResult = (\n transition.when as (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>\n )({\n snapshot,\n context: snapshot.context,\n from: snapshot.currentStepId,\n timeline: snapshot.history.timeline,\n index: snapshot.history.index,\n event,\n signal,\n handlers\n });\n\n const asyncGuard = isPromiseLike(guardResult);\n const asyncGuardPromise = asyncGuard ? (guardResult as PromiseLike<boolean>) : null;\n\n let allowed: boolean;\n try {\n if (asyncGuard) {\n hooks?.onAsyncGuardStart?.(transition);\n allowed = await withTimeout(\n withAbortSignal(asyncGuardPromise as PromiseLike<boolean>, signal),\n transition.timeoutMs ?? defaultTimeoutMs,\n () =>\n new JourneyTimeoutError(\n `Transition guard timed out after ${transition.timeoutMs ?? defaultTimeoutMs}ms (event: ${event.type}, transition: ${transition.id ?? \"<anonymous>\"}).`\n )\n );\n } else {\n allowed = guardResult as boolean;\n }\n } catch (error) {\n if (asyncGuard) {\n hooks?.onAsyncGuardError?.(transition, error);\n }\n throw error;\n }\n\n if (asyncGuard) {\n hooks?.onAsyncGuardSuccess?.(transition);\n }\n\n if (allowed) {\n return transition;\n }\n }\n\n return null;\n};\n\nexport const transitionSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n nextCurrent: TStepId,\n nextContext: TContext\n): JourneySnapshot<TContext, TStepId> => {\n const baseTimeline = snapshot.history.timeline.slice(0, snapshot.history.index + 1);\n let nextTimeline = baseTimeline;\n if (nextCurrent !== snapshot.currentStepId) {\n nextTimeline = [...baseTimeline, nextCurrent];\n }\n\n const nextIndex = nextTimeline.length - 1;\n const visited = appendVisited(snapshot.visited, nextCurrent);\n\n return buildSnapshot(\n nextTimeline,\n nextIndex,\n nextContext,\n snapshot.status,\n snapshot.async,\n visited\n );\n};\n", "import { validateFiniteTimeout } from \"./helpers\";\n\nimport type {\n JourneyDefinition,\n JourneyJsonObject,\n JourneyResolvedDefinition,\n JourneyResolvedTransition,\n JourneyTransition,\n JourneyTransitionGraph\n} from \"../types\";\n\nconst hashTransitionDescriptor = (value: string) => {\n let hash = 2166136261;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n};\n\nconst buildResolvedTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyTransition<TContext, TStepId, TEventMap, THandlers>[]\n): JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[] => {\n const transitionRouteCounts = new Map<string, number>();\n const usedIds = new Set<string>();\n\n return transitions.map((transition) => {\n const target =\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : String(transition.to);\n const routeKey = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target\n });\n const ordinal = (transitionRouteCounts.get(routeKey) ?? 0) + 1;\n transitionRouteCounts.set(routeKey, ordinal);\n\n const descriptor = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target,\n ordinal\n });\n\n let suffix = 0;\n const id = (() => {\n let candidate = hashTransitionDescriptor(descriptor);\n while (usedIds.has(candidate)) {\n suffix += 1;\n candidate = hashTransitionDescriptor(`${descriptor}:${suffix}`);\n }\n return candidate;\n })();\n usedIds.add(id);\n\n return {\n ...transition,\n id,\n ...(transition.label !== undefined ? { label: transition.label } : {})\n } as JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>;\n });\n};\n\nexport const resolveJourneyDefinition = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>\n): JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers> => {\n type TEventType = string;\n const resolvedTransitions: JourneyTransition<TContext, TStepId, TEventMap, THandlers>[] = [];\n const { transitions } = journey;\n\n if (transitions === undefined) {\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n }\n\n if (Array.isArray(transitions)) {\n if (transitions.length === 0) {\n throw new Error(\n \"Journey linear transitions must include the initial step as the first item.\"\n );\n }\n\n const [initialStep, ...linearEntries] = transitions;\n if (typeof initialStep !== \"string\") {\n throw new Error(\"Journey linear transitions at index 0 must be a step id string.\");\n }\n\n if (!(initialStep in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${initialStep}\".`);\n }\n\n // Resolve initial: use journey.initial if provided (start from middle), otherwise array[0]\n const resolvedInitial = (journey.initial ?? initialStep) as TStepId;\n\n if (journey.initial !== undefined) {\n const allStepIds = transitions.map((entry) =>\n typeof entry === \"string\" ? entry : entry.step\n );\n if (!allStepIds.includes(journey.initial)) {\n throw new Error(\n `Journey initial step \"${journey.initial}\" does not exist in linear transitions.`\n );\n }\n }\n\n let previousStep = initialStep as TStepId;\n const seenSteps = new Set<string>([initialStep]);\n for (const [offset, entry] of linearEntries.entries()) {\n const index = offset + 1;\n if (typeof entry === \"string\") {\n if (!(entry in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry}\".`);\n }\n\n if (seenSteps.has(entry)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry}\" at index ${index}.`\n );\n }\n seenSteps.add(entry);\n\n resolvedTransitions.push({\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry as TStepId;\n continue;\n }\n\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(\n `Journey linear transitions at index ${index} must be a step id string or step config object.`\n );\n }\n\n const allowedKeys = new Set([\n \"step\",\n \"label\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"timeoutMs\"\n ]);\n for (const key of Object.keys(entry)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey linear transition object at index ${index} contains unsupported field \"${key}\". Allowed fields are \"step\", \"label\", \"updateContext\", \"onEnter\", \"onLeave\", and \"timeoutMs\".`\n );\n }\n }\n\n if (typeof entry.step !== \"string\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define string \"step\".`\n );\n }\n\n if (!(entry.step in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry.step}\".`);\n }\n\n if (seenSteps.has(entry.step)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry.step}\" at index ${index}.`\n );\n }\n seenSteps.add(entry.step);\n\n if (entry.updateContext !== undefined && typeof entry.updateContext !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (entry.onEnter !== undefined && typeof entry.onEnter !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (entry.onLeave !== undefined && typeof entry.onLeave !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n validateFiniteTimeout(entry.timeoutMs, `Journey linear transition object at index ${index}`);\n\n resolvedTransitions.push({\n ...(entry.label !== undefined ? { label: entry.label } : {}),\n ...(entry.timeoutMs !== undefined ? { timeoutMs: entry.timeoutMs } : {}),\n ...(entry.updateContext !== undefined ? { updateContext: entry.updateContext } : {}),\n ...(entry.onEnter !== undefined ? { onEnter: entry.onEnter } : {}),\n ...(entry.onLeave !== undefined ? { onLeave: entry.onLeave } : {}),\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry.step as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry.step as TStepId;\n }\n\n return {\n ...journey,\n initial: resolvedInitial,\n transitions: buildResolvedTransitions(resolvedTransitions)\n };\n }\n\n if (!transitions || typeof transitions !== \"object\") {\n throw new Error(\"Journey transitions must be an array or an object map when provided.\");\n }\n\n const transitionGraph = transitions as JourneyTransitionGraph<\n TContext,\n TStepId,\n TEventMap,\n THandlers\n >;\n\n const orderedGraphEntries = [\n ...Object.entries(transitionGraph).filter(([fromKey]) => fromKey !== \"global\"),\n ...(transitionGraph.global ? ([[\"global\", transitionGraph.global]] as const) : [])\n ];\n\n for (const [fromKey, eventMap] of orderedGraphEntries) {\n if (fromKey !== \"global\" && !(fromKey in journey.steps)) {\n throw new Error(`Journey transitions reference unknown step \"${fromKey}\".`);\n }\n\n if (!eventMap || typeof eventMap !== \"object\" || Array.isArray(eventMap)) {\n throw new Error(`Journey transitions for \"${fromKey}\" must be an event map object.`);\n }\n\n for (const [event, rawEdges] of Object.entries(eventMap) as Array<\n [TEventType, (typeof eventMap)[TEventType] | true]\n >) {\n const isTerminal = event === \"completeJourney\" || event === \"terminateJourney\";\n const edges =\n isTerminal && (rawEdges === true || (Array.isArray(rawEdges) && rawEdges.length === 0))\n ? [{}]\n : rawEdges;\n\n if (!Array.isArray(edges)) {\n throw new Error(`Journey transitions for \"${fromKey}.${event}\" must be an array.`);\n }\n\n for (const [index, edge] of edges.entries()) {\n if (!edge || typeof edge !== \"object\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must be an object.`\n );\n }\n\n const allowedKeys = new Set(\n isTerminal\n ? [\"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n : [\"to\", \"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n );\n for (const key of Object.keys(edge)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (!isTerminal && typeof (edge as { to?: unknown }).to !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define string \"to\".`\n );\n }\n\n if ((edge as { when?: unknown }).when !== undefined && typeof edge.when !== \"function\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"when\" as a function when provided.`\n );\n }\n\n if (\n (edge as { updateContext?: unknown }).updateContext !== undefined &&\n typeof edge.updateContext !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onEnter?: unknown }).onEnter !== undefined &&\n typeof edge.onEnter !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onLeave?: unknown }).onLeave !== undefined &&\n typeof edge.onLeave !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onLeave\" as a function when provided.`\n );\n }\n\n if ((edge as { label?: unknown }).label !== undefined && typeof edge.label !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"label\" as a string when provided.`\n );\n }\n\n validateFiniteTimeout(\n (edge as { timeoutMs?: unknown }).timeoutMs,\n `Journey transition at \"${fromKey}.${event}[${index}]\"`\n );\n\n resolvedTransitions.push({\n ...edge,\n from: (fromKey === \"global\" ? \"*\" : fromKey) as TStepId | \"*\",\n event\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n }\n }\n }\n\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n};\n", "/* eslint-disable no-redeclare */\nimport { resolveTransitionTarget } from \"../../journey-machine/helpers\";\nimport { resolveJourneyDefinition } from \"../../journey-machine/resolve-journey-definition\";\n\nimport type {\n JourneyDefinition,\n JourneyDiagnosticsIssue,\n JourneyDiagnosticsOptions,\n JourneyDiagnosticsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyMode\n} from \"../../types\";\n\nconst buildShadowKey = (from: string, event: string) => `${from}\\u0000${event}`;\n\n/** Analyzes a journey definition for structural diagnostics such as dead ends and cycles. */\nexport function getJourneyDiagnostics<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyDiagnosticsOptions\n): JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>>;\nexport function getJourneyDiagnostics<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options: JourneyDiagnosticsOptions = {}\n): JourneyDiagnosticsResult<TStepId, JourneyFullEventType<TEventMap>> {\n type TEventType = JourneyFullEventType<TEventMap>;\n const resolvedJourney = resolveJourneyDefinition(journey);\n const mode: JourneyMode =\n journey.transitions === undefined\n ? \"headless\"\n : Array.isArray(journey.transitions)\n ? \"linear\"\n : \"graph\";\n const stepIds = Object.keys(resolvedJourney.steps) as TStepId[];\n const issues: JourneyDiagnosticsIssue<TStepId, TEventType>[] = [];\n const requireExplicitCompletion = options.requireExplicitCompletion ?? false;\n const graphChecksSkipped = mode === \"headless\";\n\n if (graphChecksSkipped) {\n return {\n issues,\n summary: {\n mode,\n stepCount: stepIds.length,\n reachableStepCount: stepIds.length > 0 ? 1 : 0,\n unreachableStepCount: 0,\n deadEndCount: 0,\n cycleCount: 0,\n shadowedTransitionCount: 0,\n graphChecksSkipped: true,\n terminalPathExists: false\n }\n };\n }\n\n const shadowedTransitionIndexes = new Set<number>();\n const unconditionalTransitionByKey = new Map<string, { transitionId: string | null }>();\n\n resolvedJourney.transitions.forEach((transition, index) => {\n const key = buildShadowKey(transition.from, transition.event);\n const blocker = unconditionalTransitionByKey.get(key);\n\n if (blocker) {\n shadowedTransitionIndexes.add(index);\n issues.push({\n code: \"shadowed-transition\",\n severity: \"warning\",\n from: transition.from,\n eventType: transition.event as TEventType,\n transitionId: transition.id,\n ...(transition.label !== undefined ? { label: transition.label } : {}),\n message:\n blocker.transitionId === null\n ? `Transition \"${transition.from}.${transition.event}\" is shadowed by an earlier unconditional transition.`\n : `Transition \"${transition.from}.${transition.event}\" is shadowed by unconditional transition \"${blocker.transitionId}\".`\n });\n return;\n }\n\n if (transition.when === undefined) {\n unconditionalTransitionByKey.set(key, {\n transitionId: transition.id ?? null\n });\n }\n });\n\n const activeTransitions = resolvedJourney.transitions.filter(\n (_, index) => !shadowedTransitionIndexes.has(index)\n );\n const isImplicitlyTerminalStep = (stepId: TStepId) =>\n mode === \"linear\" &&\n Array.isArray(journey.transitions) &&\n journey.transitions[journey.transitions.length - 1] !== undefined &&\n (typeof journey.transitions[journey.transitions.length - 1] === \"string\"\n ? journey.transitions[journey.transitions.length - 1]\n : journey.transitions[journey.transitions.length - 1].step) === stepId &&\n !requireExplicitCompletion;\n\n const getOutgoingTransitions = (stepId: TStepId) =>\n activeTransitions.filter((transition) => transition.from === \"*\" || transition.from === stepId);\n\n const reachable = new Set<TStepId>();\n const markReachable = (stepId: TStepId) => {\n if (reachable.has(stepId)) {\n return;\n }\n\n reachable.add(stepId);\n for (const transition of getOutgoingTransitions(stepId)) {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n continue;\n }\n markReachable(target);\n }\n };\n markReachable(resolvedJourney.initial);\n\n for (const stepId of stepIds) {\n if (reachable.has(stepId)) {\n continue;\n }\n\n issues.push({\n code: \"unreachable-step\",\n severity: \"warning\",\n stepId,\n message: `Step \"${stepId}\" is unreachable from the initial step \"${resolvedJourney.initial}\".`\n });\n }\n\n for (const stepId of reachable) {\n if (isImplicitlyTerminalStep(stepId)) {\n continue;\n }\n\n if (getOutgoingTransitions(stepId).length > 0) {\n continue;\n }\n\n issues.push({\n code: \"dead-end-step\",\n severity: \"error\",\n stepId,\n message: `Step \"${stepId}\" is reachable but has no outgoing transitions or terminal exit.`\n });\n }\n\n const cycleKeys = new Set<string>();\n const visitedForCycles = new Set<TStepId>();\n const stack: TStepId[] = [];\n\n const walkCycles = (stepId: TStepId) => {\n visitedForCycles.add(stepId);\n stack.push(stepId);\n\n for (const transition of getOutgoingTransitions(stepId)) {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n continue;\n }\n\n const stackIndex = stack.indexOf(target);\n if (stackIndex >= 0) {\n const cycleSteps = [...stack.slice(stackIndex), target];\n const cycleKey = cycleSteps.join(\"\\u0000\");\n if (!cycleKeys.has(cycleKey)) {\n cycleKeys.add(cycleKey);\n issues.push({\n code: \"cycle-detected\",\n severity: \"warning\",\n from: transition.from,\n eventType: transition.event as TEventType,\n transitionId: transition.id,\n ...(transition.label !== undefined ? { label: transition.label } : {}),\n steps: cycleSteps,\n message: `Cycle detected: ${cycleSteps.join(\" -> \")}.`\n });\n }\n continue;\n }\n\n if (!visitedForCycles.has(target)) {\n walkCycles(target);\n }\n }\n\n stack.pop();\n };\n\n walkCycles(resolvedJourney.initial);\n\n const terminalMemo = new Map<TStepId, boolean>();\n const canReachTerminal = (stepId: TStepId, pending = new Set<TStepId>()): boolean => {\n const memoized = terminalMemo.get(stepId);\n if (memoized !== undefined) {\n return memoized;\n }\n\n if (isImplicitlyTerminalStep(stepId)) {\n terminalMemo.set(stepId, true);\n return true;\n }\n\n if (pending.has(stepId)) {\n return false;\n }\n\n pending.add(stepId);\n const terminalReachable = getOutgoingTransitions(stepId).some((transition) => {\n const target = resolveTransitionTarget(transition);\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n return true;\n }\n return canReachTerminal(target, pending);\n });\n pending.delete(stepId);\n terminalMemo.set(stepId, terminalReachable);\n return terminalReachable;\n };\n\n const terminalPathExists = canReachTerminal(resolvedJourney.initial);\n if (!terminalPathExists) {\n issues.push({\n code: \"no-terminal-path\",\n severity: \"warning\",\n stepId: resolvedJourney.initial,\n message: `No terminal path is reachable from the initial step \"${resolvedJourney.initial}\".`\n });\n }\n\n return {\n issues,\n summary: {\n mode,\n stepCount: stepIds.length,\n reachableStepCount: reachable.size,\n unreachableStepCount: stepIds.length - reachable.size,\n deadEndCount: issues.filter((issue) => issue.code === \"dead-end-step\").length,\n cycleCount: issues.filter((issue) => issue.code === \"cycle-detected\").length,\n shadowedTransitionCount: issues.filter((issue) => issue.code === \"shadowed-transition\")\n .length,\n graphChecksSkipped: false,\n terminalPathExists\n }\n };\n}\n/* eslint-enable no-redeclare */\n", "import { getJourneyDiagnostics } from \"./diagnostics\";\n\nimport type {\n JourneyDiagnosticsOptions,\n JourneyDiagnosticsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyMachine,\n JourneyMachinePlugin\n} from \"../../types\";\n\nexport type JourneyDiagnosticsMachineExtension<\n TStepId extends string,\n TEventType extends string\n> = {\n getDiagnostics: (\n options?: JourneyDiagnosticsOptions\n ) => JourneyDiagnosticsResult<TStepId, TEventType>;\n};\n\nexport type JourneyDiagnosticsMachine<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> &\n JourneyDiagnosticsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;\n\n/** Creates a plugin that augments a machine with structural diagnostics helpers. */\nexport const createDiagnosticsPlugin = () =>\n ({\n name: \"diagnostics\",\n setup: ({ journey, options }) => ({\n augmentMachine: () => ({\n getDiagnostics: (diagnosticsOptions?: JourneyDiagnosticsOptions) =>\n getJourneyDiagnostics(journey, {\n requireExplicitCompletion:\n diagnosticsOptions?.requireExplicitCompletion ?? options.requireExplicitCompletion\n })\n })\n })\n }) satisfies JourneyMachinePlugin;\n\nexport { getJourneyDiagnostics } from \"./diagnostics\";\n"],
5
- "mappings": "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",
6
- "names": ["isFiniteNumber", "value", "validateFiniteTimeout", "timeoutMs", "label", "resolveTransitionTarget", "transition", "hashTransitionDescriptor", "value", "hash", "index", "buildResolvedTransitions", "transitions", "transitionRouteCounts", "usedIds", "transition", "target", "routeKey", "ordinal", "descriptor", "suffix", "id", "candidate", "resolveJourneyDefinition", "journey", "resolvedTransitions", "initialStep", "linearEntries", "resolvedInitial", "entry", "previousStep", "seenSteps", "offset", "allowedKeys", "key", "validateFiniteTimeout", "transitionGraph", "orderedGraphEntries", "fromKey", "eventMap", "event", "rawEdges", "isTerminal", "edges", "edge", "buildShadowKey", "from", "event", "getJourneyDiagnostics", "journey", "options", "resolvedJourney", "resolveJourneyDefinition", "mode", "stepIds", "issues", "requireExplicitCompletion", "shadowedTransitionIndexes", "unconditionalTransitionByKey", "transition", "index", "key", "blocker", "activeTransitions", "_", "isImplicitlyTerminalStep", "stepId", "getOutgoingTransitions", "reachable", "markReachable", "target", "resolveTransitionTarget", "cycleKeys", "visitedForCycles", "stack", "walkCycles", "stackIndex", "cycleSteps", "cycleKey", "terminalMemo", "canReachTerminal", "pending", "memoized", "terminalReachable", "terminalPathExists", "issue", "createDiagnosticsPlugin", "journey", "options", "diagnosticsOptions", "getJourneyDiagnostics"]
7
- }
@@ -1,2 +0,0 @@
1
- "use strict";var E=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var k=(n,t)=>{for(var s in t)E(n,s,{get:t[s],enumerable:!0})},R=(n,t,s,a)=>{if(t&&typeof t=="object"||typeof t=="function")for(let c of $(t))!C.call(n,c)&&c!==s&&E(n,c,{get:()=>t[c],enumerable:!(a=M(t,c))||a.enumerable});return n};var O=n=>R(E({},"__esModule",{value:!0}),n);var A={};k(A,{createExecutionPathsPlugin:()=>j,getExecutionPaths:()=>w});module.exports=O(A);var P=n=>typeof n=="number"&&Number.isFinite(n),S=(n,t)=>{if(n!==void 0&&!P(n))throw new Error(`${t} must define a finite numeric "timeoutMs" when provided.`)};var b=n=>n.event==="completeJourney"?"COMPLETE":n.event==="terminateJourney"?"TERMINATED":n.to;var g=n=>{let t=2166136261;for(let s=0;s<n.length;s+=1)t^=n.charCodeAt(s),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")},m=n=>{let t=new Map,s=new Set;return n.map(a=>{let c=a.event==="completeJourney"?"COMPLETE":a.event==="terminateJourney"?"TERMINATED":String(a.to),o=JSON.stringify({from:a.from,event:a.event,target:c}),u=(t.get(o)??0)+1;t.set(o,u);let i=JSON.stringify({from:a.from,event:a.event,target:c,ordinal:u}),p=0,d=(()=>{let T=g(i);for(;s.has(T);)p+=1,T=g(`${i}:${p}`);return T})();return s.add(d),{...a,id:d,...a.label!==void 0?{label:a.label}:{}}})},v=n=>{let t=[],{transitions:s}=n;if(s===void 0)return{...n,transitions:m(t)};if(Array.isArray(s)){if(s.length===0)throw new Error("Journey linear transitions must include the initial step as the first item.");let[o,...u]=s;if(typeof o!="string")throw new Error("Journey linear transitions at index 0 must be a step id string.");if(!(o in n.steps))throw new Error(`Journey linear transitions reference unknown step "${o}".`);let i=n.initial??o;if(n.initial!==void 0&&!s.map(e=>typeof e=="string"?e:e.step).includes(n.initial))throw new Error(`Journey initial step "${n.initial}" does not exist in linear transitions.`);let p=o,d=new Set([o]);for(let[T,e]of u.entries()){let r=T+1;if(typeof e=="string"){if(!(e in n.steps))throw new Error(`Journey linear transitions reference unknown step "${e}".`);if(d.has(e))throw new Error(`Journey linear transitions contain duplicate step "${e}" at index ${r}.`);d.add(e),t.push({from:p,event:"goToNextStep",to:e}),p=e;continue}if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`Journey linear transitions at index ${r} must be a step id string or step config object.`);let y=new Set(["step","label","updateContext","onEnter","onLeave","timeoutMs"]);for(let f of Object.keys(e))if(!y.has(f))throw new Error(`Journey linear transition object at index ${r} contains unsupported field "${f}". Allowed fields are "step", "label", "updateContext", "onEnter", "onLeave", and "timeoutMs".`);if(typeof e.step!="string")throw new Error(`Journey linear transition object at index ${r} must define string "step".`);if(!(e.step in n.steps))throw new Error(`Journey linear transitions reference unknown step "${e.step}".`);if(d.has(e.step))throw new Error(`Journey linear transitions contain duplicate step "${e.step}" at index ${r}.`);if(d.add(e.step),e.updateContext!==void 0&&typeof e.updateContext!="function")throw new Error(`Journey linear transition object at index ${r} must define "updateContext" as a function when provided.`);if(e.onEnter!==void 0&&typeof e.onEnter!="function")throw new Error(`Journey linear transition object at index ${r} must define "onEnter" as a function when provided.`);if(e.onLeave!==void 0&&typeof e.onLeave!="function")throw new Error(`Journey linear transition object at index ${r} must define "onLeave" as a function when provided.`);S(e.timeoutMs,`Journey linear transition object at index ${r}`),t.push({...e.label!==void 0?{label:e.label}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},...e.updateContext!==void 0?{updateContext:e.updateContext}:{},...e.onEnter!==void 0?{onEnter:e.onEnter}:{},...e.onLeave!==void 0?{onLeave:e.onLeave}:{},from:p,event:"goToNextStep",to:e.step}),p=e.step}return{...n,initial:i,transitions:m(t)}}if(!s||typeof s!="object")throw new Error("Journey transitions must be an array or an object map when provided.");let a=s,c=[...Object.entries(a).filter(([o])=>o!=="global"),...a.global?[["global",a.global]]:[]];for(let[o,u]of c){if(o!=="global"&&!(o in n.steps))throw new Error(`Journey transitions reference unknown step "${o}".`);if(!u||typeof u!="object"||Array.isArray(u))throw new Error(`Journey transitions for "${o}" must be an event map object.`);for(let[i,p]of Object.entries(u)){let d=i==="completeJourney"||i==="terminateJourney",T=d&&(p===!0||Array.isArray(p)&&p.length===0)?[{}]:p;if(!Array.isArray(T))throw new Error(`Journey transitions for "${o}.${i}" must be an array.`);for(let[e,r]of T.entries()){if(!r||typeof r!="object")throw new Error(`Journey transition at "${o}.${i}[${e}]" must be an object.`);let y=new Set(d?["when","updateContext","onEnter","onLeave","label","timeoutMs"]:["to","when","updateContext","onEnter","onLeave","label","timeoutMs"]);for(let f of Object.keys(r))if(!y.has(f))throw new Error(`Journey transition at "${o}.${i}[${e}]" contains unsupported field "${f}".`);if(!d&&typeof r.to!="string")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define string "to".`);if(r.when!==void 0&&typeof r.when!="function")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define "when" as a function when provided.`);if(r.updateContext!==void 0&&typeof r.updateContext!="function")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define "updateContext" as a function when provided.`);if(r.onEnter!==void 0&&typeof r.onEnter!="function")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define "onEnter" as a function when provided.`);if(r.onLeave!==void 0&&typeof r.onLeave!="function")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define "onLeave" as a function when provided.`);if(r.label!==void 0&&typeof r.label!="string")throw new Error(`Journey transition at "${o}.${i}[${e}]" must define "label" as a string when provided.`);S(r.timeoutMs,`Journey transition at "${o}.${i}[${e}]"`),t.push({...r,from:o==="global"?"*":o,event:i})}}}return{...n,transitions:m(t)}};var I=(n,t)=>typeof n!="number"||!Number.isFinite(n)?t:Math.max(1,Math.trunc(n));function w(n,t={}){let a=(e=>Array.isArray(e.transitions)&&(e.transitions.length===0||typeof e.transitions[0]=="object"&&e.transitions[0]!==null))(n)?n:v(n),c=I(t.maxDepth,5),o=I(t.maxPaths,10),u=[],i=!1,p=!1,d=e=>{if(u.length>=o){i=!0;return}u.push(e)},T=(e,r,y)=>{if(u.length>=o){i=!0;return}let f=a.transitions.filter(l=>l.from==="*"||l.from===e);if(f.length===0){d({steps:r,events:y,terminated:"final"});return}if(y.length>=c){d({steps:r,events:y,terminated:"depth"}),i=!0;return}for(let l of f){let J=[...y,l.event],x=b(l);if(x==="COMPLETE"||x==="TERMINATED"){d({steps:r,events:J,terminated:"final"});continue}let h=[...r,x];if(r.includes(x)){p=!0,d({steps:h,events:J,terminated:"cycle"});continue}if(T(x,h,J),u.length>=o){i=!0;return}}};return T(a.initial,[a.initial],[]),{paths:u,truncated:i,cyclesDetected:p}}var j=()=>({name:"execution-paths",setup:({resolvedJourney:n})=>({augmentMachine:()=>({getExecutionPaths:t=>w(n,t)})})});0&&(module.exports={createExecutionPathsPlugin,getExecutionPaths});
2
- //# sourceMappingURL=index.cjs.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/plugins/execution-paths/index.ts", "../../../src/journey-machine/helpers.ts", "../../../src/journey-machine/resolve-journey-definition.ts", "../../../src/plugins/execution-paths/execution-paths.ts"],
4
- "sourcesContent": ["import { getExecutionPaths } from \"./execution-paths\";\n\nimport type {\n JourneyExecutionPathOptions,\n JourneyExecutionPathsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyMachine,\n JourneyMachinePlugin\n} from \"../../types\";\n\nexport type JourneyExecutionPathsMachineExtension<\n TStepId extends string,\n TEventType extends string\n> = {\n getExecutionPaths: (\n options?: JourneyExecutionPathOptions\n ) => JourneyExecutionPathsResult<TStepId, TEventType>;\n};\n\nexport type JourneyExecutionPathsMachine<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown> = Record<never, never>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> &\n JourneyExecutionPathsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;\n\n/**\n * Creates a plugin that augments a machine with structural execution-path\n * enumeration without pulling graph code into the base entrypoint.\n */\nexport const createExecutionPathsPlugin = () =>\n ({\n name: \"execution-paths\",\n setup: ({ resolvedJourney }) => ({\n augmentMachine: () => ({\n getExecutionPaths: (options?: JourneyExecutionPathOptions) =>\n getExecutionPaths(resolvedJourney, options)\n })\n })\n }) satisfies JourneyMachinePlugin;\n\nexport { getExecutionPaths } from \"./execution-paths\";\n", "import type {\n JourneyAsyncState,\n JourneyEvent,\n JourneyGoToEvent,\n JourneyJsonObject,\n JourneyJsonValue,\n JourneyPayloadFor,\n JourneyResolvedTransition,\n JourneySendEvent,\n JourneySendResult,\n JourneySnapshot,\n JourneyStatus,\n JourneyStepAsyncState,\n JourneyTerminal,\n JourneyTransition,\n JourneyTransitionArgs\n} from \"../types\";\n\nexport const assertStepExists = <TStepId extends string>(\n steps: Record<TStepId, unknown>,\n stepId: TStepId,\n message: string\n) => {\n if (!(stepId in steps)) {\n throw new Error(message);\n }\n};\n\nexport const isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);\n\nconst cloneSerializableValue = <T extends JourneyJsonValue>(value: T): T => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneSerializableValue(entry)) as T;\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneSerializableValue(entryValue as JourneyJsonValue)\n ])\n ) as T;\n }\n\n return value;\n};\n\ntype SerializableCheckState = {\n readonly seen: WeakSet<object>;\n};\n\nconst describeValue = (value: unknown): string => {\n if (value === null) {\n return \"null\";\n }\n\n if (Array.isArray(value)) {\n return \"array\";\n }\n\n if (typeof value === \"object\") {\n const constructorName = (value as { constructor?: { name?: string } }).constructor?.name;\n return constructorName && constructorName !== \"Object\" ? constructorName : \"object\";\n }\n\n return typeof value;\n};\n\nfunction assertSerializableValue(\n value: unknown,\n label: string,\n state: SerializableCheckState,\n path: readonly string[] = []\n): asserts value is JourneyJsonValue {\n if (\n value === null ||\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n return;\n }\n\n const pathLabel = path.length === 0 ? label : `${label}.${path.join(\".\")}`;\n\n if (value === undefined) {\n throw new Error(`${pathLabel} must be JSON-serializable. Received undefined.`);\n }\n\n if (typeof value === \"bigint\" || typeof value === \"symbol\" || typeof value === \"function\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${typeof value}.`);\n }\n\n if (typeof value !== \"object\") {\n throw new Error(`${pathLabel} must be JSON-serializable. Received ${describeValue(value)}.`);\n }\n\n if (state.seen.has(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Circular references are not supported.`\n );\n }\n\n state.seen.add(value);\n\n if (Array.isArray(value)) {\n for (const [index, entryValue] of value.entries()) {\n assertSerializableValue(entryValue, label, state, [...path, String(index)]);\n }\n return;\n }\n\n if (!isPlainObject(value)) {\n throw new Error(\n `${pathLabel} must be JSON-serializable. Received non-plain ${describeValue(value)}.`\n );\n }\n\n for (const [key, entryValue] of Object.entries(value)) {\n assertSerializableValue(entryValue, label, state, [...path, key]);\n }\n}\n\nexport function assertSerializableContext<TContext extends JourneyJsonObject>(\n context: TContext,\n label = \"Journey context\"\n): TContext {\n assertSerializableValue(context, label, { seen: new WeakSet() });\n return context;\n}\n\nexport const cloneContext = <TContext extends JourneyJsonObject>(context: TContext): TContext =>\n cloneSerializableValue(assertSerializableContext(context));\n\nconst cloneDefinitionValueFallback = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map((entry) => cloneDefinitionValueFallback(entry));\n }\n\n if (value instanceof Date) {\n return new Date(value.getTime());\n }\n\n if (value instanceof Map) {\n return new Map(\n [...value.entries()].map(([key, entryValue]) => [\n cloneDefinitionValueFallback(key),\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n if (value instanceof Set) {\n return new Set([...value].map((entry) => cloneDefinitionValueFallback(entry)));\n }\n\n if (isPlainObject(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entryValue]) => [\n key,\n cloneDefinitionValueFallback(entryValue)\n ])\n );\n }\n\n return value;\n};\n\nexport const cloneMetaValue = <T>(value: T): T => {\n if ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) {\n return value;\n }\n\n if (typeof structuredClone === \"function\") {\n try {\n return structuredClone(value);\n } catch {\n return cloneDefinitionValueFallback(value) as T;\n }\n } else {\n return cloneDefinitionValueFallback(value) as T;\n }\n};\n\nconst freezeSnapshotValue = (value: unknown) => {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return;\n }\n\n if (Array.isArray(value)) {\n for (const item of value) {\n freezeSnapshotValue(item);\n }\n Object.freeze(value);\n return;\n }\n\n if (!isPlainObject(value)) {\n return;\n }\n\n for (const entryValue of Object.values(value)) {\n freezeSnapshotValue(entryValue);\n }\n Object.freeze(value);\n};\n\nexport const normalizeStepCount = (steps?: number): number => {\n if (typeof steps !== \"number\" || !Number.isFinite(steps)) {\n return 1;\n }\n return Math.max(1, Math.trunc(steps));\n};\n\nexport const now = (): number => Date.now();\n\nconst unique = <T>(items: readonly T[]): T[] => [...new Set(items)];\n\nconst normalizeVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n stepIds: readonly TStepId[]\n): Record<TStepId, boolean> =>\n Object.fromEntries(stepIds.map((stepId) => [stepId, visited[stepId] === true])) as Record<\n TStepId,\n boolean\n >;\n\nexport const buildVisitedFromTimeline = <TStepId extends string>(\n timeline: readonly TStepId[],\n stepIds?: readonly TStepId[]\n): Record<TStepId, boolean> => {\n const resolvedStepIds = stepIds ?? unique(timeline);\n const visited = Object.fromEntries(resolvedStepIds.map((stepId) => [stepId, false])) as Record<\n TStepId,\n boolean\n >;\n\n for (const stepId of timeline) {\n visited[stepId] = true;\n }\n\n return visited;\n};\n\nexport const appendVisited = <TStepId extends string>(\n visited: Record<TStepId, boolean>,\n current: TStepId\n): Record<TStepId, boolean> => ({\n ...visited,\n [current]: true\n});\n\nexport const isPromiseLike = <T>(value: T | PromiseLike<T>): value is PromiseLike<T> =>\n typeof value === \"object\" &&\n value !== null &&\n \"then\" in value &&\n typeof (value as { then: unknown }).then === \"function\";\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === \"number\" && Number.isFinite(value);\n\nexport const validateFiniteTimeout = (timeoutMs: unknown, label: string) => {\n if (timeoutMs !== undefined && !isFiniteNumber(timeoutMs)) {\n throw new Error(`${label} must define a finite numeric \"timeoutMs\" when provided.`);\n }\n};\n\nexport class JourneyTimeoutError extends Error {\n override name = \"JourneyTimeoutError\";\n\n constructor(message: string) {\n super(message);\n }\n}\n\nexport class JourneyDisposedError extends Error {\n override name = \"JourneyDisposedError\";\n readonly operation: string;\n\n constructor(operation: string) {\n super(`Journey machine has been disposed; \"${operation}\" can no longer be used.`);\n this.operation = operation;\n }\n}\n\ntype DiagnosticGlobal = typeof globalThis & {\n __DEV__?: unknown;\n process?: {\n env?: {\n NODE_ENV?: string;\n };\n };\n};\n\nexport const isDevelopmentEnvironment = (): boolean => {\n const diagnosticGlobal = globalThis as DiagnosticGlobal;\n if (typeof diagnosticGlobal.__DEV__ === \"boolean\") {\n return diagnosticGlobal.__DEV__;\n }\n\n const nodeEnv = diagnosticGlobal.process?.env?.NODE_ENV;\n return nodeEnv === undefined || nodeEnv === \"development\";\n};\n\nexport const warnInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.warn(message);\n return;\n }\n\n console.warn(message, detail);\n};\n\nexport const errorInDevelopment = (message: string, detail?: unknown) => {\n if (!isDevelopmentEnvironment() || typeof console === \"undefined\") {\n return;\n }\n\n if (detail === undefined) {\n console.error(message);\n return;\n }\n\n console.error(message, detail);\n};\n\nexport const withTimeout = async <T>(\n promise: PromiseLike<T>,\n timeoutMs: number | undefined,\n buildError: () => Error\n): Promise<T> => {\n if (!isFiniteNumber(timeoutMs) || timeoutMs <= 0) {\n return await promise;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => {\n reject(buildError());\n }, timeoutMs);\n\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n }\n );\n });\n};\n\nexport const withAbortSignal = async <T>(\n promise: PromiseLike<T>,\n signal: AbortSignal\n): Promise<T> => {\n if (signal.aborted) {\n throw signal.reason;\n }\n\n return await new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(signal.reason);\n };\n\n signal.addEventListener(\"abort\", onAbort, { once: true });\n promise.then(\n (value) => {\n signal.removeEventListener(\"abort\", onAbort);\n resolve(value);\n },\n (error) => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(error);\n }\n );\n });\n};\n\nexport const buildIdleStepAsyncState = (): JourneyStepAsyncState => ({\n phase: \"idle\",\n eventType: null,\n transitionId: null,\n error: null\n});\n\nexport const buildInitialAsyncState = <TStepId extends string>(\n steps: Record<TStepId, unknown>\n): JourneyAsyncState<TStepId> => {\n const byStep = Object.fromEntries(\n Object.keys(steps).map((stepId) => [stepId, buildIdleStepAsyncState()])\n ) as Record<TStepId, JourneyStepAsyncState>;\n\n return {\n isLoading: false,\n byStep\n };\n};\n\nexport const isGoToStepByIdEvent = <\n TStepId extends string,\n TEventMap extends Record<string, unknown>\n>(\n event: JourneySendEvent<TStepId, TEventMap>\n): event is JourneyGoToEvent<TStepId, JourneyPayloadFor<TEventMap, \"goToStepById\">> =>\n event.type === \"goToStepById\" && \"stepId\" in event;\n\nexport const isTerminalTarget = <TStepId extends string>(\n target: TStepId | JourneyTerminal\n): target is JourneyTerminal => target === \"COMPLETE\" || target === \"TERMINATED\";\n\nexport const resolveTransitionTarget = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transition: JourneyTransition<TContext, TStepId, TEventMap, THandlers>\n): TStepId | JourneyTerminal =>\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : (transition.to as TStepId | JourneyTerminal);\n\nexport const validateJourneyTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[],\n steps: Record<TStepId, unknown>\n) => {\n const stepRegistry = steps as Record<string, unknown>;\n const allowedKeys = new Set([\n \"from\",\n \"event\",\n \"to\",\n \"when\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"id\",\n \"label\",\n \"timeoutMs\"\n ]);\n\n for (const [index, transition] of transitions.entries()) {\n if (!transition || typeof transition !== \"object\") {\n throw new Error(`Journey transition at index ${index} must be an object.`);\n }\n\n for (const key of Object.keys(transition)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at index ${index} contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (typeof transition.from !== \"string\" || typeof transition.event !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define string \"from\" and \"event\".`\n );\n }\n\n if (transition.from !== \"*\" && !(transition.from in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} references unknown from step \"${transition.from}\".`\n );\n }\n\n validateFiniteTimeout(transition.timeoutMs, `Journey transition at index ${index}`);\n\n if (transition.when !== undefined && typeof transition.when !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"when\" as a function when provided.`\n );\n }\n\n if (transition.updateContext !== undefined && typeof transition.updateContext !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (transition.onEnter !== undefined && typeof transition.onEnter !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (transition.onLeave !== undefined && typeof transition.onLeave !== \"function\") {\n throw new Error(\n `Journey transition at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n if (transition.id !== undefined && typeof transition.id !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"id\" as a string when provided.`\n );\n }\n\n if (transition.label !== undefined && typeof transition.label !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} must define \"label\" as a string when provided.`\n );\n }\n\n if (transition.event === \"completeJourney\" || transition.event === \"terminateJourney\") {\n if (\"to\" in transition && transition.to !== undefined) {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" cannot define \"to\".`\n );\n }\n continue;\n }\n\n if (typeof transition.to !== \"string\") {\n throw new Error(\n `Journey transition at index ${index} with event \"${transition.event}\" must define string \"to\".`\n );\n }\n\n if (!isTerminalTarget(transition.to) && !(transition.to in stepRegistry)) {\n throw new Error(\n `Journey transition at index ${index} points to unknown step \"${transition.to}\".`\n );\n }\n }\n};\n\nexport const buildSendResult = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n transitioned: boolean,\n options: {\n transitionId?: string;\n label?: string;\n error?: unknown;\n } = {}\n): JourneySendResult<TContext, TStepId> => ({\n transitioned,\n ...(options.transitionId !== undefined ? { transitionId: options.transitionId } : {}),\n ...(options.label !== undefined ? { label: options.label } : {}),\n ...(\"error\" in options ? { error: options.error } : {}),\n snapshot\n});\n\nexport const buildSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n timeline: readonly TStepId[],\n index: number,\n context: TContext,\n status: JourneyStatus,\n asyncState: JourneyAsyncState<TStepId>,\n visited?: Record<TStepId, boolean>\n): JourneySnapshot<TContext, TStepId> => {\n if (timeline.length === 0) {\n throw new Error(\"Journey timeline cannot be empty.\");\n }\n\n const safeIndex = Math.max(0, Math.min(Math.trunc(index), timeline.length - 1));\n const currentStepId = timeline[safeIndex] as TStepId;\n const stepIds = unique(\n visited ? ([...(Object.keys(visited) as TStepId[]), ...timeline] as const) : timeline\n );\n\n return {\n status,\n currentStepId,\n history: {\n timeline: [...timeline],\n index: safeIndex\n },\n context: cloneContext(context),\n visited: visited\n ? normalizeVisited(visited, stepIds)\n : buildVisitedFromTimeline(timeline, stepIds),\n async: cloneSerializableValue(\n asyncState as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n};\n\nexport const stabilizeSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>\n): JourneySnapshot<TContext, TStepId> => {\n const stableSnapshot: JourneySnapshot<TContext, TStepId> = {\n ...snapshot,\n history: {\n timeline: [...snapshot.history.timeline],\n index: snapshot.history.index\n },\n context: cloneContext(snapshot.context),\n visited: { ...snapshot.visited },\n async: cloneSerializableValue(\n snapshot.async as unknown as JourneyJsonValue\n ) as JourneyAsyncState<TStepId>\n };\n\n freezeSnapshotValue(stableSnapshot);\n return stableSnapshot;\n};\n\nexport const selectTransition = async <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>,\n TTransition extends {\n from: TStepId | \"*\";\n event: string;\n when?: (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>;\n timeoutMs?: number;\n id?: string;\n label?: string;\n }\n>(\n transitions: readonly TTransition[],\n snapshot: JourneySnapshot<TContext, TStepId>,\n event: JourneyEvent<TStepId, TEventMap>,\n signal: AbortSignal,\n handlers: THandlers,\n hooks?: {\n onAsyncGuardStart?: (transition: TTransition) => void;\n onAsyncGuardSuccess?: (transition: TTransition) => void;\n onAsyncGuardError?: (transition: TTransition, error: unknown) => void;\n },\n defaultTimeoutMs?: number\n): Promise<TTransition | null> => {\n for (const transition of transitions) {\n const fromMatches = transition.from === \"*\" || transition.from === snapshot.currentStepId;\n const eventMatches = transition.event === event.type;\n\n if (!fromMatches || !eventMatches) {\n continue;\n }\n\n if (!transition.when) {\n return transition;\n }\n\n let guardResult: boolean | Promise<boolean>;\n if (signal.aborted) {\n throw signal.reason;\n }\n\n guardResult = (\n transition.when as (\n args: JourneyTransitionArgs<TContext, TStepId, TEventMap, THandlers>\n ) => boolean | Promise<boolean>\n )({\n snapshot,\n context: snapshot.context,\n from: snapshot.currentStepId,\n timeline: snapshot.history.timeline,\n index: snapshot.history.index,\n event,\n signal,\n handlers\n });\n\n const asyncGuard = isPromiseLike(guardResult);\n const asyncGuardPromise = asyncGuard ? (guardResult as PromiseLike<boolean>) : null;\n\n let allowed: boolean;\n try {\n if (asyncGuard) {\n hooks?.onAsyncGuardStart?.(transition);\n allowed = await withTimeout(\n withAbortSignal(asyncGuardPromise as PromiseLike<boolean>, signal),\n transition.timeoutMs ?? defaultTimeoutMs,\n () =>\n new JourneyTimeoutError(\n `Transition guard timed out after ${transition.timeoutMs ?? defaultTimeoutMs}ms (event: ${event.type}, transition: ${transition.id ?? \"<anonymous>\"}).`\n )\n );\n } else {\n allowed = guardResult as boolean;\n }\n } catch (error) {\n if (asyncGuard) {\n hooks?.onAsyncGuardError?.(transition, error);\n }\n throw error;\n }\n\n if (asyncGuard) {\n hooks?.onAsyncGuardSuccess?.(transition);\n }\n\n if (allowed) {\n return transition;\n }\n }\n\n return null;\n};\n\nexport const transitionSnapshot = <TContext extends JourneyJsonObject, TStepId extends string>(\n snapshot: JourneySnapshot<TContext, TStepId>,\n nextCurrent: TStepId,\n nextContext: TContext\n): JourneySnapshot<TContext, TStepId> => {\n const baseTimeline = snapshot.history.timeline.slice(0, snapshot.history.index + 1);\n let nextTimeline = baseTimeline;\n if (nextCurrent !== snapshot.currentStepId) {\n nextTimeline = [...baseTimeline, nextCurrent];\n }\n\n const nextIndex = nextTimeline.length - 1;\n const visited = appendVisited(snapshot.visited, nextCurrent);\n\n return buildSnapshot(\n nextTimeline,\n nextIndex,\n nextContext,\n snapshot.status,\n snapshot.async,\n visited\n );\n};\n", "import { validateFiniteTimeout } from \"./helpers\";\n\nimport type {\n JourneyDefinition,\n JourneyJsonObject,\n JourneyResolvedDefinition,\n JourneyResolvedTransition,\n JourneyTransition,\n JourneyTransitionGraph\n} from \"../types\";\n\nconst hashTransitionDescriptor = (value: string) => {\n let hash = 2166136261;\n for (let index = 0; index < value.length; index += 1) {\n hash ^= value.charCodeAt(index);\n hash = Math.imul(hash, 16777619);\n }\n return (hash >>> 0).toString(16).padStart(8, \"0\");\n};\n\nconst buildResolvedTransitions = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n THandlers extends Record<string, unknown>\n>(\n transitions: readonly JourneyTransition<TContext, TStepId, TEventMap, THandlers>[]\n): JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>[] => {\n const transitionRouteCounts = new Map<string, number>();\n const usedIds = new Set<string>();\n\n return transitions.map((transition) => {\n const target =\n transition.event === \"completeJourney\"\n ? \"COMPLETE\"\n : transition.event === \"terminateJourney\"\n ? \"TERMINATED\"\n : String(transition.to);\n const routeKey = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target\n });\n const ordinal = (transitionRouteCounts.get(routeKey) ?? 0) + 1;\n transitionRouteCounts.set(routeKey, ordinal);\n\n const descriptor = JSON.stringify({\n from: transition.from,\n event: transition.event,\n target,\n ordinal\n });\n\n let suffix = 0;\n const id = (() => {\n let candidate = hashTransitionDescriptor(descriptor);\n while (usedIds.has(candidate)) {\n suffix += 1;\n candidate = hashTransitionDescriptor(`${descriptor}:${suffix}`);\n }\n return candidate;\n })();\n usedIds.add(id);\n\n return {\n ...transition,\n id,\n ...(transition.label !== undefined ? { label: transition.label } : {})\n } as JourneyResolvedTransition<TContext, TStepId, TEventMap, THandlers>;\n });\n};\n\nexport const resolveJourneyDefinition = <\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>\n): JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers> => {\n type TEventType = string;\n const resolvedTransitions: JourneyTransition<TContext, TStepId, TEventMap, THandlers>[] = [];\n const { transitions } = journey;\n\n if (transitions === undefined) {\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n }\n\n if (Array.isArray(transitions)) {\n if (transitions.length === 0) {\n throw new Error(\n \"Journey linear transitions must include the initial step as the first item.\"\n );\n }\n\n const [initialStep, ...linearEntries] = transitions;\n if (typeof initialStep !== \"string\") {\n throw new Error(\"Journey linear transitions at index 0 must be a step id string.\");\n }\n\n if (!(initialStep in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${initialStep}\".`);\n }\n\n // Resolve initial: use journey.initial if provided (start from middle), otherwise array[0]\n const resolvedInitial = (journey.initial ?? initialStep) as TStepId;\n\n if (journey.initial !== undefined) {\n const allStepIds = transitions.map((entry) =>\n typeof entry === \"string\" ? entry : entry.step\n );\n if (!allStepIds.includes(journey.initial)) {\n throw new Error(\n `Journey initial step \"${journey.initial}\" does not exist in linear transitions.`\n );\n }\n }\n\n let previousStep = initialStep as TStepId;\n const seenSteps = new Set<string>([initialStep]);\n for (const [offset, entry] of linearEntries.entries()) {\n const index = offset + 1;\n if (typeof entry === \"string\") {\n if (!(entry in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry}\".`);\n }\n\n if (seenSteps.has(entry)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry}\" at index ${index}.`\n );\n }\n seenSteps.add(entry);\n\n resolvedTransitions.push({\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry as TStepId;\n continue;\n }\n\n if (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n throw new Error(\n `Journey linear transitions at index ${index} must be a step id string or step config object.`\n );\n }\n\n const allowedKeys = new Set([\n \"step\",\n \"label\",\n \"updateContext\",\n \"onEnter\",\n \"onLeave\",\n \"timeoutMs\"\n ]);\n for (const key of Object.keys(entry)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey linear transition object at index ${index} contains unsupported field \"${key}\". Allowed fields are \"step\", \"label\", \"updateContext\", \"onEnter\", \"onLeave\", and \"timeoutMs\".`\n );\n }\n }\n\n if (typeof entry.step !== \"string\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define string \"step\".`\n );\n }\n\n if (!(entry.step in journey.steps)) {\n throw new Error(`Journey linear transitions reference unknown step \"${entry.step}\".`);\n }\n\n if (seenSteps.has(entry.step)) {\n throw new Error(\n `Journey linear transitions contain duplicate step \"${entry.step}\" at index ${index}.`\n );\n }\n seenSteps.add(entry.step);\n\n if (entry.updateContext !== undefined && typeof entry.updateContext !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (entry.onEnter !== undefined && typeof entry.onEnter !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (entry.onLeave !== undefined && typeof entry.onLeave !== \"function\") {\n throw new Error(\n `Journey linear transition object at index ${index} must define \"onLeave\" as a function when provided.`\n );\n }\n\n validateFiniteTimeout(entry.timeoutMs, `Journey linear transition object at index ${index}`);\n\n resolvedTransitions.push({\n ...(entry.label !== undefined ? { label: entry.label } : {}),\n ...(entry.timeoutMs !== undefined ? { timeoutMs: entry.timeoutMs } : {}),\n ...(entry.updateContext !== undefined ? { updateContext: entry.updateContext } : {}),\n ...(entry.onEnter !== undefined ? { onEnter: entry.onEnter } : {}),\n ...(entry.onLeave !== undefined ? { onLeave: entry.onLeave } : {}),\n from: previousStep,\n event: \"goToNextStep\" as TEventType,\n to: entry.step as TStepId\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n previousStep = entry.step as TStepId;\n }\n\n return {\n ...journey,\n initial: resolvedInitial,\n transitions: buildResolvedTransitions(resolvedTransitions)\n };\n }\n\n if (!transitions || typeof transitions !== \"object\") {\n throw new Error(\"Journey transitions must be an array or an object map when provided.\");\n }\n\n const transitionGraph = transitions as JourneyTransitionGraph<\n TContext,\n TStepId,\n TEventMap,\n THandlers\n >;\n\n const orderedGraphEntries = [\n ...Object.entries(transitionGraph).filter(([fromKey]) => fromKey !== \"global\"),\n ...(transitionGraph.global ? ([[\"global\", transitionGraph.global]] as const) : [])\n ];\n\n for (const [fromKey, eventMap] of orderedGraphEntries) {\n if (fromKey !== \"global\" && !(fromKey in journey.steps)) {\n throw new Error(`Journey transitions reference unknown step \"${fromKey}\".`);\n }\n\n if (!eventMap || typeof eventMap !== \"object\" || Array.isArray(eventMap)) {\n throw new Error(`Journey transitions for \"${fromKey}\" must be an event map object.`);\n }\n\n for (const [event, rawEdges] of Object.entries(eventMap) as Array<\n [TEventType, (typeof eventMap)[TEventType] | true]\n >) {\n const isTerminal = event === \"completeJourney\" || event === \"terminateJourney\";\n const edges =\n isTerminal && (rawEdges === true || (Array.isArray(rawEdges) && rawEdges.length === 0))\n ? [{}]\n : rawEdges;\n\n if (!Array.isArray(edges)) {\n throw new Error(`Journey transitions for \"${fromKey}.${event}\" must be an array.`);\n }\n\n for (const [index, edge] of edges.entries()) {\n if (!edge || typeof edge !== \"object\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must be an object.`\n );\n }\n\n const allowedKeys = new Set(\n isTerminal\n ? [\"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n : [\"to\", \"when\", \"updateContext\", \"onEnter\", \"onLeave\", \"label\", \"timeoutMs\"]\n );\n for (const key of Object.keys(edge)) {\n if (!allowedKeys.has(key)) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" contains unsupported field \"${key}\".`\n );\n }\n }\n\n if (!isTerminal && typeof (edge as { to?: unknown }).to !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define string \"to\".`\n );\n }\n\n if ((edge as { when?: unknown }).when !== undefined && typeof edge.when !== \"function\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"when\" as a function when provided.`\n );\n }\n\n if (\n (edge as { updateContext?: unknown }).updateContext !== undefined &&\n typeof edge.updateContext !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"updateContext\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onEnter?: unknown }).onEnter !== undefined &&\n typeof edge.onEnter !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onEnter\" as a function when provided.`\n );\n }\n\n if (\n (edge as { onLeave?: unknown }).onLeave !== undefined &&\n typeof edge.onLeave !== \"function\"\n ) {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"onLeave\" as a function when provided.`\n );\n }\n\n if ((edge as { label?: unknown }).label !== undefined && typeof edge.label !== \"string\") {\n throw new Error(\n `Journey transition at \"${fromKey}.${event}[${index}]\" must define \"label\" as a string when provided.`\n );\n }\n\n validateFiniteTimeout(\n (edge as { timeoutMs?: unknown }).timeoutMs,\n `Journey transition at \"${fromKey}.${event}[${index}]\"`\n );\n\n resolvedTransitions.push({\n ...edge,\n from: (fromKey === \"global\" ? \"*\" : fromKey) as TStepId | \"*\",\n event\n } as JourneyTransition<TContext, TStepId, TEventMap, THandlers>);\n }\n }\n }\n\n return {\n ...journey,\n transitions: buildResolvedTransitions(resolvedTransitions)\n } as JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>;\n};\n", "/* eslint-disable no-redeclare */\nimport { resolveTransitionTarget } from \"../../journey-machine/helpers\";\nimport { resolveJourneyDefinition } from \"../../journey-machine/resolve-journey-definition\";\n\nimport type {\n JourneyDefinition,\n JourneyExecutionPath,\n JourneyExecutionPathEventType,\n JourneyExecutionPathOptions,\n JourneyExecutionPathsResult,\n JourneyFullEventType,\n JourneyJsonObject,\n JourneyResolvedDefinition\n} from \"../../types\";\n\nconst normalizeLimit = (value: number | undefined, fallback: number): number => {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n return fallback;\n }\n\n return Math.max(1, Math.trunc(value));\n};\n\n/**\n * Enumerates structural execution paths from a resolved journey definition.\n */\nexport function getExecutionPaths<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyExecutionPathOptions\n): JourneyExecutionPathsResult<TStepId, JourneyFullEventType<TEventMap>>;\nexport function getExecutionPaths<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey: JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options?: JourneyExecutionPathOptions\n): JourneyExecutionPathsResult<TStepId, JourneyFullEventType<TEventMap>>;\nexport function getExecutionPaths<\n TContext extends JourneyJsonObject,\n TStepId extends string,\n TEventMap extends Record<string, unknown>,\n TStepMeta = unknown,\n THandlers extends Record<string, unknown> = Record<never, never>\n>(\n journey:\n | JourneyDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>\n | JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers>,\n options: JourneyExecutionPathOptions = {}\n): JourneyExecutionPathsResult<TStepId, JourneyFullEventType<TEventMap>> {\n type TEventType = JourneyFullEventType<TEventMap>;\n const isResolvedJourneyDefinition = (\n value: typeof journey\n ): value is JourneyResolvedDefinition<TContext, TStepId, TEventMap, TStepMeta, THandlers> =>\n Array.isArray(value.transitions) &&\n (value.transitions.length === 0 ||\n (typeof value.transitions[0] === \"object\" && value.transitions[0] !== null));\n const resolvedJourney = isResolvedJourneyDefinition(journey)\n ? journey\n : resolveJourneyDefinition(journey);\n const maxDepth = normalizeLimit(options.maxDepth, 5);\n const maxPaths = normalizeLimit(options.maxPaths, 10);\n const paths: JourneyExecutionPath<TStepId, TEventType>[] = [];\n let truncated = false;\n let cyclesDetected = false;\n\n const pushPath = (path: JourneyExecutionPath<TStepId, TEventType>) => {\n if (paths.length >= maxPaths) {\n truncated = true;\n return;\n }\n\n paths.push(path);\n };\n\n const visit = (\n currentStepId: TStepId,\n steps: TStepId[],\n events: JourneyExecutionPathEventType<TEventType>[]\n ) => {\n if (paths.length >= maxPaths) {\n truncated = true;\n return;\n }\n\n const outgoing = resolvedJourney.transitions.filter(\n (transition) => transition.from === \"*\" || transition.from === currentStepId\n );\n\n if (outgoing.length === 0) {\n pushPath({ steps, events, terminated: \"final\" });\n return;\n }\n\n if (events.length >= maxDepth) {\n pushPath({ steps, events, terminated: \"depth\" });\n truncated = true;\n return;\n }\n\n for (const transition of outgoing) {\n const nextEvents = [...events, transition.event as JourneyExecutionPathEventType<TEventType>];\n const target = resolveTransitionTarget(transition);\n\n if (target === \"COMPLETE\" || target === \"TERMINATED\") {\n pushPath({ steps, events: nextEvents, terminated: \"final\" });\n continue;\n }\n\n const nextSteps = [...steps, target];\n if (steps.includes(target)) {\n cyclesDetected = true;\n pushPath({ steps: nextSteps, events: nextEvents, terminated: \"cycle\" });\n continue;\n }\n\n visit(target, nextSteps, nextEvents);\n if (paths.length >= maxPaths) {\n truncated = true;\n return;\n }\n }\n };\n\n visit(resolvedJourney.initial, [resolvedJourney.initial], []);\n\n return {\n paths,\n truncated,\n cyclesDetected\n };\n}\n/* eslint-enable no-redeclare */\n"],
5
- "mappings": "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",
6
- "names": ["execution_paths_exports", "__export", "createExecutionPathsPlugin", "getExecutionPaths", "__toCommonJS", "isFiniteNumber", "value", "validateFiniteTimeout", "timeoutMs", "label", "resolveTransitionTarget", "transition", "hashTransitionDescriptor", "value", "hash", "index", "buildResolvedTransitions", "transitions", "transitionRouteCounts", "usedIds", "transition", "target", "routeKey", "ordinal", "descriptor", "suffix", "id", "candidate", "resolveJourneyDefinition", "journey", "resolvedTransitions", "initialStep", "linearEntries", "resolvedInitial", "entry", "previousStep", "seenSteps", "offset", "allowedKeys", "key", "validateFiniteTimeout", "transitionGraph", "orderedGraphEntries", "fromKey", "eventMap", "event", "rawEdges", "isTerminal", "edges", "edge", "normalizeLimit", "value", "fallback", "getExecutionPaths", "journey", "options", "resolvedJourney", "resolveJourneyDefinition", "maxDepth", "maxPaths", "paths", "truncated", "cyclesDetected", "pushPath", "path", "visit", "currentStepId", "steps", "events", "outgoing", "transition", "nextEvents", "target", "resolveTransitionTarget", "nextSteps", "createExecutionPathsPlugin", "resolvedJourney", "options", "getExecutionPaths"]
7
- }
@@ -1,18 +0,0 @@
1
- import type { JourneyExecutionPathOptions, JourneyExecutionPathsResult, JourneyFullEventType, JourneyJsonObject, JourneyMachine } from "../../types";
2
- export type JourneyExecutionPathsMachineExtension<TStepId extends string, TEventType extends string> = {
3
- getExecutionPaths: (options?: JourneyExecutionPathOptions) => JourneyExecutionPathsResult<TStepId, TEventType>;
4
- };
5
- export type JourneyExecutionPathsMachine<TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> & JourneyExecutionPathsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;
6
- /**
7
- * Creates a plugin that augments a machine with structural execution-path
8
- * enumeration without pulling graph code into the base entrypoint.
9
- */
10
- export declare const createExecutionPathsPlugin: () => {
11
- name: string;
12
- setup: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>>({ resolvedJourney }: import("../../types").JourneyMachinePluginSetupContext<TContext, TStepId, TEventMap, TStepMeta, THandlers>) => {
13
- augmentMachine: () => {
14
- getExecutionPaths: (options?: JourneyExecutionPathOptions) => JourneyExecutionPathsResult<TStepId, JourneyFullEventType<TEventMap>>;
15
- };
16
- };
17
- };
18
- export { getExecutionPaths } from "./execution-paths";
@@ -1,18 +0,0 @@
1
- import type { JourneyExecutionPathOptions, JourneyExecutionPathsResult, JourneyFullEventType, JourneyJsonObject, JourneyMachine } from "../../types";
2
- export type JourneyExecutionPathsMachineExtension<TStepId extends string, TEventType extends string> = {
3
- getExecutionPaths: (options?: JourneyExecutionPathOptions) => JourneyExecutionPathsResult<TStepId, TEventType>;
4
- };
5
- export type JourneyExecutionPathsMachine<TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>> = JourneyMachine<TContext, TStepId, TEventMap, TStepMeta, THandlers> & JourneyExecutionPathsMachineExtension<TStepId, JourneyFullEventType<TEventMap>>;
6
- /**
7
- * Creates a plugin that augments a machine with structural execution-path
8
- * enumeration without pulling graph code into the base entrypoint.
9
- */
10
- export declare const createExecutionPathsPlugin: () => {
11
- name: string;
12
- setup: <TContext extends JourneyJsonObject, TStepId extends string, TEventMap extends Record<string, unknown> = Record<never, never>, TStepMeta = unknown, THandlers extends Record<string, unknown> = Record<never, never>>({ resolvedJourney }: import("../../types").JourneyMachinePluginSetupContext<TContext, TStepId, TEventMap, TStepMeta, THandlers>) => {
13
- augmentMachine: () => {
14
- getExecutionPaths: (options?: JourneyExecutionPathOptions) => JourneyExecutionPathsResult<TStepId, JourneyFullEventType<TEventMap>>;
15
- };
16
- };
17
- };
18
- export { getExecutionPaths } from "./execution-paths";
@@ -1,2 +0,0 @@
1
- var I=n=>typeof n=="number"&&Number.isFinite(n),J=(n,i)=>{if(n!==void 0&&!I(n))throw new Error(`${i} must define a finite numeric "timeoutMs" when provided.`)};var h=n=>n.event==="completeJourney"?"COMPLETE":n.event==="terminateJourney"?"TERMINATED":n.to;var b=n=>{let i=2166136261;for(let a=0;a<n.length;a+=1)i^=n.charCodeAt(a),i=Math.imul(i,16777619);return(i>>>0).toString(16).padStart(8,"0")},E=n=>{let i=new Map,a=new Set;return n.map(s=>{let f=s.event==="completeJourney"?"COMPLETE":s.event==="terminateJourney"?"TERMINATED":String(s.to),t=JSON.stringify({from:s.from,event:s.event,target:f}),u=(i.get(t)??0)+1;i.set(t,u);let r=JSON.stringify({from:s.from,event:s.event,target:f,ordinal:u}),p=0,d=(()=>{let c=b(r);for(;a.has(c);)p+=1,c=b(`${r}:${p}`);return c})();return a.add(d),{...s,id:d,...s.label!==void 0?{label:s.label}:{}}})},g=n=>{let i=[],{transitions:a}=n;if(a===void 0)return{...n,transitions:E(i)};if(Array.isArray(a)){if(a.length===0)throw new Error("Journey linear transitions must include the initial step as the first item.");let[t,...u]=a;if(typeof t!="string")throw new Error("Journey linear transitions at index 0 must be a step id string.");if(!(t in n.steps))throw new Error(`Journey linear transitions reference unknown step "${t}".`);let r=n.initial??t;if(n.initial!==void 0&&!a.map(e=>typeof e=="string"?e:e.step).includes(n.initial))throw new Error(`Journey initial step "${n.initial}" does not exist in linear transitions.`);let p=t,d=new Set([t]);for(let[c,e]of u.entries()){let o=c+1;if(typeof e=="string"){if(!(e in n.steps))throw new Error(`Journey linear transitions reference unknown step "${e}".`);if(d.has(e))throw new Error(`Journey linear transitions contain duplicate step "${e}" at index ${o}.`);d.add(e),i.push({from:p,event:"goToNextStep",to:e}),p=e;continue}if(!e||typeof e!="object"||Array.isArray(e))throw new Error(`Journey linear transitions at index ${o} must be a step id string or step config object.`);let T=new Set(["step","label","updateContext","onEnter","onLeave","timeoutMs"]);for(let y of Object.keys(e))if(!T.has(y))throw new Error(`Journey linear transition object at index ${o} contains unsupported field "${y}". Allowed fields are "step", "label", "updateContext", "onEnter", "onLeave", and "timeoutMs".`);if(typeof e.step!="string")throw new Error(`Journey linear transition object at index ${o} must define string "step".`);if(!(e.step in n.steps))throw new Error(`Journey linear transitions reference unknown step "${e.step}".`);if(d.has(e.step))throw new Error(`Journey linear transitions contain duplicate step "${e.step}" at index ${o}.`);if(d.add(e.step),e.updateContext!==void 0&&typeof e.updateContext!="function")throw new Error(`Journey linear transition object at index ${o} must define "updateContext" as a function when provided.`);if(e.onEnter!==void 0&&typeof e.onEnter!="function")throw new Error(`Journey linear transition object at index ${o} must define "onEnter" as a function when provided.`);if(e.onLeave!==void 0&&typeof e.onLeave!="function")throw new Error(`Journey linear transition object at index ${o} must define "onLeave" as a function when provided.`);J(e.timeoutMs,`Journey linear transition object at index ${o}`),i.push({...e.label!==void 0?{label:e.label}:{},...e.timeoutMs!==void 0?{timeoutMs:e.timeoutMs}:{},...e.updateContext!==void 0?{updateContext:e.updateContext}:{},...e.onEnter!==void 0?{onEnter:e.onEnter}:{},...e.onLeave!==void 0?{onLeave:e.onLeave}:{},from:p,event:"goToNextStep",to:e.step}),p=e.step}return{...n,initial:r,transitions:E(i)}}if(!a||typeof a!="object")throw new Error("Journey transitions must be an array or an object map when provided.");let s=a,f=[...Object.entries(s).filter(([t])=>t!=="global"),...s.global?[["global",s.global]]:[]];for(let[t,u]of f){if(t!=="global"&&!(t in n.steps))throw new Error(`Journey transitions reference unknown step "${t}".`);if(!u||typeof u!="object"||Array.isArray(u))throw new Error(`Journey transitions for "${t}" must be an event map object.`);for(let[r,p]of Object.entries(u)){let d=r==="completeJourney"||r==="terminateJourney",c=d&&(p===!0||Array.isArray(p)&&p.length===0)?[{}]:p;if(!Array.isArray(c))throw new Error(`Journey transitions for "${t}.${r}" must be an array.`);for(let[e,o]of c.entries()){if(!o||typeof o!="object")throw new Error(`Journey transition at "${t}.${r}[${e}]" must be an object.`);let T=new Set(d?["when","updateContext","onEnter","onLeave","label","timeoutMs"]:["to","when","updateContext","onEnter","onLeave","label","timeoutMs"]);for(let y of Object.keys(o))if(!T.has(y))throw new Error(`Journey transition at "${t}.${r}[${e}]" contains unsupported field "${y}".`);if(!d&&typeof o.to!="string")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define string "to".`);if(o.when!==void 0&&typeof o.when!="function")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define "when" as a function when provided.`);if(o.updateContext!==void 0&&typeof o.updateContext!="function")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define "updateContext" as a function when provided.`);if(o.onEnter!==void 0&&typeof o.onEnter!="function")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define "onEnter" as a function when provided.`);if(o.onLeave!==void 0&&typeof o.onLeave!="function")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define "onLeave" as a function when provided.`);if(o.label!==void 0&&typeof o.label!="string")throw new Error(`Journey transition at "${t}.${r}[${e}]" must define "label" as a string when provided.`);J(o.timeoutMs,`Journey transition at "${t}.${r}[${e}]"`),i.push({...o,from:t==="global"?"*":t,event:r})}}}return{...n,transitions:E(i)}};var v=(n,i)=>typeof n!="number"||!Number.isFinite(n)?i:Math.max(1,Math.trunc(n));function S(n,i={}){let s=(e=>Array.isArray(e.transitions)&&(e.transitions.length===0||typeof e.transitions[0]=="object"&&e.transitions[0]!==null))(n)?n:g(n),f=v(i.maxDepth,5),t=v(i.maxPaths,10),u=[],r=!1,p=!1,d=e=>{if(u.length>=t){r=!0;return}u.push(e)},c=(e,o,T)=>{if(u.length>=t){r=!0;return}let y=s.transitions.filter(l=>l.from==="*"||l.from===e);if(y.length===0){d({steps:o,events:T,terminated:"final"});return}if(T.length>=f){d({steps:o,events:T,terminated:"depth"}),r=!0;return}for(let l of y){let w=[...T,l.event],x=h(l);if(x==="COMPLETE"||x==="TERMINATED"){d({steps:o,events:w,terminated:"final"});continue}let m=[...o,x];if(o.includes(x)){p=!0,d({steps:m,events:w,terminated:"cycle"});continue}if(c(x,m,w),u.length>=t){r=!0;return}}};return c(s.initial,[s.initial],[]),{paths:u,truncated:r,cyclesDetected:p}}var j=()=>({name:"execution-paths",setup:({resolvedJourney:n})=>({augmentMachine:()=>({getExecutionPaths:i=>S(n,i)})})});export{j as createExecutionPathsPlugin,S as getExecutionPaths};
2
- //# sourceMappingURL=index.js.map