@modular-react/journeys 0.1.0 → 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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { AbandonCtx } from '@modular-react/core';
2
+ import { CatalogMeta } from '@modular-react/core';
3
+ import { ChildOutcome } from '@modular-react/core';
2
4
  import { ComponentType } from 'react';
3
5
  import { EntryInputOf } from '@modular-react/core';
4
6
  import { EntryNamesOf } from '@modular-react/core';
@@ -7,6 +9,8 @@ import { ExitCtx } from '@modular-react/core';
7
9
  import { ExitNamesOf } from '@modular-react/core';
8
10
  import { ExitOutputOf } from '@modular-react/core';
9
11
  import { InstanceId } from '@modular-react/core';
12
+ import { InvokeSpec } from '@modular-react/core';
13
+ import { isJourneySystemAbort } from '@modular-react/core';
10
14
  import { JourneyDefinitionSummary } from '@modular-react/core';
11
15
  import { JourneyHandleRef } from '@modular-react/core';
12
16
  import { JourneyInstance } from '@modular-react/core';
@@ -14,13 +18,20 @@ import { JourneyPersistence } from '@modular-react/core';
14
18
  import { JourneyRuntime } from '@modular-react/core';
15
19
  import { JourneyStatus } from '@modular-react/core';
16
20
  import { JourneyStep } from '@modular-react/core';
21
+ import { JourneySystemAbortReason } from '@modular-react/core';
22
+ import { JourneySystemAbortReasonCode } from '@modular-react/core';
17
23
  import { MaybePromise } from '@modular-react/core';
18
24
  import { ModuleDescriptor } from '@modular-react/core';
19
25
  import { ModuleExitEvent } from '@modular-react/react';
20
26
  import { ModuleTypeMap } from '@modular-react/core';
21
27
  import { NavigationItemBase } from '@modular-react/core';
28
+ import { ParentLink } from '@modular-react/core';
29
+ import { PendingInvoke } from '@modular-react/core';
22
30
  import { ReactNode } from 'react';
23
31
  import { RegistryPlugin } from '@modular-react/core';
32
+ import { ResumeBounceCounter } from '@modular-react/core';
33
+ import { ResumeHandler } from '@modular-react/core';
34
+ import { ResumeMap } from '@modular-react/core';
24
35
  import { SerializedJourney } from '@modular-react/core';
25
36
  import { StepSpec } from '@modular-react/core';
26
37
  import { TerminalCtx } from '@modular-react/core';
@@ -31,13 +42,44 @@ import { TransitionResult } from '@modular-react/core';
31
42
 
32
43
  export { AbandonCtx }
33
44
 
34
- /** Erased shape used by the registry — `any` on the generics lets the
45
+ /**
46
+ * A transition handler with declared `targets` metadata attached. Functionally
47
+ * identical to the bare handler the journey runtime expects — the call
48
+ * signature is preserved verbatim, so the value drops directly into a
49
+ * `transitions[mod][entry][exit]` slot. The host's preloader walks
50
+ * `Object.values(perEntry)` and reads each handler's `.targets` to schedule
51
+ * speculative imports.
52
+ */
53
+ export declare type AnnotatedTransitionHandler<THandler extends (ctx: any) => any, TTargets extends readonly (StepObjectRef | TerminalSentinel)[]> = THandler & {
54
+ readonly targets: TTargets;
55
+ };
56
+
57
+ /** Erased shape used by the registry — `any` on every generic lets the
35
58
  * registry store definitions from different journeys side-by-side.
36
59
  * Tightening to `unknown` breaks variance: `initialState: (input: TInput)
37
60
  * => TState` for a specific journey is not assignable to
38
61
  * `(input: unknown) => unknown` because function parameters are
39
- * contravariant, so the registry would reject any concrete definition. */
40
- export declare type AnyJourneyDefinition = JourneyDefinition<ModuleTypeMap, any, any>;
62
+ * contravariant, so the registry would reject any concrete definition.
63
+ *
64
+ * TModules is also `any` (rather than `ModuleTypeMap`) so the structural
65
+ * variance check on `ResumeMap`/`TransitionMap` does not strictly require
66
+ * the wide form to carry every specific module key — `any` short-circuits
67
+ * the property-by-property check and admits any concrete TModules. */
68
+ export declare type AnyJourneyDefinition = JourneyDefinition<any, any, any, any, any>;
69
+
70
+ export { ChildOutcome }
71
+
72
+ /**
73
+ * Convenience wrapper for ordering two version strings. Returns -1 if `a`
74
+ * sorts before `b`, 1 if after, 0 if equal. Throws {@link SemverParseError}
75
+ * if either input is not a strict `MAJOR.MINOR.PATCH`.
76
+ *
77
+ * Useful for persisted-data compatibility checks: "is the version recorded
78
+ * on this saved blob older than the cutoff at which we changed the on-disk
79
+ * shape?". For matching against a range (`^1.0.0`, `>=1.5 <2`, …) use
80
+ * {@link satisfies} instead.
81
+ */
82
+ export declare function compareVersions(a: string, b: string): number;
41
83
 
42
84
  /**
43
85
  * Create a journey runtime bound to a set of registered journeys. The
@@ -117,34 +159,43 @@ export declare function createWebStoragePersistence<TInput, TState>(options: Web
117
159
  * transitions, and the journey's private state.
118
160
  *
119
161
  * **Why the empty parens?** TypeScript can't partially infer generics: if
120
- * `defineJourney` took `<TModules, TState, TInput>` in a single call, you'd
121
- * either have to spell all three — losing the ability to infer `TInput`
122
- * from `initialState`'s parameter — or spell none, losing the ability to
123
- * narrow `TModules` / `TState`. The two-call shape splits the generics
124
- * so `TModules` + `TState` are explicit (first call) while `TInput` is
125
- * inferred from the definition object (second call).
162
+ * `defineJourney` took `<TModules, TState, TInput, TOutput>` in a single
163
+ * call, you'd either have to spell all four — losing the ability to infer
164
+ * `TInput` from `initialState`'s parameter — or spell none, losing the
165
+ * ability to narrow `TModules` / `TState`. The two-call shape splits the
166
+ * generics so `TModules` + `TState` (+ optional `TOutput`) are explicit
167
+ * (first call) while `TInput` is inferred from the definition object
168
+ * (second call).
126
169
  *
127
170
  * ```ts
128
- * defineJourney<OnboardingModules, OnboardingState>()({
171
+ * defineJourney<OnboardingModules, OnboardingState>()({ ... });
172
+ * defineJourney<OnboardingModules, OnboardingState, { token: string }>()({
129
173
  * id: "customer-onboarding",
130
174
  * version: "1.0.0",
131
175
  * initialState: (input: { customerId: string }) => ({ ... }),
132
- * // TInput is inferred as { customerId: string } here
133
176
  * start: (state) => ({ module: "profile", entry: "review", input: { customerId: state.customerId } }),
134
- * transitions: { ... },
177
+ * transitions: {
178
+ * billing: {
179
+ * collect: {
180
+ * done: ({ output }) => ({ complete: { token: output.token } }),
181
+ * // ^ checked against { token: string }
182
+ * },
183
+ * },
184
+ * },
135
185
  * });
136
186
  * ```
137
187
  *
138
188
  * Zero runtime cost — the definition is returned unchanged.
139
189
  */
