jssm 5.162.34 → 5.162.35

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/jssm.es5.d.cts CHANGED
@@ -3576,6 +3576,57 @@ declare class Machine<mDT> {
3576
3576
  * @returns `true` if removed, `false` if no match was registered.
3577
3577
  */
3578
3578
  off<Ev extends JssmEventName>(name: Ev, handler: JssmEventHandler<mDT, Ev>): boolean;
3579
+ /**
3580
+ * Invoke a single event-handler entry, respecting its filter, once-removal
3581
+ * semantics, and the error re-fire / recursion-guard logic. Extracted so
3582
+ * {@link _fire} can share identical behavior between the size-1 fast-path
3583
+ * and the general snapshotted loop.
3584
+ * @param entry - The subscriber descriptor to invoke.
3585
+ * @param set - The live Set that owns `entry`; needed for once-removal.
3586
+ * @param name - The event name being dispatched (used in error re-fires).
3587
+ * @param detail - The event payload forwarded to the handler.
3588
+ * @internal
3589
+ */
3590
+ _fire_one<Ev extends JssmEventName>(entry: JssmEventEntry<mDT, Ev>, set: Set<JssmEventEntry<any, any>>, name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
3591
+ /**
3592
+ * Dispatch an event to every registered subscriber in registration
3593
+ * order. Filters are checked first; non-matching handlers are skipped
3594
+ * without invoking the handler. Exceptions thrown by a handler are
3595
+ * caught and re-emitted as an `error` event so subsequent handlers
3596
+ * still run.
3597
+ *
3598
+ * Re-entry into the `error` event itself is guarded — if an `error`
3599
+ * handler throws, the new exception is swallowed rather than rebroadcast
3600
+ * to avoid an infinite loop.
3601
+ *
3602
+ * When exactly one subscriber is registered the common case avoids the
3603
+ * `Array.from(set)` snapshot allocation by capturing the lone entry into a
3604
+ * local first — equivalent to a 1-element snapshot but allocation-free.
3605
+ * The general path still snapshots for re-entrancy safety.
3606
+ * @internal
3607
+ */
3608
+ /**
3609
+ * Whether at least one live subscriber is registered for `name`. Used by
3610
+ * the transition-commit observation block to skip building a detail
3611
+ * literal that {@link Machine._fire} would immediately discard — a panel
3612
+ * listening only to `'transition'` (fsl-bind, fsl-viz, fsl-info-panel)
3613
+ * previously paid for the exit/entry/data-change detail allocations on
3614
+ * every transition. Read at fire time, so a listener installed by a
3615
+ * pre-hook is still seen (#671).
3616
+ * @param name The event name to probe.
3617
+ * @returns `true` when a subsequent `_fire(name, ...)` would reach at
3618
+ * least one handler.
3619
+ *
3620
+ * ```typescript
3621
+ * machine.on('transition', () => {});
3622
+ * machine._has_subscribers('transition'); // true
3623
+ * machine._has_subscribers('exit'); // false
3624
+ * ```
3625
+ * @see Machine._fire
3626
+ * @internal
3627
+ */
3628
+ _has_subscribers(name: JssmEventName): boolean;
3629
+ _fire<Ev extends JssmEventName>(name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
3579
3630
  set_hook(HookDesc: HookDescription<mDT>): void;
3580
3631
  /**
3581
3632
  * Remove a previously-registered hook described by a
@@ -3916,6 +3967,81 @@ declare class Machine<mDT> {
3916
3967
  *
3917
3968
  */
3918
3969
  override(newState: StateType, newData?: mDT): void;
3970
+ /*********
3971
+ *
3972
+ * Fire a `'rejection'` event caused by a hook vetoing a pending transition.
3973
+ * Extracted from the per-call closures inside {@link transition_impl} so
3974
+ * that it is allocated once at class-definition time rather than on every
3975
+ * hooked transition.
3976
+ *
3977
+ * @param hook_name Name of the hook that rejected (e.g. `'exit'`).
3978
+ * @param fromState State the machine was in when the transition was
3979
+ * attempted; used as the `from` field of the rejection event.
3980
+ * @param newState State that would have been entered had the hook
3981
+ * passed; used as the `to` field of the rejection event.
3982
+ * @param fromAction Action name when the transition was initiated by an
3983
+ * action call; `undefined` for plain state transitions.
3984
+ * @param oldData Machine data at the moment the transition was
3985
+ * attempted, before any hook mutations.
3986
+ * @param newData The `next_data` value passed to the transition call.
3987
+ * @param wasForced Whether the transition was attempted via
3988
+ * `force_transition`.
3989
+ *
3990
+ * @see transition_impl
3991
+ * @see _fire
3992
+ *
3993
+ * @internal
3994
+ *
3995
+ */
3996
+ _fire_hook_rejection(hook_name: string, fromState: StateType, newState: StateType, fromAction: StateType | undefined, oldData: mDT, newData: mDT | undefined, wasForced: boolean): void;
3997
+ /*********
3998
+ *
3999
+ * Fire the FSL boundary-hook actions for a single, already-committed state
4000
+ * change. In FSL, `do` is a synonym for `action`, so `on enter &g do 'X';`
4001
+ * means "when the machine crosses INTO group `g`, dispatch machine action
4002
+ * `X`" — and likewise `on exit` / plain-state subjects. This is the runtime
4003
+ * that fires those parked hooks.
4004
+ *
4005
+ * Crossing semantics (statechart convention — exits before enters):
4006
+ *
4007
+ * 1. `prev_groups` / `next_groups` are the deep (transitive) group sets of
4008
+ * the old and new states, from `_state_to_groups`.
4009
+ * 2. **Exits** fire first: every group in `prev_groups \ next_groups` with an
4010
+ * `onExit`, plus the plain `prev_state`'s `onExit` (when the state name
4011
+ * actually changed).
4012
+ * 3. **Enters** fire next: every group in `next_groups \ prev_groups` with an
4013
+ * `onEnter`, plus the plain `next_state`'s `onEnter` (when the state name
4014
+ * changed).
4015
+ * 4. A group present in BOTH sets is a transition *within* that group and
4016
+ * fires neither of its boundary hooks. `prev_state === next_state` fires
4017
+ * nothing at all.
4018
+ * 5. "Fire its action" is `this.action(label)`. If that action is not valid
4019
+ * from the current state, `action` is a safe no-op (returns `false`) — an
4020
+ * inapplicable boundary action never throws.
4021
+ * 6. Multi-membership and nesting both fan out naturally: a state in groups
4022
+ * A and B fires both; crossing an inner and an outer boundary fires both
4023
+ * levels.
4024
+ *
4025
+ * Because firing an action can drive a further transition (which crosses
4026
+ * more boundaries, which fires more actions), this is a bounded
4027
+ * run-to-completion: `_boundary_depth` tracks the live cascade depth and a
4028
+ * cascade deeper than `_boundary_depth_limit` throws a {@link JssmError}
4029
+ * rather than overflowing the stack or hanging. The limit defaults to 100
4030
+ * and is configurable via the `boundary_depth_limit` constructor option.
4031
+ *
4032
+ * @param prev_state The state the machine was in before this commit.
4033
+ * @param next_state The state the machine is in now (already committed).
4034
+ *
4035
+ * @throws {JssmError} If cascaded boundary firing exceeds `_boundary_depth_limit`
4036
+ * (a probable infinite loop).
4037
+ *
4038
+ * @see action
4039
+ * @see transition_impl
4040
+ *
4041
+ * @internal
4042
+ *
4043
+ */
4044
+ _fire_boundary_actions(prev_state: StateType, next_state: StateType): void;
3919
4045
  /*********
3920
4046
  *
3921
4047
  * Shared transition core used by {@link transition}, {@link force_transition},
package/jssm.es6.d.ts CHANGED
@@ -3576,6 +3576,57 @@ declare class Machine<mDT> {
3576
3576
  * @returns `true` if removed, `false` if no match was registered.
3577
3577
  */
3578
3578
  off<Ev extends JssmEventName>(name: Ev, handler: JssmEventHandler<mDT, Ev>): boolean;
3579
+ /**
3580
+ * Invoke a single event-handler entry, respecting its filter, once-removal
3581
+ * semantics, and the error re-fire / recursion-guard logic. Extracted so
3582
+ * {@link _fire} can share identical behavior between the size-1 fast-path
3583
+ * and the general snapshotted loop.
3584
+ * @param entry - The subscriber descriptor to invoke.
3585
+ * @param set - The live Set that owns `entry`; needed for once-removal.
3586
+ * @param name - The event name being dispatched (used in error re-fires).
3587
+ * @param detail - The event payload forwarded to the handler.
3588
+ * @internal
3589
+ */
3590
+ _fire_one<Ev extends JssmEventName>(entry: JssmEventEntry<mDT, Ev>, set: Set<JssmEventEntry<any, any>>, name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
3591
+ /**
3592
+ * Dispatch an event to every registered subscriber in registration
3593
+ * order. Filters are checked first; non-matching handlers are skipped
3594
+ * without invoking the handler. Exceptions thrown by a handler are
3595
+ * caught and re-emitted as an `error` event so subsequent handlers
3596
+ * still run.
3597
+ *
3598
+ * Re-entry into the `error` event itself is guarded — if an `error`
3599
+ * handler throws, the new exception is swallowed rather than rebroadcast
3600
+ * to avoid an infinite loop.
3601
+ *
3602
+ * When exactly one subscriber is registered the common case avoids the
3603
+ * `Array.from(set)` snapshot allocation by capturing the lone entry into a
3604
+ * local first — equivalent to a 1-element snapshot but allocation-free.
3605
+ * The general path still snapshots for re-entrancy safety.
3606
+ * @internal
3607
+ */
3608
+ /**
3609
+ * Whether at least one live subscriber is registered for `name`. Used by
3610
+ * the transition-commit observation block to skip building a detail
3611
+ * literal that {@link Machine._fire} would immediately discard — a panel
3612
+ * listening only to `'transition'` (fsl-bind, fsl-viz, fsl-info-panel)
3613
+ * previously paid for the exit/entry/data-change detail allocations on
3614
+ * every transition. Read at fire time, so a listener installed by a
3615
+ * pre-hook is still seen (#671).
3616
+ * @param name The event name to probe.
3617
+ * @returns `true` when a subsequent `_fire(name, ...)` would reach at
3618
+ * least one handler.
3619
+ *
3620
+ * ```typescript
3621
+ * machine.on('transition', () => {});
3622
+ * machine._has_subscribers('transition'); // true
3623
+ * machine._has_subscribers('exit'); // false
3624
+ * ```
3625
+ * @see Machine._fire
3626
+ * @internal
3627
+ */
3628
+ _has_subscribers(name: JssmEventName): boolean;
3629
+ _fire<Ev extends JssmEventName>(name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
3579
3630
  set_hook(HookDesc: HookDescription<mDT>): void;
3580
3631
  /**
3581
3632
  * Remove a previously-registered hook described by a
@@ -3916,6 +3967,81 @@ declare class Machine<mDT> {
3916
3967
  *
3917
3968
  */
3918
3969
  override(newState: StateType, newData?: mDT): void;
3970
+ /*********
3971
+ *
3972
+ * Fire a `'rejection'` event caused by a hook vetoing a pending transition.
3973
+ * Extracted from the per-call closures inside {@link transition_impl} so
3974
+ * that it is allocated once at class-definition time rather than on every
3975
+ * hooked transition.
3976
+ *
3977
+ * @param hook_name Name of the hook that rejected (e.g. `'exit'`).
3978
+ * @param fromState State the machine was in when the transition was
3979
+ * attempted; used as the `from` field of the rejection event.
3980
+ * @param newState State that would have been entered had the hook
3981
+ * passed; used as the `to` field of the rejection event.
3982
+ * @param fromAction Action name when the transition was initiated by an
3983
+ * action call; `undefined` for plain state transitions.
3984
+ * @param oldData Machine data at the moment the transition was
3985
+ * attempted, before any hook mutations.
3986
+ * @param newData The `next_data` value passed to the transition call.
3987
+ * @param wasForced Whether the transition was attempted via
3988
+ * `force_transition`.
3989
+ *
3990
+ * @see transition_impl
3991
+ * @see _fire
3992
+ *
3993
+ * @internal
3994
+ *
3995
+ */
3996
+ _fire_hook_rejection(hook_name: string, fromState: StateType, newState: StateType, fromAction: StateType | undefined, oldData: mDT, newData: mDT | undefined, wasForced: boolean): void;
3997
+ /*********
3998
+ *
3999
+ * Fire the FSL boundary-hook actions for a single, already-committed state
4000
+ * change. In FSL, `do` is a synonym for `action`, so `on enter &g do 'X';`
4001
+ * means "when the machine crosses INTO group `g`, dispatch machine action
4002
+ * `X`" — and likewise `on exit` / plain-state subjects. This is the runtime
4003
+ * that fires those parked hooks.
4004
+ *
4005
+ * Crossing semantics (statechart convention — exits before enters):
4006
+ *
4007
+ * 1. `prev_groups` / `next_groups` are the deep (transitive) group sets of
4008
+ * the old and new states, from `_state_to_groups`.
4009
+ * 2. **Exits** fire first: every group in `prev_groups \ next_groups` with an
4010
+ * `onExit`, plus the plain `prev_state`'s `onExit` (when the state name
4011
+ * actually changed).
4012
+ * 3. **Enters** fire next: every group in `next_groups \ prev_groups` with an
4013
+ * `onEnter`, plus the plain `next_state`'s `onEnter` (when the state name
4014
+ * changed).
4015
+ * 4. A group present in BOTH sets is a transition *within* that group and
4016
+ * fires neither of its boundary hooks. `prev_state === next_state` fires
4017
+ * nothing at all.
4018
+ * 5. "Fire its action" is `this.action(label)`. If that action is not valid
4019
+ * from the current state, `action` is a safe no-op (returns `false`) — an
4020
+ * inapplicable boundary action never throws.
4021
+ * 6. Multi-membership and nesting both fan out naturally: a state in groups
4022
+ * A and B fires both; crossing an inner and an outer boundary fires both
4023
+ * levels.
4024
+ *
4025
+ * Because firing an action can drive a further transition (which crosses
4026
+ * more boundaries, which fires more actions), this is a bounded
4027
+ * run-to-completion: `_boundary_depth` tracks the live cascade depth and a
4028
+ * cascade deeper than `_boundary_depth_limit` throws a {@link JssmError}
4029
+ * rather than overflowing the stack or hanging. The limit defaults to 100
4030
+ * and is configurable via the `boundary_depth_limit` constructor option.
4031
+ *
4032
+ * @param prev_state The state the machine was in before this commit.
4033
+ * @param next_state The state the machine is in now (already committed).
4034
+ *
4035
+ * @throws {JssmError} If cascaded boundary firing exceeds `_boundary_depth_limit`
4036
+ * (a probable infinite loop).
4037
+ *
4038
+ * @see action
4039
+ * @see transition_impl
4040
+ *
4041
+ * @internal
4042
+ *
4043
+ */
4044
+ _fire_boundary_actions(prev_state: StateType, next_state: StateType): void;
3919
4045
  /*********
3920
4046
  *
3921
4047
  * Shared transition core used by {@link transition}, {@link force_transition},
package/jssm.fence.d.ts CHANGED
@@ -2846,6 +2846,57 @@ declare class Machine<mDT> {
2846
2846
  * @returns `true` if removed, `false` if no match was registered.
2847
2847
  */
2848
2848
  off<Ev extends JssmEventName>(name: Ev, handler: JssmEventHandler<mDT, Ev>): boolean;
2849
+ /**
2850
+ * Invoke a single event-handler entry, respecting its filter, once-removal
2851
+ * semantics, and the error re-fire / recursion-guard logic. Extracted so
2852
+ * {@link _fire} can share identical behavior between the size-1 fast-path
2853
+ * and the general snapshotted loop.
2854
+ * @param entry - The subscriber descriptor to invoke.
2855
+ * @param set - The live Set that owns `entry`; needed for once-removal.
2856
+ * @param name - The event name being dispatched (used in error re-fires).
2857
+ * @param detail - The event payload forwarded to the handler.
2858
+ * @internal
2859
+ */
2860
+ _fire_one<Ev extends JssmEventName>(entry: JssmEventEntry<mDT, Ev>, set: Set<JssmEventEntry<any, any>>, name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
2861
+ /**
2862
+ * Dispatch an event to every registered subscriber in registration
2863
+ * order. Filters are checked first; non-matching handlers are skipped
2864
+ * without invoking the handler. Exceptions thrown by a handler are
2865
+ * caught and re-emitted as an `error` event so subsequent handlers
2866
+ * still run.
2867
+ *
2868
+ * Re-entry into the `error` event itself is guarded — if an `error`
2869
+ * handler throws, the new exception is swallowed rather than rebroadcast
2870
+ * to avoid an infinite loop.
2871
+ *
2872
+ * When exactly one subscriber is registered the common case avoids the
2873
+ * `Array.from(set)` snapshot allocation by capturing the lone entry into a
2874
+ * local first — equivalent to a 1-element snapshot but allocation-free.
2875
+ * The general path still snapshots for re-entrancy safety.
2876
+ * @internal
2877
+ */
2878
+ /**
2879
+ * Whether at least one live subscriber is registered for `name`. Used by
2880
+ * the transition-commit observation block to skip building a detail
2881
+ * literal that {@link Machine._fire} would immediately discard — a panel
2882
+ * listening only to `'transition'` (fsl-bind, fsl-viz, fsl-info-panel)
2883
+ * previously paid for the exit/entry/data-change detail allocations on
2884
+ * every transition. Read at fire time, so a listener installed by a
2885
+ * pre-hook is still seen (#671).
2886
+ * @param name The event name to probe.
2887
+ * @returns `true` when a subsequent `_fire(name, ...)` would reach at
2888
+ * least one handler.
2889
+ *
2890
+ * ```typescript
2891
+ * machine.on('transition', () => {});
2892
+ * machine._has_subscribers('transition'); // true
2893
+ * machine._has_subscribers('exit'); // false
2894
+ * ```
2895
+ * @see Machine._fire
2896
+ * @internal
2897
+ */
2898
+ _has_subscribers(name: JssmEventName): boolean;
2899
+ _fire<Ev extends JssmEventName>(name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
2849
2900
  set_hook(HookDesc: HookDescription<mDT>): void;
2850
2901
  /**
2851
2902
  * Remove a previously-registered hook described by a
@@ -3186,6 +3237,81 @@ declare class Machine<mDT> {
3186
3237
  *
3187
3238
  */
3188
3239
  override(newState: StateType, newData?: mDT): void;
3240
+ /*********
3241
+ *
3242
+ * Fire a `'rejection'` event caused by a hook vetoing a pending transition.
3243
+ * Extracted from the per-call closures inside {@link transition_impl} so
3244
+ * that it is allocated once at class-definition time rather than on every
3245
+ * hooked transition.
3246
+ *
3247
+ * @param hook_name Name of the hook that rejected (e.g. `'exit'`).
3248
+ * @param fromState State the machine was in when the transition was
3249
+ * attempted; used as the `from` field of the rejection event.
3250
+ * @param newState State that would have been entered had the hook
3251
+ * passed; used as the `to` field of the rejection event.
3252
+ * @param fromAction Action name when the transition was initiated by an
3253
+ * action call; `undefined` for plain state transitions.
3254
+ * @param oldData Machine data at the moment the transition was
3255
+ * attempted, before any hook mutations.
3256
+ * @param newData The `next_data` value passed to the transition call.
3257
+ * @param wasForced Whether the transition was attempted via
3258
+ * `force_transition`.
3259
+ *
3260
+ * @see transition_impl
3261
+ * @see _fire
3262
+ *
3263
+ * @internal
3264
+ *
3265
+ */
3266
+ _fire_hook_rejection(hook_name: string, fromState: StateType, newState: StateType, fromAction: StateType | undefined, oldData: mDT, newData: mDT | undefined, wasForced: boolean): void;
3267
+ /*********
3268
+ *
3269
+ * Fire the FSL boundary-hook actions for a single, already-committed state
3270
+ * change. In FSL, `do` is a synonym for `action`, so `on enter &g do 'X';`
3271
+ * means "when the machine crosses INTO group `g`, dispatch machine action
3272
+ * `X`" — and likewise `on exit` / plain-state subjects. This is the runtime
3273
+ * that fires those parked hooks.
3274
+ *
3275
+ * Crossing semantics (statechart convention — exits before enters):
3276
+ *
3277
+ * 1. `prev_groups` / `next_groups` are the deep (transitive) group sets of
3278
+ * the old and new states, from `_state_to_groups`.
3279
+ * 2. **Exits** fire first: every group in `prev_groups \ next_groups` with an
3280
+ * `onExit`, plus the plain `prev_state`'s `onExit` (when the state name
3281
+ * actually changed).
3282
+ * 3. **Enters** fire next: every group in `next_groups \ prev_groups` with an
3283
+ * `onEnter`, plus the plain `next_state`'s `onEnter` (when the state name
3284
+ * changed).
3285
+ * 4. A group present in BOTH sets is a transition *within* that group and
3286
+ * fires neither of its boundary hooks. `prev_state === next_state` fires
3287
+ * nothing at all.
3288
+ * 5. "Fire its action" is `this.action(label)`. If that action is not valid
3289
+ * from the current state, `action` is a safe no-op (returns `false`) — an
3290
+ * inapplicable boundary action never throws.
3291
+ * 6. Multi-membership and nesting both fan out naturally: a state in groups
3292
+ * A and B fires both; crossing an inner and an outer boundary fires both
3293
+ * levels.
3294
+ *
3295
+ * Because firing an action can drive a further transition (which crosses
3296
+ * more boundaries, which fires more actions), this is a bounded
3297
+ * run-to-completion: `_boundary_depth` tracks the live cascade depth and a
3298
+ * cascade deeper than `_boundary_depth_limit` throws a {@link JssmError}
3299
+ * rather than overflowing the stack or hanging. The limit defaults to 100
3300
+ * and is configurable via the `boundary_depth_limit` constructor option.
3301
+ *
3302
+ * @param prev_state The state the machine was in before this commit.
3303
+ * @param next_state The state the machine is in now (already committed).
3304
+ *
3305
+ * @throws {JssmError} If cascaded boundary firing exceeds `_boundary_depth_limit`
3306
+ * (a probable infinite loop).
3307
+ *
3308
+ * @see action
3309
+ * @see transition_impl
3310
+ *
3311
+ * @internal
3312
+ *
3313
+ */
3314
+ _fire_boundary_actions(prev_state: StateType, next_state: StateType): void;
3189
3315
  /*********
3190
3316
  *
3191
3317
  * Shared transition core used by {@link transition}, {@link force_transition},
@@ -2719,6 +2719,57 @@ declare class Machine<mDT> {
2719
2719
  * @returns `true` if removed, `false` if no match was registered.
2720
2720
  */
2721
2721
  off<Ev extends JssmEventName>(name: Ev, handler: JssmEventHandler<mDT, Ev>): boolean;
2722
+ /**
2723
+ * Invoke a single event-handler entry, respecting its filter, once-removal
2724
+ * semantics, and the error re-fire / recursion-guard logic. Extracted so
2725
+ * {@link _fire} can share identical behavior between the size-1 fast-path
2726
+ * and the general snapshotted loop.
2727
+ * @param entry - The subscriber descriptor to invoke.
2728
+ * @param set - The live Set that owns `entry`; needed for once-removal.
2729
+ * @param name - The event name being dispatched (used in error re-fires).
2730
+ * @param detail - The event payload forwarded to the handler.
2731
+ * @internal
2732
+ */
2733
+ _fire_one<Ev extends JssmEventName>(entry: JssmEventEntry<mDT, Ev>, set: Set<JssmEventEntry<any, any>>, name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
2734
+ /**
2735
+ * Dispatch an event to every registered subscriber in registration
2736
+ * order. Filters are checked first; non-matching handlers are skipped
2737
+ * without invoking the handler. Exceptions thrown by a handler are
2738
+ * caught and re-emitted as an `error` event so subsequent handlers
2739
+ * still run.
2740
+ *
2741
+ * Re-entry into the `error` event itself is guarded — if an `error`
2742
+ * handler throws, the new exception is swallowed rather than rebroadcast
2743
+ * to avoid an infinite loop.
2744
+ *
2745
+ * When exactly one subscriber is registered the common case avoids the
2746
+ * `Array.from(set)` snapshot allocation by capturing the lone entry into a
2747
+ * local first — equivalent to a 1-element snapshot but allocation-free.
2748
+ * The general path still snapshots for re-entrancy safety.
2749
+ * @internal
2750
+ */
2751
+ /**
2752
+ * Whether at least one live subscriber is registered for `name`. Used by
2753
+ * the transition-commit observation block to skip building a detail
2754
+ * literal that {@link Machine._fire} would immediately discard — a panel
2755
+ * listening only to `'transition'` (fsl-bind, fsl-viz, fsl-info-panel)
2756
+ * previously paid for the exit/entry/data-change detail allocations on
2757
+ * every transition. Read at fire time, so a listener installed by a
2758
+ * pre-hook is still seen (#671).
2759
+ * @param name The event name to probe.
2760
+ * @returns `true` when a subsequent `_fire(name, ...)` would reach at
2761
+ * least one handler.
2762
+ *
2763
+ * ```typescript
2764
+ * machine.on('transition', () => {});
2765
+ * machine._has_subscribers('transition'); // true
2766
+ * machine._has_subscribers('exit'); // false
2767
+ * ```
2768
+ * @see Machine._fire
2769
+ * @internal
2770
+ */
2771
+ _has_subscribers(name: JssmEventName): boolean;
2772
+ _fire<Ev extends JssmEventName>(name: Ev, detail: JssmEventDetailMap<mDT>[Ev]): void;
2722
2773
  set_hook(HookDesc: HookDescription<mDT>): void;
2723
2774
  /**
2724
2775
  * Remove a previously-registered hook described by a
@@ -3059,6 +3110,81 @@ declare class Machine<mDT> {
3059
3110
  *
3060
3111
  */
3061
3112
  override(newState: StateType, newData?: mDT): void;
3113
+ /*********
3114
+ *
3115
+ * Fire a `'rejection'` event caused by a hook vetoing a pending transition.
3116
+ * Extracted from the per-call closures inside {@link transition_impl} so
3117
+ * that it is allocated once at class-definition time rather than on every
3118
+ * hooked transition.
3119
+ *
3120
+ * @param hook_name Name of the hook that rejected (e.g. `'exit'`).
3121
+ * @param fromState State the machine was in when the transition was
3122
+ * attempted; used as the `from` field of the rejection event.
3123
+ * @param newState State that would have been entered had the hook
3124
+ * passed; used as the `to` field of the rejection event.
3125
+ * @param fromAction Action name when the transition was initiated by an
3126
+ * action call; `undefined` for plain state transitions.
3127
+ * @param oldData Machine data at the moment the transition was
3128
+ * attempted, before any hook mutations.
3129
+ * @param newData The `next_data` value passed to the transition call.
3130
+ * @param wasForced Whether the transition was attempted via
3131
+ * `force_transition`.
3132
+ *
3133
+ * @see transition_impl
3134
+ * @see _fire
3135
+ *
3136
+ * @internal
3137
+ *
3138
+ */
3139
+ _fire_hook_rejection(hook_name: string, fromState: StateType, newState: StateType, fromAction: StateType | undefined, oldData: mDT, newData: mDT | undefined, wasForced: boolean): void;
3140
+ /*********
3141
+ *
3142
+ * Fire the FSL boundary-hook actions for a single, already-committed state
3143
+ * change. In FSL, `do` is a synonym for `action`, so `on enter &g do 'X';`
3144
+ * means "when the machine crosses INTO group `g`, dispatch machine action
3145
+ * `X`" — and likewise `on exit` / plain-state subjects. This is the runtime
3146
+ * that fires those parked hooks.
3147
+ *
3148
+ * Crossing semantics (statechart convention — exits before enters):
3149
+ *
3150
+ * 1. `prev_groups` / `next_groups` are the deep (transitive) group sets of
3151
+ * the old and new states, from `_state_to_groups`.
3152
+ * 2. **Exits** fire first: every group in `prev_groups \ next_groups` with an
3153
+ * `onExit`, plus the plain `prev_state`'s `onExit` (when the state name
3154
+ * actually changed).
3155
+ * 3. **Enters** fire next: every group in `next_groups \ prev_groups` with an
3156
+ * `onEnter`, plus the plain `next_state`'s `onEnter` (when the state name
3157
+ * changed).
3158
+ * 4. A group present in BOTH sets is a transition *within* that group and
3159
+ * fires neither of its boundary hooks. `prev_state === next_state` fires
3160
+ * nothing at all.
3161
+ * 5. "Fire its action" is `this.action(label)`. If that action is not valid
3162
+ * from the current state, `action` is a safe no-op (returns `false`) — an
3163
+ * inapplicable boundary action never throws.
3164
+ * 6. Multi-membership and nesting both fan out naturally: a state in groups
3165
+ * A and B fires both; crossing an inner and an outer boundary fires both
3166
+ * levels.
3167
+ *
3168
+ * Because firing an action can drive a further transition (which crosses
3169
+ * more boundaries, which fires more actions), this is a bounded
3170
+ * run-to-completion: `_boundary_depth` tracks the live cascade depth and a
3171
+ * cascade deeper than `_boundary_depth_limit` throws a {@link JssmError}
3172
+ * rather than overflowing the stack or hanging. The limit defaults to 100
3173
+ * and is configurable via the `boundary_depth_limit` constructor option.
3174
+ *
3175
+ * @param prev_state The state the machine was in before this commit.
3176
+ * @param next_state The state the machine is in now (already committed).
3177
+ *
3178
+ * @throws {JssmError} If cascaded boundary firing exceeds `_boundary_depth_limit`
3179
+ * (a probable infinite loop).
3180
+ *
3181
+ * @see action
3182
+ * @see transition_impl
3183
+ *
3184
+ * @internal
3185
+ *
3186
+ */
3187
+ _fire_boundary_actions(prev_state: StateType, next_state: StateType): void;
3062
3188
  /*********
3063
3189
  *
3064
3190
  * Shared transition core used by {@link transition}, {@link force_transition},