@typeonce/effect-machine 0.20.0 → 0.21.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/README.md +41 -0
- package/dist/Machine.d.ts +62 -16
- package/dist/Machine.d.ts.map +1 -1
- package/dist/Machine.js +4 -3
- package/dist/Machine.js.map +1 -1
- package/dist/internal/machine/executionPlan.d.ts.map +1 -1
- package/dist/internal/machine/executionPlan.js +33 -3
- package/dist/internal/machine/executionPlan.js.map +1 -1
- package/dist/internal/machine/machine.d.ts.map +1 -1
- package/dist/internal/machine/machine.js +38 -9
- package/dist/internal/machine/machine.js.map +1 -1
- package/dist/internal/machine/planner.d.ts +11 -2
- package/dist/internal/machine/planner.d.ts.map +1 -1
- package/dist/internal/machine/planner.js +49 -9
- package/dist/internal/machine/planner.js.map +1 -1
- package/dist/internal/machine/topology.d.ts +9 -1
- package/dist/internal/machine/topology.d.ts.map +1 -1
- package/dist/internal/machine/topology.js +7 -0
- package/dist/internal/machine/topology.js.map +1 -1
- package/dist/internal/testing/machine/verification.d.ts.map +1 -1
- package/dist/internal/testing/machine/verification.js +15 -3
- package/dist/internal/testing/machine/verification.js.map +1 -1
- package/dist/testing/MachineTest.d.ts +2 -0
- package/dist/testing/MachineTest.d.ts.map +1 -1
- package/dist/testing/MachineTest.js.map +1 -1
- package/docs/agent-guide.md +17 -0
- package/package.json +1 -1
- package/src/Machine.ts +230 -43
- package/src/internal/machine/executionPlan.ts +37 -3
- package/src/internal/machine/machine.ts +57 -9
- package/src/internal/machine/planner.ts +64 -11
- package/src/internal/machine/topology.ts +18 -1
- package/src/internal/testing/machine/verification.ts +16 -3
- package/src/testing/MachineTest.ts +2 -0
package/README.md
CHANGED
|
@@ -420,6 +420,47 @@ choice destinations remain calls such as `to.full.Running()`. Runtime named
|
|
|
420
420
|
branch builders remain callable, including `select.unchanged()`, because their
|
|
421
421
|
result carries the selected branch evidence.
|
|
422
422
|
|
|
423
|
+
### Update an active scope value
|
|
424
|
+
|
|
425
|
+
Use `to.local.update(...)` to replace the value owned by the nearest active
|
|
426
|
+
compound scope without rebuilding its active child. Use
|
|
427
|
+
`to.branch.<path>.update(...)` for a valued compound or parallel ancestor of the
|
|
428
|
+
handler source:
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
Increment: ;
|
|
432
|
+
;((to) =>
|
|
433
|
+
to.branch.root.session.update(({ ancestors, target }) => target.from({ count: ancestors["root.session"].count + 1 })))
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
The update keeps the exact active descendants, their values, history records,
|
|
437
|
+
completion outputs, and unrelated parallel regions. It runs no exit or entry
|
|
438
|
+
actions and does not restart state-owned work. Eventless stabilization still
|
|
439
|
+
runs, so an `always` transition can react to the new value.
|
|
440
|
+
|
|
441
|
+
`update` is callable when used directly and is also a static selection for a
|
|
442
|
+
named branch:
|
|
443
|
+
|
|
444
|
+
```ts
|
|
445
|
+
to.branches({
|
|
446
|
+
changed: { target: to.local.update },
|
|
447
|
+
unchanged: { target: to.none }
|
|
448
|
+
}).resolve(({ select, event }) =>
|
|
449
|
+
event.changed
|
|
450
|
+
? select.changed.from({ count: event.count })
|
|
451
|
+
: select.unchanged()
|
|
452
|
+
)
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
The resolver must return `target(value)` or `target.from(input)`. It may return
|
|
456
|
+
`decline()` only with `{ declinable: true }`. Pass `{ reenter: true }` on event
|
|
457
|
+
or invocation transitions when the handler source should exit and enter again.
|
|
458
|
+
Reentry applies to that source, not to the ancestor whose value changed.
|
|
459
|
+
|
|
460
|
+
The selector omits `update` for schema-less scopes, atomic and final states,
|
|
461
|
+
inactive branches, parallel sibling regions, and choice resolvers. Updating a
|
|
462
|
+
parallel sibling requires an event handled by that region.
|
|
463
|
+
|
|
423
464
|
Use `declinable: true` when a resolver may decide that its transition is not
|
|
424
465
|
enabled. Only that resolver receives `decline()`, and its return type expands to
|
|
425
466
|
accept the opaque declined result:
|
package/dist/Machine.d.ts
CHANGED
|
@@ -2234,9 +2234,10 @@ export declare namespace Machine {
|
|
|
2234
2234
|
*
|
|
2235
2235
|
* **Details**
|
|
2236
2236
|
*
|
|
2237
|
-
* Every branch exposes its
|
|
2238
|
-
* A compound local or branch target covers its descendants
|
|
2239
|
-
* `
|
|
2237
|
+
* Every branch exposes its static selection without executing its resolver.
|
|
2238
|
+
* A compound local or branch target covers its descendants. An `update`
|
|
2239
|
+
* selection keeps `target` undefined and records its value owner in
|
|
2240
|
+
* `selection.path`; `none` identifies an explicitly targetless branch.
|
|
2240
2241
|
*
|
|
2241
2242
|
* @category models
|
|
2242
2243
|
* @since 0.4.0
|
|
@@ -2841,6 +2842,20 @@ export declare namespace Machine {
|
|
|
2841
2842
|
readonly [AncestorStateId in ValuedStateIdentifier<States>]: StateByIdentifier<States, AncestorStateId>;
|
|
2842
2843
|
}>;
|
|
2843
2844
|
}
|
|
2845
|
+
/**
|
|
2846
|
+
* Opaque instruction that replaces one active compound or parallel state's
|
|
2847
|
+
* value without changing its active descendants.
|
|
2848
|
+
*
|
|
2849
|
+
* @category models
|
|
2850
|
+
* @since 0.21.0
|
|
2851
|
+
*/
|
|
2852
|
+
interface StateUpdate<States extends StateSchemas, StateId extends ValuedStateIdentifier<States>> {
|
|
2853
|
+
readonly [Topology.StateUpdateTypeId]: typeof Topology.StateUpdateTypeId;
|
|
2854
|
+
readonly path: StateId;
|
|
2855
|
+
readonly value: StateByIdentifier<States, StateId>;
|
|
2856
|
+
}
|
|
2857
|
+
/** @internal */
|
|
2858
|
+
type StateUpdateBuilder<States extends StateSchemas, StateId extends ValuedStateIdentifier<States>> = ((value: StateByIdentifier<States, StateId>) => StateUpdate<States, StateId>) & FromMethod<readonly [input: SchemaByIdentifier<States, StateId>["~type.make.in"]], StateUpdate<States, StateId>>;
|
|
2844
2859
|
/**
|
|
2845
2860
|
* Opaque result returned by an explicitly targetless transition.
|
|
2846
2861
|
*
|
|
@@ -3045,6 +3060,20 @@ export declare namespace Machine {
|
|
|
3045
3060
|
type SelectionNode<AllStates extends StateSchemas, Node, Path extends string, Scope extends "local" | "branch", Builder> = Node extends ChoiceStateNodeConfig ? SelectionMethod<Builder, Path, "choice"> : Node extends {
|
|
3046
3061
|
readonly states: infer Children extends StateSchemas;
|
|
3047
3062
|
} ? SelectionMethod<Builder, Path> & InitialSelectionMethod<Builder, Path> & SelectionTreeWithPrefix<AllStates, Children, Path, Scope, Builder> : SelectionMethod<Builder, Path>;
|
|
3063
|
+
/** @internal */
|
|
3064
|
+
type StateUpdateSelectionForNode<AllStates extends StateSchemas, Node, Path extends string> = Node extends {
|
|
3065
|
+
readonly states: StateSchemas;
|
|
3066
|
+
} ? NodeSchema<Node> extends never ? {} : {
|
|
3067
|
+
readonly update: SelectionValue<StateUpdateBuilder<AllStates, Extract<Path, ValuedStateIdentifier<AllStates>>>, Path, "update">;
|
|
3068
|
+
} : {};
|
|
3069
|
+
/** @internal */
|
|
3070
|
+
type BranchUpdateSelectionPath<AllStates extends StateSchemas, Node, Path extends string, Rest extends string> = StateUpdateSelectionForNode<AllStates, Node, Path> & (Node extends {
|
|
3071
|
+
readonly states: infer Children extends StateSchemas;
|
|
3072
|
+
} ? Rest extends `${infer Head}.${infer Tail}` ? Head extends keyof Children ? {
|
|
3073
|
+
readonly [Key in Head]: BranchUpdateSelectionPath<AllStates, Children[Head], JoinPath<Path, Head>, Tail>;
|
|
3074
|
+
} : {} : Rest extends keyof Children ? {
|
|
3075
|
+
readonly [Key in Rest]: StateUpdateSelectionForNode<AllStates, Children[Rest], JoinPath<Path, Rest>>;
|
|
3076
|
+
} : {} : {});
|
|
3048
3077
|
type FullSelectionNode<AllStates extends StateSchemas, Node, Path extends StateIdentifier<AllStates>, Builder> = Node extends {
|
|
3049
3078
|
readonly states: StateSchemas;
|
|
3050
3079
|
} ? SelectionMethod<Builder, Path> & InitialSelectionMethod<Builder, Path> : SelectionMethod<Builder, Path>;
|
|
@@ -3052,11 +3081,13 @@ export declare namespace Machine {
|
|
|
3052
3081
|
readonly [Key in Extract<ActiveStateKey<States>, keyof FullTargetBuilder<States>>]: FullSelectionNode<States, States[Key], Extract<Key, StateIdentifier<States>>, FullTargetBuilder<States>[Key]>;
|
|
3053
3082
|
};
|
|
3054
3083
|
type BranchTargetSelector<States extends StateSchemas, Source extends StateNodeIdentifier<States>, Root extends string = Source extends `${infer Head}.${string}` ? Head : Source> = Root extends ActiveStateKey<States> ? Root extends keyof BranchTargetBuilder<States, Source> ? {
|
|
3055
|
-
readonly [Key in Root]: SelectionNode<States, States[Key], Key, "branch", BranchTargetBuilder<States, Source>[Key]
|
|
3084
|
+
readonly [Key in Root]: SelectionNode<States, States[Key], Key, "branch", BranchTargetBuilder<States, Source>[Key]> & (Source extends ChoiceIdentifier<States> ? {} : Source extends `${Key}.${infer Rest}` ? BranchUpdateSelectionPath<States, States[Key], Key, Rest> : StateUpdateSelectionForNode<States, States[Key], Key>);
|
|
3056
3085
|
} : {} : {};
|
|
3057
|
-
type LocalTargetSelector<States extends StateSchemas, Source extends StateNodeIdentifier<States>> = NearestCompoundScope<States, Source> extends infer Scope extends StateIdentifier<States> ? ChildrenOf<States, Scope> extends infer Children extends StateSchemas ? LocalTargetBuilder<States, Source> extends infer Builder ? SelectionTreeWithPrefix<States, Children, Scope, "local", Builder> & ("with" extends keyof Builder ? {
|
|
3086
|
+
type LocalTargetSelector<States extends StateSchemas, Source extends StateNodeIdentifier<States>> = NearestCompoundScope<States, Source> extends infer Scope ? [Scope] extends [never] ? {} : Scope extends StateIdentifier<States> ? ChildrenOf<States, Scope> extends infer Children extends StateSchemas ? LocalTargetBuilder<States, Source> extends infer Builder ? SelectionTreeWithPrefix<States, Children, Scope, "local", Builder> & ("with" extends keyof Builder ? {
|
|
3058
3087
|
readonly with: SelectionValue<Builder["with"], Scope>;
|
|
3059
|
-
} : {})
|
|
3088
|
+
} : {}) & (Source extends ChoiceIdentifier<States> ? {} : Scope extends ValuedStateIdentifier<States> ? {
|
|
3089
|
+
readonly update: SelectionValue<StateUpdateBuilder<States, Scope>, Scope, "update">;
|
|
3090
|
+
} : {}) : {} : {} : {} : {};
|
|
3060
3091
|
type HistorySelectionTree<AllStates extends StateSchemas, States extends StateSchemas, Prefix extends string, Builder> = {
|
|
3061
3092
|
readonly [Key in Extract<HistoryContainingKey<States>, keyof Builder>]: States[Key] extends HistoryStateNodeConfig ? SelectionValue<Builder[Key], JoinPath<Prefix, Key>, "history"> : States[Key] extends {
|
|
3062
3093
|
readonly states: infer Children extends StateSchemas;
|
|
@@ -3074,9 +3105,9 @@ export declare namespace Machine {
|
|
|
3074
3105
|
interface TargetSelector<States extends StateSchemas, Source extends StateNodeIdentifier<States>> {
|
|
3075
3106
|
/** Handles the trigger without selecting a destination. */
|
|
3076
3107
|
readonly none: SelectionValue<TargetBuilder<States, Source>["none"], never, "none">;
|
|
3077
|
-
/** Selects a destination
|
|
3108
|
+
/** Selects a destination or updates the nearest active compound scope. */
|
|
3078
3109
|
readonly local: LocalTargetSelector<States, Source>;
|
|
3079
|
-
/** Selects a destination
|
|
3110
|
+
/** Selects a destination or updates a valued active ancestor under the current root. */
|
|
3080
3111
|
readonly branch: BranchTargetSelector<States, Source>;
|
|
3081
3112
|
/** Selects a complete destination under any top-level state. */
|
|
3082
3113
|
readonly full: FullTargetSelector<States>;
|
|
@@ -3365,14 +3396,14 @@ export declare namespace Machine {
|
|
|
3365
3396
|
* **Details**
|
|
3366
3397
|
*
|
|
3367
3398
|
* Handlers return snapshots for complete state replacement, target builder
|
|
3368
|
-
* results for path-safe partial transitions,
|
|
3369
|
-
* explicitly targetless transition. Raw decoded state
|
|
3370
|
-
* not accepted at transition boundaries.
|
|
3399
|
+
* results for path-safe partial transitions, state-value updates, or
|
|
3400
|
+
* `target.none()` for an explicitly targetless transition. Raw decoded state
|
|
3401
|
+
* values and `void` are not accepted at transition boundaries.
|
|
3371
3402
|
*
|
|
3372
3403
|
* @category utility types
|
|
3373
3404
|
* @since 0.4.0
|
|
3374
3405
|
*/
|
|
3375
|
-
type HandlerResult<States extends StateSchemas, E, R> = Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>> | StateConstruction<Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>>> | NoTarget;
|
|
3406
|
+
type HandlerResult<States extends StateSchemas, E, R> = Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>> | StateUpdate<States, ValuedStateIdentifier<States>> | StateConstruction<Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>> | StateUpdate<States, ValuedStateIdentifier<States>>> | NoTarget;
|
|
3376
3407
|
/** A choice resolver must always select a typed target synchronously. */
|
|
3377
3408
|
type ChoiceResult<States extends StateSchemas, E, R> = Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>> | StateConstruction<Snapshot<States> | Target<States, StateIdentifier<States>> | HistoryTarget<States, HistoryIdentifier<States>> | ChoiceTarget<States, ChoiceIdentifier<States>>>;
|
|
3378
3409
|
/**
|
|
@@ -3633,6 +3664,10 @@ export declare namespace Machine {
|
|
|
3633
3664
|
}
|
|
3634
3665
|
type TransitionResolver<Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, Context, Selection> = (context: TransitionResolveContext<Context, Selection>, enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>) => SelectionKind<Selection> extends "none" ? undefined : SelectedTargetResult<Selection> | undefined;
|
|
3635
3666
|
type DeclinableTransitionResolver<Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, Context, Selection> = (context: TransitionResolveContext<Context, Selection> & DeclineCapability, enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>) => (SelectionKind<Selection> extends "none" ? undefined : SelectedTargetResult<Selection> | undefined) | Declined;
|
|
3667
|
+
/** @internal */
|
|
3668
|
+
type StateUpdateResolver<Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, Context, Selection> = (context: TransitionResolveContext<Context, Selection>, enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>) => SelectedTargetResult<Selection>;
|
|
3669
|
+
/** @internal */
|
|
3670
|
+
type DeclinableStateUpdateResolver<Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, Context, Selection> = (context: TransitionResolveContext<Context, Selection> & DeclineCapability, enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>) => SelectedTargetResult<Selection> | Declined;
|
|
3636
3671
|
/** One named destination declared by a branching transition. */
|
|
3637
3672
|
interface TransitionBranchInput<Selection extends TargetSelection<any, any, any> = TargetSelection<any, any, any>> {
|
|
3638
3673
|
/** Exact topology destination available to the branching resolver. */
|
|
@@ -3725,6 +3760,16 @@ export declare namespace Machine {
|
|
|
3725
3760
|
/** Reenters the source using the selected target's default construction. */
|
|
3726
3761
|
readonly reenter: () => BuiltTransition<States, Events, Emits, StateId, Context, Reenter, SelectionKind<Selection> extends "none" ? undefined : SelectedTargetResult<Selection> | undefined, "required">;
|
|
3727
3762
|
} : {} : {});
|
|
3763
|
+
/** @internal */
|
|
3764
|
+
interface StateUpdateTransitionRequired<States extends StateSchemas, Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, StateId extends StateNodeIdentifier<States>, Context, Reenter extends boolean, Selection extends TargetSelection<any, any, "update">> {
|
|
3765
|
+
(resolve: StateUpdateResolver<Events, Emits, Context, Selection>, options?: TransitionRequiredOptions<Reenter>): BuiltTransition<States, Events, Emits, StateId, Context, Reenter, SelectedTargetResult<Selection>, "required">;
|
|
3766
|
+
}
|
|
3767
|
+
/** @internal */
|
|
3768
|
+
interface StateUpdateTransitionDeclinable<States extends StateSchemas, Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, StateId extends StateNodeIdentifier<States>, Context, Reenter extends boolean, Selection extends TargetSelection<any, any, "update">> {
|
|
3769
|
+
(resolve: DeclinableStateUpdateResolver<Events, Emits, Context, Selection>, options: TransitionDeclinableOptions<Reenter>): BuiltTransition<States, Events, Emits, StateId, Context, Reenter, SelectedTargetResult<Selection> | Declined, "declinable">;
|
|
3770
|
+
}
|
|
3771
|
+
/** @internal */
|
|
3772
|
+
type StateUpdateTransition<States extends StateSchemas, Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, StateId extends StateNodeIdentifier<States>, Context, Reenter extends boolean, Acceptance extends TransitionAcceptance, Selection extends TargetSelection<any, any, "update">> = Selection & StateUpdateTransitionRequired<States, Events, Emits, StateId, Context, Reenter, Selection> & ("declinable" extends Acceptance ? StateUpdateTransitionDeclinable<States, Events, Emits, StateId, Context, Reenter, Selection> : {});
|
|
3728
3773
|
/** @internal Type evidence retained by a machine initial-entry declaration. */
|
|
3729
3774
|
interface InitialBuilderEvidence<out Selection> {
|
|
3730
3775
|
readonly [InitialBuilderTypeId]: Types.Covariant<Selection>;
|
|
@@ -3748,7 +3793,7 @@ export declare namespace Machine {
|
|
|
3748
3793
|
type InitialSelector<States extends StateSchemas, Input = void> = InitialSelectorNode<Input, InitialTargetSelector<States>>;
|
|
3749
3794
|
/** Target-first initial-entry declaration accepted by {@link make}. */
|
|
3750
3795
|
type InitialBuilderInput<States extends StateSchemas, Input> = (to: InitialSelector<States, Input>) => InitialBuilderEvidence<TargetSelection<any, any, any>>;
|
|
3751
|
-
type TransitionSelectorNode<States extends StateSchemas, Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, StateId extends StateNodeIdentifier<States>, Context, Reenter extends boolean, Acceptance extends TransitionAcceptance, Node> = Node extends (...args: infer Args) => infer Selection ? Selection extends TargetSelection<any, any, any> ? ((...args: Args) => TransitionTarget<States, Events, Emits, StateId, Context, Reenter, Acceptance, Selection>) & {
|
|
3796
|
+
type TransitionSelectorNode<States extends StateSchemas, Events extends ReadonlyArray<TaggedSchema>, Emits extends ReadonlyArray<TaggedSchema>, StateId extends StateNodeIdentifier<States>, Context, Reenter extends boolean, Acceptance extends TransitionAcceptance, Node> = Node extends TargetSelection<any, any, "update"> ? StateUpdateTransition<States, Events, Emits, StateId, Context, Reenter, Acceptance, Node> : Node extends (...args: infer Args) => infer Selection ? Selection extends TargetSelection<any, any, any> ? ((...args: Args) => TransitionTarget<States, Events, Emits, StateId, Context, Reenter, Acceptance, Selection>) & {
|
|
3752
3797
|
readonly [Key in keyof Node]: TransitionSelectorNode<States, Events, Emits, StateId, Context, Reenter, Acceptance, Node[Key]>;
|
|
3753
3798
|
} : never : Node extends TargetSelection<any, any, any> ? TransitionTarget<States, Events, Emits, StateId, Context, Reenter, Acceptance, Node> : {
|
|
3754
3799
|
readonly [Key in keyof Node]: TransitionSelectorNode<States, Events, Emits, StateId, Context, Reenter, Acceptance, Node[Key]>;
|
|
@@ -4908,9 +4953,10 @@ export declare const initialDefinition: <M extends Machine.Any>(machine: M) => M
|
|
|
4908
4953
|
*
|
|
4909
4954
|
* Event handlers retain their handler-key order within each source state and
|
|
4910
4955
|
* are followed by eventless and completion handlers. This function does not
|
|
4911
|
-
* execute resolvers. Every
|
|
4912
|
-
*
|
|
4913
|
-
*
|
|
4956
|
+
* execute resolvers. Every branch exposes its static selection. State updates
|
|
4957
|
+
* retain the updated owner in `selection.path` while leaving `target`
|
|
4958
|
+
* undefined because they do not change topology. `acceptance` reports whether
|
|
4959
|
+
* the resolver may decline the transition.
|
|
4914
4960
|
*
|
|
4915
4961
|
* @category getters
|
|
4916
4962
|
* @since 0.4.0
|