140
- export declare const defineJourney: <TModules extends ModuleTypeMap, TState>() => <TInput = void>(definition: JourneyDefinition<TModules, TState, TInput>) => JourneyDefinition<TModules, TState, TInput>;
190
+ export declare const defineJourney: <TModules extends ModuleTypeMap, TState, TOutput = unknown, TMeta extends { [K in keyof TMeta]: unknown; } = Record<string, unknown>>() => <TInput = void>(definition: JourneyDefinition<TModules, TState, TInput, TOutput, CatalogMeta & TMeta>) => JourneyDefinition<TModules, TState, TInput, TOutput, any>;
141
191
 
142
192
  /**
143
193
  * Build a handle from a journey definition. Runtime identity is just
144
194
  * `{ id: def.id }`; the returned object is typed so callers get
145
- * `input`-checking through the `start` overload.
195
+ * `input`-checking through the `start` overload and `outcome.payload`
196
+ * narrowing through a parent journey's resume handler.
146
197
  */
147
- export declare function defineJourneyHandle<TModules extends ModuleTypeMap, TState, TInput>(def: JourneyDefinition<TModules, TState, TInput>): JourneyHandle<string, TInput>;
198
+ export declare function defineJourneyHandle<TModules extends ModuleTypeMap, TState, TInput, TOutput>(def: JourneyDefinition<TModules, TState, TInput, TOutput>): JourneyHandle<string, TInput, TOutput>;
148
199
 
149
200
  /**
150
201
  * Identity helper that ties a persistence adapter's `keyFor` input to a
@@ -175,6 +226,75 @@ export declare function defineJourneyHandle<TModules extends ModuleTypeMap, TSta
175
226
  */
176
227
  export declare function defineJourneyPersistence<TInput, TState>(adapter: JourneyPersistence<TState, TInput>): JourneyPersistence<TState, TInput>;
177
228
 
229
+ /**
230
+ * Wrap a transition handler with a static declaration of every outcome it may
231
+ * take. Two effects:
232
+ *
233
+ * 1. **Runtime — preload precision.** `<JourneyOutlet>`'s default
234
+ * `preload="precise"` mode reads `targets` and warms exactly those
235
+ * entries' chunks during idle time, so navigating Next finds the
236
+ * chunk already cached. Bare-function handlers contribute nothing
237
+ * to precise mode (they fall back to `preload="aggressive"` if set).
238
+ * Sentinel targets (`"complete"`, `"abort"`, `"invoke"`) carry no
239
+ * chunk to preload — they are skipped.
240
+ *
241
+ * 2. **Type-level — the handler's return is constrained to the declared
242
+ * arms.** Declaring `targets: [{ module: "plan", entry: "choose" }]`
243
+ * means the handler may only return `{ next: ... }`; declaring
244
+ * `targets: ["abort"]` means only `{ abort: ... }`; mixing both
245
+ * allows either. Returning an undeclared arm is a compile error.
246
+ *
247
+ * **`targets` is mandatory.** A wrapped handler must enumerate every
248
+ * outcome it may take. If you don't want a declaration, use a bare
249
+ * function — the runtime invocation path is identical, and bare handlers
250
+ * sit out of precise-mode preload.
251
+ *
252
+ * Two call shapes:
253
+ *
254
+ * ```ts
255
+ * // Curried (recommended): bind the journey's generics once, get full
256
+ * // contextual typing on every wrapped handler. Naming convention mirrors
257
+ * // `selectModule` (a descriptive verb for the binder, not an
258
+ * // abbreviation — `tx` reads as "transaction" in most codebases).
259
+ * const transition = defineTransition<OnboardingModules, OnboardingState>();
260
+ *
261
+ * profileComplete: transition({
262
+ * targets: [{ module: "plan", entry: "choose" }],
263
+ * handle: ({ output, state }) => ({
264
+ * state: { ...state, hint: output.hint },
265
+ * next: { module: "plan", entry: "choose", input: ... },
266
+ * }),
267
+ * }),
268
+ *
269
+ * // Mix step refs with sentinels for handlers that branch between
270
+ * // next and a terminal arm:
271
+ * checkout: transition({
272
+ * targets: [{ module: "plan", entry: "choose" }, "abort"],
273
+ * handle: ({ output }) =>
274
+ * output.kind === "ok"
275
+ * ? { next: { module: "plan", entry: "choose", input: ... } }
276
+ * : { abort: { reason: "user-cancelled" } },
277
+ * }),
278
+ *
279
+ * // Bare: zero-config, no contextual narrowing. Targets accept any
280
+ * // `{ module: string; entry: string } | "complete" | "abort" | "invoke"`;
281
+ * // useful for one-off handlers or for journeys whose return literals
282
+ * // are already typed by an outer annotation.
283
+ * cancelled: defineTransition({
284
+ * targets: ["abort"],
285
+ * handle: () => ({ abort: { reason: "user-cancelled" } }),
286
+ * }),
287
+ * ```
288
+ */
289
+ export declare function defineTransition<TModules extends ModuleTypeMap, TState = unknown, TOutput = unknown>(): TypedTransitionBinder<TModules, TState, TOutput>;
290
+
291
+ export declare function defineTransition<THandler extends (ctx: any) => any, const TTargets extends readonly (StepObjectRef | TerminalSentinel)[]>(spec: DefineTransitionSpec<THandler, TTargets>): AnnotatedTransitionHandler<THandler, TTargets>;
292
+
293
+ declare interface DefineTransitionSpec<THandler extends (ctx: any) => any, TTargets extends readonly (StepObjectRef | TerminalSentinel)[]> {
294
+ readonly targets: TTargets;
295
+ readonly handle: THandler;
296
+ }
297
+
178
298
  export { EntryInputOf }
179
299
 
180
300
  export { EntryNamesOf }
@@ -189,6 +309,54 @@ export { ExitOutputOf }
189
309
 
190
310
  export { InstanceId }
191
311
 
312
+ /**
313
+ * Typed builder for the `{ invoke }` arm of `TransitionResult`. The union
314
+ * arm itself declares `InvokeSpec<unknown, unknown>` — bare object literals
315
+ * like `{ invoke: { handle, input, resume } }` therefore won't catch a
316
+ * mismatch between `input` and the handle's `TInput`. Going through this
317
+ * helper threads both `TInput` and `TOutput` from the handle into `input`
318
+ * (which must be assignable) and the returned spec, so authors get
319
+ * end-to-end checking at the call site:
320
+ *
321
+ * ```ts
322
+ * confirmAge: ({ state }) =>
323
+ * invoke({
324
+ * handle: verifyIdentityHandle, // TInput = { customerId: string }
325
+ * input: { customerId: state.id }, // checked against TInput
326
+ * resume: "afterAgeVerified",
327
+ * }),
328
+ * ```
329
+ *
330
+ * The runtime treats the result identically to a hand-built literal — the
331
+ * only purpose is the compile-time check.
332
+ */
333
+ export declare function invoke<TInput, TOutput>(spec: {
334
+ readonly handle: JourneyHandleRef<string, TInput, TOutput>;
335
+ readonly input: TInput;
336
+ readonly resume: string;
337
+ }): {
338
+ readonly invoke: InvokeSpec<TInput, TOutput>;
339
+ };
340
+
341
+ export { InvokeSpec }
342
+
343
+ /**
344
+ * Narrow a value to the annotated form. Used by the auto-preloader to read
345
+ * `targets` from a handler without trusting structural lookups on `unknown`.
346
+ * Each target must be either a `{ module, entry }` string-pair or one of
347
+ * the recognized sentinel strings.
348
+ */
349
+ export declare function isAnnotatedTransition(value: unknown): value is AnnotatedTransitionHandler<(ctx: any) => any, readonly (StepObjectRef | TerminalSentinel)[]>;
350
+
351
+ export { isJourneySystemAbort }
352
+
353
+ /**
354
+ * Narrow a value to one of the recognized {@link TerminalSentinel} strings.
355
+ * Exposed for hosts that introspect a wrapped handler's targets and want to
356
+ * separate step refs from terminal arms without a string-equality dance.
357
+ */
358
+ export declare function isTerminalSentinel(value: unknown): value is TerminalSentinel;
359
+
192
360
  /**
193
361
  * Default shape the journeys plugin emits for each `nav`-carrying journey.
194
362
  * When {@link JourneysPluginOptions.buildNavItem} is provided, the plugin
@@ -218,16 +386,102 @@ export declare interface JourneyDefaultNavItem extends NavigationItemBase {
218
386
  };
219
387
  }
220
388
 
221
- export declare interface JourneyDefinition<TModules extends ModuleTypeMap, TState, TInput = void> {
389
+ export declare interface JourneyDefinition<TModules extends ModuleTypeMap, TState, TInput = void, TOutput = unknown, TMeta extends {
390
+ [K in keyof TMeta]: unknown;
391
+ } = Record<string, unknown>> {
222
392
  readonly id: string;
223
393
  readonly version: string;
224
- readonly meta?: Readonly<Record<string, unknown>>;
394
+ readonly meta?: Readonly<CatalogMeta & TMeta>;
225
395
  readonly initialState: (input: TInput) => TState;
226
396
  readonly start: (state: TState, input: TInput) => StepSpec<TModules>;
227
- readonly transitions: TransitionMap<TModules, TState>;
397
+ readonly transitions: TransitionMap<TModules, TState, TOutput>;
398
+ /**
399
+ * Resume handlers fired when a child journey `invoke`d from a parent
400
+ * step terminates. Keyed by `[moduleId][entryName][resumeName]` — the
401
+ * runtime looks up `resumes[currentMod][currentEntry][invokeSpec.resume]`
402
+ * at child terminal time and applies the result as the parent's next
403
+ * transition. Optional — journeys that never invoke can omit it.
404
+ */
405
+ readonly resumes?: ResumeMap<TModules, TState, TOutput>;
406
+ /**
407
+ * Closed set of journey handles this journey may invoke from any of its
408
+ * transitions (or from a resume that returns `{ invoke }`). Strongly
409
+ * recommended for any journey that uses `invoke`:
410
+ *
411
+ * 1. **Static cycle detection.** When every journey in a registration
412
+ * declares `invokes`, the registry runs a graph-level cycle check
413
+ * at validation time and rejects the registration with a path like
414
+ * `cycle detected: A → B → A` — far easier to diagnose than the
415
+ * runtime `invoke-cycle` abort.
416
+ * 2. **Runtime arrival check.** At invoke time the runtime verifies
417
+ * that the dispatched handle id appears in `invokes`; an unexpected
418
+ * handle aborts the parent with reason `invoke-undeclared-child`,
419
+ * catching dynamic dispatch bugs (a transition that branches on
420
+ * `output` and lands on a handle the author never intended).
421
+ *
422
+ * Omit only when the call set is genuinely dynamic (e.g. a host that
423
+ * receives child handles from a slot contribution at runtime). The
424
+ * runtime cycle / depth / bounce guards still apply in that case;
425
+ * they just no longer have a static graph to cross-check against.
426
+ *
427
+ * Self-loops (a journey listing its own handle) are reported as a
428
+ * cycle — by construction they would also blow the call-stack guard
429
+ * at runtime.
430
+ */
431
+ readonly invokes?: ReadonlyArray<JourneyHandleRef<string, any, any>>;
432
+ /**
433
+ * Expected module version ranges, keyed by the `id` of a module declared
434
+ * in `TModules`. The keys are constrained to that map so a typo in a
435
+ * module id is a compile error rather than a registration-time issue
436
+ * ("requires module 'profil' but it is not registered"). The journeys
437
+ * plugin checks each entry at registry resolve time against the
438
+ * actually-registered module's `version` field; any incompatibility
439
+ * fails assembly with a {@link JourneyValidationError} listing every
440
+ * mismatch at once.
441
+ *
442
+ * **Why declare this even though the journey already references modules
443
+ * by id in `transitions`?** A journey that mixes in a module from another
444
+ * team is implicitly coupled to that module's exit-name and input-shape
445
+ * contract. The id-and-shape match holds today, but a backwards-
446
+ * incompatible bump on the other side ("we renamed the `success` exit
447
+ * to `done`") would otherwise only surface at runtime when the journey
448
+ * actually navigates to that step. Adding a compat declaration moves
449
+ * that failure to startup so an incompatible deployment refuses to come
450
+ * up at all, instead of breaking a single user mid-flow.
451
+ *
452
+ * The range syntax is an npm-style subset: caret, tilde, x-range,
453
+ * comparators, AND, OR, and hyphen — see the README's
454
+ * "Pattern - module compatibility (`moduleCompat`)" section for the
455
+ * exhaustive list. Pre-release tags and build metadata are not
456
+ * supported. Module ids in this map are typed against `TModules` so
457
+ * a typo is a compile error; an entry naming a module that genuinely
458
+ * isn't registered (e.g. via the erased `AnyJourneyDefinition` path)
459
+ * is reported with a dedicated "module not registered" issue.
460
+ *
461
+ * Optional. A journey that omits this field opts out of compatibility
462
+ * enforcement entirely; the existing structural validators
463
+ * (`transitions` referencing real modules / entries / exits) still run.
464
+ *
465
+ * @example
466
+ * ```ts
467
+ * defineJourney<OnboardingModules, OnboardingState>()({
468
+ * id: "onboarding",
469
+ * version: "1.0.0",
470
+ * moduleCompat: {
471
+ * profile: "^1.0.0",
472
+ * billing: "^2.0.0 || ^3.0.0",
473
+ * plan: ">=1.5.0 <2.0.0",
474
+ * },
475
+ * // ...
476
+ * });
477
+ * ```
478
+ */
479
+ readonly moduleCompat?: {
480
+ readonly [K in keyof TModules & string]?: string;
481
+ };
228
482
  readonly onTransition?: (ev: TransitionEvent_2<TModules, TState>) => void;
229
- readonly onAbandon?: (ctx: AbandonCtx<TModules, TState>) => TransitionResult<TModules, TState>;
230
- readonly onComplete?: (ctx: TerminalCtx<TState>, result: unknown) => void;
483
+ readonly onAbandon?: (ctx: AbandonCtx<TModules, TState>) => TransitionResult<TModules, TState, TOutput>;
484
+ readonly onComplete?: (ctx: TerminalCtx<TState>, result: TOutput) => void;
231
485
  readonly onAbort?: (ctx: TerminalCtx<TState>, reason: unknown) => void;
232
486
  readonly onHydrate?: (blob: SerializedJourney<TState>) => SerializedJourney<TState>;
233
487
  }
@@ -236,14 +490,16 @@ export { JourneyDefinitionSummary }
236
490
 
237
491
  /**
238
492
  * Lightweight token a journey exports so modules and shells can open it
239
- * with a typed `input` without pulling in the journey's runtime code.
493
+ * with a typed `input` (and a typed `outcome.payload` when invoked from a
494
+ * parent journey) without pulling in the journey's runtime code.
240
495
  * Structurally identical to `JourneyHandleRef` in `@modular-react/core` —
241
496
  * re-exported here so authors have a single canonical name to import.
242
497
  *
243
- * The `__input` field is phantom: it never holds a value at runtime, it
244
- * only carries the input type for the `start(handle, input)` overload.
498
+ * The `__input` and `__output` fields are phantom: they never hold values
499
+ * at runtime, they only carry types for the `start(handle, input)`
500
+ * overload and a parent journey's resume handler signature.
245
501
  */
246
- export declare type JourneyHandle<TId extends string = string, TInput = unknown> = JourneyHandleRef<TId, TInput>;
502
+ export declare type JourneyHandle<TId extends string = string, TInput = unknown, TOutput = unknown> = JourneyHandleRef<TId, TInput, TOutput>;
247
503
 
248
504
  export declare class JourneyHydrationError extends Error {
249
505
  constructor(message: string, options?: ErrorOptions);
@@ -337,6 +593,19 @@ export declare interface JourneyOutletProps {
337
593
  readonly onStepError?: (err: unknown, ctx: {
338
594
  step: JourneyStep;
339
595
  }) => JourneyStepErrorPolicy;
596
+ /**
597
+ * When `false`, the outlet renders the instance you handed it directly,
598
+ * even if it has a child journey in flight. Set this when you compose
599
+ * two outlets to render parent and child side-by-side or in a modal —
600
+ * the parent outlet stays on the parent's step, and a sibling outlet
601
+ * keyed off `instance.activeChildId` renders the child.
602
+ *
603
+ * When `true` (the default), the outlet walks the active call chain
604
+ * from the supplied `instanceId` down to the leaf and renders the leaf,
605
+ * matching the subroutine intuition: a child takes over the same
606
+ * outlet for the duration of its run.
607
+ */
608
+ readonly leafOnly?: boolean;
340
609
  /**
341
610
  * Cap on `retry` responses before the outlet falls back to `abort`. The
342
611
  * counter increments on every retry from `onStepError` and is never reset,
@@ -355,6 +624,36 @@ export declare interface JourneyOutletProps {
355
624
  * through their own reporting.
356
625
  */
357
626
  readonly errorComponent?: ComponentType<JourneyOutletErrorProps>;
627
+ /**
628
+ * Speculatively prefetch the chunks for entries reachable from the
629
+ * current step during idle time after mount, so the next click finds
630
+ * its bundle hot.
631
+ *
632
+ * `"precise"` (default, alias `true`) — read declared `targets` from
633
+ * `defineTransition({ targets, handle })`-annotated handlers on the
634
+ * current step's transitions. Preload exactly those entries.
635
+ * Bare-function handlers contribute nothing (this is the precise
636
+ * mode's whole point — no guessing).
637
+ *
638
+ * `"aggressive"` — preload every entry that appears as a transition
639
+ * source OR as a declared `target` of any annotated handler in the
640
+ * journey's `transitions` map. The destination-side pass catches
641
+ * terminal-only steps that have no outbound transitions of their
642
+ * own (e.g. a freshly-added receipt screen reachable from `next:`
643
+ * but not yet wired with its own exits). A step reachable only
644
+ * via `definition.start` AND with no outbound transitions of its
645
+ * own is the one remaining static gap — but such a step can only
646
+ * be the current step on first mount (no exits → no advance), and
647
+ * the skip-current logic already excludes it. Useful when handlers
648
+ * are not annotated and the journey is small enough that warming
649
+ * all candidates is cheap.
650
+ *
651
+ * `false` — opt out entirely.
652
+ *
653
+ * Has no effect for eager (`component:`) entries — their import is
654
+ * already resolved. Effects only fire in the browser; SSR is a no-op.
655
+ */
656
+ readonly preload?: boolean | "precise" | "aggressive";
358
657
  }
359
658
 
360
659
  export { JourneyPersistence }
@@ -434,12 +733,16 @@ export declare interface JourneyRegisterOptions<TState = unknown, TInput = unkno
434
733
  */
435
734
  onHydrate?: (blob: SerializedJourney<TState>) => SerializedJourney<TState>;
436
735
  /**
437
- * Fires when a step component throws or a transition handler throws for
438
- * an instance of this journey. Observation-only — the runtime still
439
- * aborts / retries according to the outlet's `onStepError` policy.
736
+ * Fires when a step component throws, a transition handler throws,
737
+ * or an invoke / resume / abandon hook throws. Observation-only — the
738
+ * runtime still aborts / retries according to the outlet's
739
+ * `onStepError` policy. The `phase` discriminator lets telemetry
740
+ * distinguish a component throw (`"step"`) from an invoke/resume
741
+ * control-plane failure or a custom `onAbandon` crash.
440
742
  */
441
743
  onError?: (err: unknown, ctx: {
442
744
  step: JourneyStep | null;
745
+ phase: "step" | "invoke" | "resume" | "abandon";
443
746
  }) => void;
444
747
  /**
445
748
  * Optional. Without it, journeys live in memory only — every
@@ -480,6 +783,58 @@ export declare interface JourneyRegisterOptions<TState = unknown, TInput = unkno
480
783
  * default item into the app's narrowed type.
481
784
  */
482
785
  nav?: JourneyNavContribution<TInput>;
786
+ /**
787
+ * Cap on the depth of an in-flight invoke chain that includes this
788
+ * journey. The depth is the number of *active* journey instances in
789
+ * the chain — a root parent on its own is depth 1, a parent with one
790
+ * in-flight child is depth 2, etc. When an invoke would push depth
791
+ * beyond `maxCallStackDepth`, the parent aborts with reason
792
+ * `invoke-stack-overflow` (the child is never started) and the
793
+ * registration's `onError` fires with `phase: "invoke"`.
794
+ *
795
+ * The runtime resolves the effective limit as the **minimum** of every
796
+ * non-undefined `maxCallStackDepth` across the active chain (ancestors
797
+ * + the new parent + the would-be child's own setting). The most
798
+ * restrictive journey wins, so a cautious utility journey can lower
799
+ * the cap for any flow that includes it without coordinating with the
800
+ * other journeys.
801
+ *
802
+ * Default: `16`. Set lower for journeys whose call graphs are known
803
+ * to be shallow; raise it (carefully) only for genuinely deep
804
+ * compositions. Setting it to `1` blocks `invoke` from this journey
805
+ * outright.
806
+ *
807
+ * `0`, negative, or non-finite values are treated as "no opinion" and
808
+ * fall through to the next journey's setting (or the library default
809
+ * if no journey in the chain expresses an opinion). This matches the
810
+ * `maxHistory` convention so a misconfigured `0` cannot accidentally
811
+ * disable the guard.
812
+ */
813
+ maxCallStackDepth?: number;
814
+ /**
815
+ * Cap on consecutive resume "bounces" at the *same* parent step. A
816
+ * bounce is a resume that returns `{ invoke }` (re-invoking a child
817
+ * instead of advancing the parent's step). The counter increments on
818
+ * every resume that returns `{ invoke }` and resets to zero whenever
819
+ * the parent's step actually advances (`{ next | complete | abort }`
820
+ * from any source). When the counter would exceed
821
+ * `maxResumeBouncesPerStep`, the parent aborts with reason
822
+ * `resume-bounce-limit`; the child whose terminal triggered the
823
+ * over-the-limit bounce is *not* re-invoked.
824
+ *
825
+ * The counter is persisted on the parent's blob (see
826
+ * `SerializedJourney.resumeBouncesAtStep`) so a reload-bounce sequence
827
+ * cannot reset the budget by round-tripping through storage.
828
+ *
829
+ * Default: `8`. Raise it for flows that legitimately retry a sub-flow
830
+ * many times in a row; lower it for paranoia. The check uses the
831
+ * parent's setting only — children do not influence their parent's
832
+ * bounce budget.
833
+ *
834
+ * `0`, negative, or non-finite values fall through to the library
835
+ * default (matches `maxCallStackDepth` and `maxHistory`).
836
+ */
837
+ maxResumeBouncesPerStep?: number;
483
838
  }
484
839
 
485
840
  export { JourneyRuntime }
@@ -530,7 +885,7 @@ export declare interface JourneysPluginExtension {
530
885
  * `options.nav.buildInput` is typed against the journey's input — pass a
531
886
  * typed definition and both are checked end-to-end.
532
887
  */
533
- registerJourney<TModules extends ModuleTypeMap, TState, TInput>(definition: JourneyDefinition<TModules, TState, TInput>, options?: JourneyRegisterOptions<TState, TInput>): void;
888
+ registerJourney<TModules extends ModuleTypeMap, TState, TInput, TOutput = unknown>(definition: JourneyDefinition<TModules, TState, TInput, TOutput>, options?: JourneyRegisterOptions<TState, TInput>): void;
534
889
  }
535
890
 
536
891
  export declare interface JourneysPluginOptions<TNavItem extends NavigationItemBase = JourneyDefaultNavItem> {
@@ -569,6 +924,10 @@ export { JourneyStep }
569
924
 
570
925
  export declare type JourneyStepErrorPolicy = "abort" | "retry" | "ignore";
571
926
 
927
+ export { JourneySystemAbortReason }
928
+
929
+ export { JourneySystemAbortReasonCode }
930
+
572
931
  /**
573
932
  * Aggregated error thrown when one or more registered journeys reference
574
933
  * module ids, entry names, or exit names that do not exist (or that
@@ -662,16 +1021,242 @@ export declare interface ModuleTabProps<TInput = unknown> {
662
1021
 
663
1022
  export { ModuleTypeMap }
664
1023
 
1024
+ /**
1025
+ * Narrow the handler return type to only the arms whose targets are declared.
1026
+ * - `{ module, entry }` in targets → `next:` arm allowed (with `input` typed
1027
+ * against the chosen entry). Multiple refs collapse into one `next:` key
1028
+ * whose value is the union of step specs.
1029
+ * - `"complete"` in targets → `complete:` arm allowed.
1030
+ * - `"abort"` in targets → `abort:` arm allowed.
1031
+ * - `"invoke"` in targets → `invoke:` arm allowed.
1032
+ *
1033
+ * Declaring an arm in targets but never returning it is fine (over-declaring
1034
+ * is conservative for preload). Returning an arm that wasn't declared is a
1035
+ * compile error — the wrapped handler can't drift past the declaration.
1036
+ */
1037
+ declare type NarrowedTransitionResult<TModules extends ModuleTypeMap, TState, TOutput, TTargets extends readonly StepRef<TModules>[]> = (Extract<TTargets[number], StepObjectRef> extends never ? never : {
1038
+ readonly next: StepSpecFromRef<TModules, Extract<TTargets[number], StepObjectRef>>;
1039
+ readonly state?: TState;
1040
+ }) | (Extract<TTargets[number], "complete"> extends never ? never : {
1041
+ readonly complete: TOutput;
1042
+ readonly state?: TState;
1043
+ }) | (Extract<TTargets[number], "abort"> extends never ? never : {
1044
+ readonly abort: unknown;
1045
+ readonly state?: TState;
1046
+ }) | (Extract<TTargets[number], "invoke"> extends never ? never : {
1047
+ readonly invoke: InvokeSpec<unknown, unknown>;
1048
+ readonly state?: TState;
1049
+ });
1050
+
1051
+ export { ParentLink }
1052
+
1053
+ export { PendingInvoke }
1054
+
665
1055
  /** Internal registration record — definition + options kept together. */
666
1056
  export declare interface RegisteredJourney<TState = unknown, TInput = unknown> {
667
1057
  readonly definition: AnyJourneyDefinition;
668
1058
  readonly options: JourneyRegisterOptions<TState, TInput> | undefined;
669
1059
  }
670
1060
 
1061
+ export { ResumeBounceCounter }
1062
+
1063
+ export { ResumeHandler }
1064
+
1065
+ export { ResumeMap }
1066
+
1067
+ /**
1068
+ * Convenience wrapper that parses both inputs and runs satisfaction. Use
1069
+ * this for one-shot checks; for hot loops, parse once and pass the cached
1070
+ * {@link ParsedRange} to {@link satisfiesParsed}.
1071
+ */
1072
+ export declare function satisfies(version: string, range: string): boolean;
1073
+
1074
+ /**
1075
+ * Curried helper for state-driven module dispatch in a transition handler.
1076
+ *
1077
+ * `selectModule<TModules>()` binds the journey's module map; the inner call
1078
+ * takes a discriminator (`key`) whose value names the next module and a
1079
+ * cases object that supplies the entry + input for each branch. Returns a
1080
+ * `StepSpec` ready to drop into `{ next }`.
1081
+ *
1082
+ * **Why curry on `TModules`?** Same partial-inference reason as
1083
+ * `defineJourney`: TypeScript can't infer `TKey` while we're also forcing
1084
+ * `TModules` to be specified — splitting the calls lets us spell the module
1085
+ * map once and let the discriminator's union flow naturally into `TKey`.
1086
+ *
1087
+ * **Exhaustive by design.** The cases object is `Record<TKey, …>`, so when
1088
+ * `key` is a union literal (`"github" | "strapi" | "contentful"`),
1089
+ * forgetting a branch is a compile error. When you want a default-everything
1090
+ * fallback instead of branch-by-branch coverage, use
1091
+ * {@link selectModuleOrDefault}.
1092
+ *
1093
+ * **What you get:**
1094
+ * - **Per-branch input checking** — each case's `entry` and `input` are
1095
+ * typed against the module the branch dispatches to. You can't paste a
1096
+ * `strapi`-shaped input under the `github` key.
1097
+ * - **One state-spread instead of N** — call sites no longer repeat
1098
+ * `{ state, next: { … } }` per branch.
1099
+ *
1100
+ * **Limit:** the discriminator key must equal the target module id. When
1101
+ * the discriminator differs from the id (e.g. `tier: "free" | "paid"`
1102
+ * dispatching to module ids `trial-onboarding` / `billing-onboarding`),
1103
+ * fall back to a `switch` returning `next` per branch — that case isn't
1104
+ * common enough yet to justify a second helper.
1105
+ *
1106
+ * @example
1107
+ * ```ts
1108
+ * import { selectModule } from "@modular-react/journeys";
1109
+ *
1110
+ * const select = selectModule<IntegrationModules>();
1111
+ *
1112
+ * chosen: ({ output, state }) => ({
1113
+ * state: { ...state, selected: output.kind },
1114
+ * next: select(output.kind, {
1115
+ * github: { entry: "configure", input: { workspaceId: state.workspaceId } },
1116
+ * strapi: { entry: "configure", input: { workspaceId: state.workspaceId } },
1117
+ * contentful: { entry: "configure", input: { workspaceId: state.workspaceId } },
1118
+ * }),
1119
+ * }),
1120
+ * ```
1121
+ *
1122
+ * Zero runtime cost beyond an object lookup.
1123
+ */
1124
+ export declare const selectModule: <TModules extends ModuleTypeMap>() => <TKey extends keyof TModules & string>(key: TKey, cases: SelectModuleCases<TModules, TKey>) => StepSpec<TModules>;
1125
+
1126
+ /**
1127
+ * Cases map for the exhaustive form `selectModule(key, cases)` — one case
1128
+ * per discriminator value. Each case's `entry` is narrowed against that
1129
+ * module's `entryPoints`; `input` is checked against that entry. Missing a
1130
+ * key is a compile error, so a journey gains exhaustiveness for free when
1131
+ * the discriminator is a union literal.
1132
+ */
1133
+ export declare type SelectModuleCases<TModules extends ModuleTypeMap, TKey extends keyof TModules & string> = {
1134
+ readonly [M in TKey]: StepCaseFor<TModules, M>;
1135
+ };
1136
+
1137
+ /**
1138
+ * Cases map for the fallback form `selectModuleOrDefault(key, cases,
1139
+ * fallback)`. Every case is optional and any discriminator value not
1140
+ * present in `cases` falls through to the explicit fallback `StepSpec`.
1141
+ * `TKey` is intentionally widened to `string` so callers can pass a
1142
+ * discriminator that includes values outside the module map (the fallback
1143
+ * handles them).
1144
+ *
1145
+ * Keys are constrained to `Extract<TKey, keyof TModules>` so a typo on a
1146
+ * module id still errors — the looseness is only on TKey itself, not on
1147
+ * which module ids the cases object accepts.
1148
+ */
1149
+ export declare type SelectModuleCasesPartial<TModules extends ModuleTypeMap, TKey extends string> = {
1150
+ readonly [M in Extract<TKey, keyof TModules & string>]?: StepCaseFor<TModules, M>;
1151
+ };
1152
+
1153
+ /**
1154
+ * Sibling of {@link selectModule} that allows partial cases plus an
1155
+ * explicit fallback `StepSpec`. Use when most discriminator values funnel
1156
+ * into a generic module and only a few warrant their own specific
1157
+ * dispatch.
1158
+ *
1159
+ * Kept as a separate function (rather than a third argument on
1160
+ * `selectModule`) so that the *exhaustive* call site is visually
1161
+ * distinct from the *fallback-allowed* one — losing exhaustiveness in
1162
+ * `selectModule` by accidentally adding a third argument later would
1163
+ * silently disable the missing-branch compile error.
1164
+ *
1165
+ * The cases object is `Partial<Record<TKey, …>>`; any discriminator value
1166
+ * not present uses `fallback`. The fallback is a full `StepSpec`
1167
+ * (carrying its own `module`) since it isn't keyed by the discriminator.
1168
+ *
1169
+ * @example
1170
+ * ```ts
1171
+ * import { selectModuleOrDefault } from "@modular-react/journeys";
1172
+ *
1173
+ * const select = selectModuleOrDefault<IntegrationModules>();
1174
+ *
1175
+ * chosen: ({ output, state }) => ({
1176
+ * state: { ...state, selected: output.kind },
1177
+ * next: select(
1178
+ * output.kind,
1179
+ * {
1180
+ * github: { entry: "configure", input: { workspaceId: state.workspaceId, repo: output.repo } },
1181
+ * },
1182
+ * { module: "generic", entry: "configure", input: { workspaceId: state.workspaceId, kind: output.kind } },
1183
+ * ),
1184
+ * }),
1185
+ * ```
1186
+ */
1187
+ export declare const selectModuleOrDefault: <TModules extends ModuleTypeMap>() => <TKey extends string>(key: TKey, cases: SelectModuleCasesPartial<TModules, TKey>, fallback: StepSpec<TModules>) => StepSpec<TModules>;
1188
+
1189
+ export declare class SemverParseError extends Error {
1190
+ constructor(message: string);
1191
+ }
1192
+
671
1193
  export { SerializedJourney }
672
1194
 
1195
+ /**
1196
+ * One case in a `selectModule` map: an entry name on module `M` plus the
1197
+ * matching input shape. The mapped object union is collapsed via the
1198
+ * indexed-access trick at the end so the resulting type is a discriminated
1199
+ * union over the module's entries (the same shape `StepSpec` uses).
1200
+ */
1201
+ declare type StepCaseFor<TModules extends ModuleTypeMap, M extends keyof TModules & string> = {
1202
+ [E in EntryNamesOf<TModules[M]> & string]: {
1203
+ readonly entry: E;
1204
+ readonly input: EntryInputOf<TModules[M], E>;
1205
+ };
1206
+ }[EntryNamesOf<TModules[M]> & string];
1207
+
1208
+ /**
1209
+ * Type predicate that splits a `StepRef` into its step-ref vs sentinel arms.
1210
+ * Object refs land in the `next:` arm; sentinels gate the terminal arms.
1211
+ */
1212
+ declare type StepObjectRef = {
1213
+ readonly module: string;
1214
+ readonly entry: string;
1215
+ };
1216
+
1217
+ /**
1218
+ * Reference to one possible outcome of a transition handler. Used by
1219
+ * {@link defineTransition} to declare every branch the handler may take;
1220
+ * the host's auto-preloader reads the `{ module, entry }` entries to warm
1221
+ * chunks for next-step candidates from the current step, and the catalog
1222
+ * harvester reads the sentinels to derive `aborts` / `completes` flags
1223
+ * without an AST walk over the handler body.
1224
+ *
1225
+ * The `{ module, entry }` shape mirrors the `next:` field handlers return —
1226
+ * a step ref is just `StepSpec` without the runtime-computed `input` —
1227
+ * so authors don't flip between two notations for the same idea.
1228
+ *
1229
+ * When `TModules` is bound (via the curried `defineTransition<TModules>()`
1230
+ * binder), `module` narrows to `keyof TModules` and `entry` narrows to that
1231
+ * module's `entryPoints` keys.
1232
+ */
1233
+ export declare type StepRef<TModules extends ModuleTypeMap> = {
1234
+ [M in keyof TModules & string]: {
1235
+ [E in EntryNamesOf<TModules[M]> & string]: {
1236
+ readonly module: M;
1237
+ readonly entry: E;
1238
+ };
1239
+ }[EntryNamesOf<TModules[M]> & string];
1240
+ }[keyof TModules & string] | TerminalSentinel;
1241
+
673
1242
  export { StepSpec }
674
1243
 
1244
+ /**
1245
+ * Build the `next.{ module, entry, input }` shape for one declared step ref.
1246
+ * Distributes over a union of refs so multiple targets produce a union of
1247
+ * step specs under a single `next:` key (rather than separate `{ next: A }`
1248
+ * vs `{ next: B }` arms — the latter would reject conditional handler
1249
+ * returns like `next: cond ? planRef : billingRef`).
1250
+ */
1251
+ declare type StepSpecFromRef<TModules extends ModuleTypeMap, TRef> = TRef extends {
1252
+ readonly module: infer M;
1253
+ readonly entry: infer E;
1254
+ } ? M extends keyof TModules & string ? E extends EntryNamesOf<TModules[M]> & string ? {
1255
+ readonly module: M;
1256
+ readonly entry: E;
1257
+ readonly input: EntryInputOf<TModules[M], E>;
1258
+ } : never : never : never;
1259
+
675
1260
  /**
676
1261
  * Narrowed variant of {@link JourneyPersistence} whose methods are
677
1262
  * guaranteed synchronous — `load` returns `SerializedJourney<TState> | null`
@@ -698,12 +1283,42 @@ export { TerminalCtx }
698
1283
 
699
1284
  export { TerminalOutcome }
700
1285
 
1286
+ /**
1287
+ * Sentinel value declaring a non-`next` outcome on a wrapped transition
1288
+ * handler. Mixed into the `targets:` array alongside `{ module, entry }`
1289
+ * step refs so a single declaration captures every branch the handler
1290
+ * may take.
1291
+ *
1292
+ * - `"complete"` — handler may return `{ complete: ... }` (terminates).
1293
+ * - `"abort"` — handler may return `{ abort: ... }` (terminates with abort).
1294
+ * - `"invoke"` — handler may return `{ invoke: { handle, input, resume } }`
1295
+ * (suspends the parent, runs a child journey). The specific handle is
1296
+ * not type-narrowed here — the journey definition's `invokes` field
1297
+ * remains the closed-set declaration the runtime cycle / undeclared-
1298
+ * child guards check against.
1299
+ */
1300
+ export declare type TerminalSentinel = "complete" | "abort" | "invoke";
1301
+
701
1302
  export { TransitionEvent_2 as TransitionEvent }
702
1303
 
703
1304
  export { TransitionMap }
704
1305
 
705
1306
  export { TransitionResult }
706
1307
 
1308
+ /**
1309
+ * Curried binder used by {@link defineTransition} to thread the journey's
1310
+ * `TModules` / `TState` / `TOutput` into the handler's contextual return
1311
+ * type — `next.module` / `next.entry` and the choice of arms (`next` vs
1312
+ * `complete` vs `abort` vs `invoke`) check against the bound generics
1313
+ * instead of widening to plain `string` / accepting any arm.
1314
+ */
1315
+ declare interface TypedTransitionBinder<TModules extends ModuleTypeMap, TState, TOutput> {
1316
+ <const TTargets extends readonly StepRef<TModules>[], TEntryInput = unknown, TExitOutput = unknown>(spec: {
1317
+ readonly targets: TTargets;
1318
+ readonly handle: (ctx: ExitCtx<TState, TExitOutput, TEntryInput>) => NarrowedTransitionResult<TModules, TState, TOutput, TTargets>;
1319
+ }): AnnotatedTransitionHandler<(ctx: ExitCtx<TState, TExitOutput, TEntryInput>) => TransitionResult<TModules, TState, TOutput>, TTargets>;
1320
+ }
1321
+
707
1322
  /**
708
1323
  * Thrown when `runtime.start()` / `runtime.hydrate()` is called with a
709
1324
  * journey id that is not registered. Distinct class so shells can
@@ -715,6 +1330,19 @@ export declare class UnknownJourneyError extends Error {
715
1330
  constructor(journeyId: string, registered: readonly string[]);
716
1331
  }
717
1332
 
1333
+ /**
1334
+ * Returns the call stack for an outlet's instance — root at index 0, the
1335
+ * active leaf at the end, intermediate parents in between. Useful for
1336
+ * shells that render layered presentations (e.g. parent visible
1337
+ * underneath, child in a modal): mount the parent outlet with
1338
+ * `leafOnly={false}` and the child outlet against `chain[chain.length - 1]`.
1339
+ *
1340
+ * Subscribes to every instance in the chain so the array re-resolves
1341
+ * when the chain shifts. Length is at least 1 (the root) for any
1342
+ * registered instance.
1343
+ */
1344
+ export declare function useJourneyCallStack(runtime: JourneyRuntime, rootId: InstanceId): readonly InstanceId[];
1345
+
718
1346
  /** Read the current provider value, or `null` when none is mounted. */
719
1347
  export declare function useJourneyContext(): JourneyProviderValue | null;
720
1348
 
@@ -727,6 +1355,36 @@ export declare function validateJourneyContracts(journeys: readonly RegisteredJo
727
1355
  */
728
1356
  export declare function validateJourneyDefinition(def: AnyJourneyDefinition): readonly string[];
729
1357
 
1358
+ /**
1359
+ * Verify the directed graph of journey-to-journey invocations, derived
1360
+ * from each registered journey's `invokes` declaration, contains no
1361
+ * cycles. A cycle in the static graph would, at runtime, manifest as
1362
+ * either an infinite chain (depth-limited by `maxCallStackDepth`) or a
1363
+ * same-id-on-stack abort — both are recoverable but late. The graph
1364
+ * check turns the same mistake into a registration-time error citing
1365
+ * the cycle path.
1366
+ *
1367
+ * Run automatically as part of {@link validateJourneyContracts}. Exposed
1368
+ * separately so shells that compose registrations (e.g. plugin chaining)
1369
+ * can run the graph check on a partial slice without invoking the full
1370
+ * contracts validator. Throws {@link JourneyValidationError} when one or
1371
+ * more cycles are detected.
1372
+ *
1373
+ * **What's checked.** The graph only spans journeys whose `invokes`
1374
+ * field is declared as an array. Edges to journey ids that are not
1375
+ * present in `journeys` are ignored — those will fail at runtime with
1376
+ * `invoke-unknown-journey`, not as cycle reports. Self-loops (a journey
1377
+ * that lists its own handle) are reported as a one-cycle.
1378
+ *
1379
+ * **What's NOT checked.** Journeys that omit `invokes` contribute no
1380
+ * edges; a cycle that runs through such a journey will not be caught
1381
+ * statically, and the runtime guards (`invoke-cycle`,
1382
+ * `invoke-stack-overflow`) remain the safety net. Authors who want
1383
+ * full static coverage should declare `invokes` on every journey that
1384
+ * uses `invoke()`.
1385
+ */
1386
+ export declare function validateJourneyGraph(journeys: readonly RegisteredJourney[]): void;
1387
+
730
1388
  export declare interface WebStoragePersistenceOptions<TInput> {
731
1389
  /**
732
1390
  * Compute the persistence key from the journey id and starting input.