@typeonce/effect-machine 0.19.1 → 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.
Files changed (54) hide show
  1. package/README.md +90 -14
  2. package/dist/Machine.d.ts +155 -18
  3. package/dist/Machine.d.ts.map +1 -1
  4. package/dist/Machine.js +15 -3
  5. package/dist/Machine.js.map +1 -1
  6. package/dist/internal/machine/atom.d.ts.map +1 -1
  7. package/dist/internal/machine/atom.js +18 -4
  8. package/dist/internal/machine/atom.js.map +1 -1
  9. package/dist/internal/machine/executionPlan.d.ts.map +1 -1
  10. package/dist/internal/machine/executionPlan.js +33 -3
  11. package/dist/internal/machine/executionPlan.js.map +1 -1
  12. package/dist/internal/machine/invocation.d.ts.map +1 -1
  13. package/dist/internal/machine/invocation.js +7 -0
  14. package/dist/internal/machine/invocation.js.map +1 -1
  15. package/dist/internal/machine/machine.d.ts +1 -0
  16. package/dist/internal/machine/machine.d.ts.map +1 -1
  17. package/dist/internal/machine/machine.js +49 -13
  18. package/dist/internal/machine/machine.js.map +1 -1
  19. package/dist/internal/machine/planner.d.ts +11 -2
  20. package/dist/internal/machine/planner.d.ts.map +1 -1
  21. package/dist/internal/machine/planner.js +49 -9
  22. package/dist/internal/machine/planner.js.map +1 -1
  23. package/dist/internal/machine/runtime.d.ts +4 -3
  24. package/dist/internal/machine/runtime.d.ts.map +1 -1
  25. package/dist/internal/machine/runtime.js +12 -1
  26. package/dist/internal/machine/runtime.js.map +1 -1
  27. package/dist/internal/machine/topology.d.ts +9 -1
  28. package/dist/internal/machine/topology.d.ts.map +1 -1
  29. package/dist/internal/machine/topology.js +7 -0
  30. package/dist/internal/machine/topology.js.map +1 -1
  31. package/dist/internal/testing/machine/verification.d.ts.map +1 -1
  32. package/dist/internal/testing/machine/verification.js +15 -3
  33. package/dist/internal/testing/machine/verification.js.map +1 -1
  34. package/dist/testing/MachineTest.d.ts +2 -0
  35. package/dist/testing/MachineTest.d.ts.map +1 -1
  36. package/dist/testing/MachineTest.js.map +1 -1
  37. package/dist/unstable/reactivity/AtomMachine.d.ts +10 -8
  38. package/dist/unstable/reactivity/AtomMachine.d.ts.map +1 -1
  39. package/dist/unstable/reactivity/AtomMachine.js +2 -2
  40. package/dist/unstable/reactivity/AtomMachine.js.map +1 -1
  41. package/docs/agent-guide.md +48 -0
  42. package/docs/effect-atom-react.md +28 -0
  43. package/package.json +1 -1
  44. package/src/Machine.ts +371 -45
  45. package/src/internal/machine/atom.ts +26 -18
  46. package/src/internal/machine/executionPlan.ts +37 -3
  47. package/src/internal/machine/invocation.ts +13 -1
  48. package/src/internal/machine/machine.ts +75 -15
  49. package/src/internal/machine/planner.ts +64 -11
  50. package/src/internal/machine/runtime.ts +48 -19
  51. package/src/internal/machine/topology.ts +18 -1
  52. package/src/internal/testing/machine/verification.ts +16 -3
  53. package/src/testing/MachineTest.ts +2 -0
  54. package/src/unstable/reactivity/AtomMachine.ts +10 -8
package/src/Machine.ts CHANGED
@@ -2265,7 +2265,15 @@ export declare namespace Logic {
2265
2265
  * @category models
2266
2266
  * @since 0.4.0
2267
2267
  */
2268
- export interface Spawn {
2268
+ export interface Spawn<OwnerEvent = unknown> {
2269
+ <const Child extends ChildMachine.Any>(
2270
+ child: Child & ChildMachine.Executable<Child> & ChildMachine.ParentCompatibility<Child, OwnerEvent>,
2271
+ ...options: ChildMachine.SpawnArgs<Child>
2272
+ ): Effect.Effect<
2273
+ ChildMachine.Ref<Child>,
2274
+ ChildAlreadyExistsError | ChildMachine.StartError<Child>,
2275
+ ChildMachine.StartRequirements<Child>
2276
+ >
2269
2277
  <ChildState, ChildEvent, ChildError, ChildRequirements, ChildOutput, ChildInitialError = never>(
2270
2278
  logic: Logic<ChildState, ChildEvent, ChildError, ChildRequirements, ChildOutput, ChildInitialError>
2271
2279
  ): Effect.Effect<
@@ -2305,7 +2313,7 @@ export declare namespace Logic {
2305
2313
  readonly parent: Address<unknown> | undefined
2306
2314
 
2307
2315
  /** Starts a child process owned by this scope. */
2308
- readonly spawn: Spawn
2316
+ readonly spawn: Spawn<Event>
2309
2317
 
2310
2318
  /** Sends an event to a machine target or typed parent-local child address. */
2311
2319
  readonly sendTo: {
@@ -2345,6 +2353,7 @@ export declare namespace Logic {
2345
2353
 
2346
2354
  const ChildAddressTypeId = "~effect/Machine/ChildAddress"
2347
2355
  const ChildAddressCompatibilityErrorTypeId = "~effect/Machine/ChildAddressCompatibilityError"
2356
+ const ChildParentCompatibilityErrorTypeId = "~effect/Machine/ChildParentCompatibilityError"
2348
2357
  const ChildMachineTypeId = "~effect/Machine/ChildMachine"
2349
2358
  type InvokeLifecycleId = string & { readonly [ChildAddressTypeId]?: never }
2350
2359
 
@@ -2389,6 +2398,95 @@ export declare namespace ChildMachine {
2389
2398
  */
2390
2399
  export type Any = ChildMachine<string, Machine.Any>
2391
2400
 
2401
+ /**
2402
+ * Bound constructor for an open family of child descriptors that share one
2403
+ * machine definition.
2404
+ *
2405
+ * @category models
2406
+ * @since 0.20.0
2407
+ */
2408
+ export interface Family<M extends Machine.Any> {
2409
+ <const Id extends string>(id: Id): ChildMachine<Id, M>
2410
+ }
2411
+
2412
+ /**
2413
+ * Ensures a child machine's declared owner protocol is accepted by the
2414
+ * process that will own it.
2415
+ *
2416
+ * @category utility types
2417
+ * @since 0.20.0
2418
+ */
2419
+ export type ParentCompatibility<Child extends Any, OwnerEvent> = Child extends ChildMachine<string, infer M> ?
2420
+ Machine.Any extends M ? {
2421
+ readonly [ChildParentCompatibilityErrorTypeId]: {
2422
+ readonly child: unknown
2423
+ readonly owner: OwnerEvent
2424
+ }
2425
+ }
2426
+ : [Machine.EventOf<Machine.ParentEvents<M>>] extends [OwnerEvent] ? unknown :
2427
+ {
2428
+ readonly [ChildParentCompatibilityErrorTypeId]: {
2429
+ readonly child: Machine.EventOf<Machine.ParentEvents<M>>
2430
+ readonly owner: OwnerEvent
2431
+ }
2432
+ }
2433
+ : never
2434
+
2435
+ /**
2436
+ * Ensures the selected child machine has complete handlers and outputs.
2437
+ *
2438
+ * @category utility types
2439
+ * @since 0.20.0
2440
+ */
2441
+ export type Executable<Child extends Any> = Child["machine"] extends EnsureExecutable<
2442
+ Machine.States<Child["machine"]>,
2443
+ Machine.UnhandledStates<Child["machine"]>,
2444
+ Machine.OutputStates<Child["machine"]>
2445
+ > ? unknown
2446
+ : never
2447
+
2448
+ /**
2449
+ * Startup arguments accepted while spawning a child machine.
2450
+ *
2451
+ * @category utility types
2452
+ * @since 0.20.0
2453
+ */
2454
+ export type SpawnArgs<Child extends Any> = Machine.InputSchema<Child["machine"]> extends typeof Schema.Void ?
2455
+ [options?: { readonly input?: never }]
2456
+ : [options: { readonly input: Machine.Input<Child["machine"]> }]
2457
+
2458
+ /**
2459
+ * Typed failures that may occur before a spawned child becomes active.
2460
+ *
2461
+ * @category utility types
2462
+ * @since 0.20.0
2463
+ */
2464
+ export type StartError<Child extends Any> = Child extends ChildMachine<string, infer M> ?
2465
+ | Machine.InitialError<M>
2466
+ | Machine.Error<M>
2467
+ | ActionError<Machine.InitialServices<M> | Machine.Services<M>>
2468
+ | InfiniteTransitionError
2469
+ | MachineSchemaDecodeError
2470
+ | StartupError
2471
+ | StoppedError
2472
+ : never
2473
+
2474
+ /**
2475
+ * Services needed to initialize a spawned child machine.
2476
+ *
2477
+ * @category utility types
2478
+ * @since 0.20.0
2479
+ */
2480
+ export type StartRequirements<Child extends Any> = Child extends ChildMachine<string, infer M> ? Exclude<
2481
+ ExcludeCompatibleRuntime<
2482
+ Exclude<ExecutionServices<Machine.InitialServices<M> | Machine.Services<M>>, MachineRuntimeRequirement>,
2483
+ Machine.Event<M>,
2484
+ Machine.Emit<M>
2485
+ >,
2486
+ Scope.Scope
2487
+ >
2488
+ : never
2489
+
2392
2490
  /**
2393
2491
  * Running machine reference selected by a child descriptor.
2394
2492
  *
@@ -2418,6 +2516,34 @@ export declare namespace ChildMachine {
2418
2516
  : never
2419
2517
  }
2420
2518
 
2519
+ /**
2520
+ * Effectful operations for child machines owned directly by the current
2521
+ * machine process.
2522
+ *
2523
+ * @category models
2524
+ * @since 0.20.0
2525
+ */
2526
+ export interface ChildOwner<OwnerEvent> {
2527
+ /** Starts a process-owned child and returns once initialization succeeds. */
2528
+ readonly spawn: <const Child extends ChildMachine.Any>(
2529
+ child: Child & ChildMachine.Executable<Child> & ChildMachine.ParentCompatibility<Child, OwnerEvent>,
2530
+ ...options: ChildMachine.SpawnArgs<Child>
2531
+ ) => Effect.Effect<
2532
+ ChildMachine.Ref<Child>,
2533
+ ChildAlreadyExistsError | ChildMachine.StartError<Child>,
2534
+ ChildMachine.StartRequirements<Child>
2535
+ >
2536
+
2537
+ /** Sends an event to one active child. Missing children are ignored. */
2538
+ readonly sendTo: <Child extends ChildMachine.Any>(
2539
+ child: Child,
2540
+ event: ChildMachine.Event<Child>
2541
+ ) => Effect.Effect<void, StoppedError>
2542
+
2543
+ /** Stops one active child. Missing children are ignored. */
2544
+ readonly stop: <Child extends ChildMachine.Any>(child: Child) => Effect.Effect<void>
2545
+ }
2546
+
2421
2547
  /**
2422
2548
  * Parent-local address for a child process that can receive events.
2423
2549
  *
@@ -3451,9 +3577,10 @@ export declare namespace Machine {
3451
3577
  *
3452
3578
  * **Details**
3453
3579
  *
3454
- * Every branch exposes its selected target without executing its resolver.
3455
- * A compound local or branch target covers its descendants;
3456
- * `undefined` identifies an explicitly targetless branch.
3580
+ * Every branch exposes its static selection without executing its resolver.
3581
+ * A compound local or branch target covers its descendants. An `update`
3582
+ * selection keeps `target` undefined and records its value owner in
3583
+ * `selection.path`; `none` identifies an explicitly targetless branch.
3457
3584
  *
3458
3585
  * @category models
3459
3586
  * @since 0.4.0
@@ -4335,6 +4462,33 @@ export declare namespace Machine {
4335
4462
  >
4336
4463
  }
4337
4464
 
4465
+ /**
4466
+ * Opaque instruction that replaces one active compound or parallel state's
4467
+ * value without changing its active descendants.
4468
+ *
4469
+ * @category models
4470
+ * @since 0.21.0
4471
+ */
4472
+ export interface StateUpdate<
4473
+ States extends StateSchemas,
4474
+ StateId extends ValuedStateIdentifier<States>
4475
+ > {
4476
+ readonly [Topology.StateUpdateTypeId]: typeof Topology.StateUpdateTypeId
4477
+ readonly path: StateId
4478
+ readonly value: StateByIdentifier<States, StateId>
4479
+ }
4480
+
4481
+ /** @internal */
4482
+ type StateUpdateBuilder<
4483
+ States extends StateSchemas,
4484
+ StateId extends ValuedStateIdentifier<States>
4485
+ > =
4486
+ & ((value: StateByIdentifier<States, StateId>) => StateUpdate<States, StateId>)
4487
+ & FromMethod<
4488
+ readonly [input: SchemaByIdentifier<States, StateId>["~type.make.in"]],
4489
+ StateUpdate<States, StateId>
4490
+ >
4491
+
4338
4492
  /**
4339
4493
  * Opaque result returned by an explicitly targetless transition.
4340
4494
  *
@@ -4619,6 +4773,45 @@ export declare namespace Machine {
4619
4773
  & SelectionTreeWithPrefix<AllStates, Children, Path, Scope, Builder>
4620
4774
  : SelectionMethod<Builder, Path>
4621
4775
 
4776
+ /** @internal */
4777
+ type StateUpdateSelectionForNode<
4778
+ AllStates extends StateSchemas,
4779
+ Node,
4780
+ Path extends string
4781
+ > = Node extends { readonly states: StateSchemas } ? NodeSchema<Node> extends never ? {}
4782
+ : {
4783
+ readonly update: SelectionValue<
4784
+ StateUpdateBuilder<AllStates, Extract<Path, ValuedStateIdentifier<AllStates>>>,
4785
+ Path,
4786
+ "update"
4787
+ >
4788
+ }
4789
+ : {}
4790
+
4791
+ /** @internal */
4792
+ type BranchUpdateSelectionPath<
4793
+ AllStates extends StateSchemas,
4794
+ Node,
4795
+ Path extends string,
4796
+ Rest extends string
4797
+ > =
4798
+ & StateUpdateSelectionForNode<AllStates, Node, Path>
4799
+ & (Node extends { readonly states: infer Children extends StateSchemas } ?
4800
+ Rest extends `${infer Head}.${infer Tail}` ? Head extends keyof Children ? {
4801
+ readonly [Key in Head]: BranchUpdateSelectionPath<
4802
+ AllStates,
4803
+ Children[Head],
4804
+ JoinPath<Path, Head>,
4805
+ Tail
4806
+ >
4807
+ }
4808
+ : {}
4809
+ : Rest extends keyof Children ? {
4810
+ readonly [Key in Rest]: StateUpdateSelectionForNode<AllStates, Children[Rest], JoinPath<Path, Rest>>
4811
+ }
4812
+ : {}
4813
+ : {})
4814
+
4622
4815
  type FullSelectionNode<
4623
4816
  AllStates extends StateSchemas,
4624
4817
  Node,
@@ -4643,13 +4836,17 @@ export declare namespace Machine {
4643
4836
  Source extends StateNodeIdentifier<States>,
4644
4837
  Root extends string = Source extends `${infer Head}.${string}` ? Head : Source
4645
4838
  > = Root extends ActiveStateKey<States> ? Root extends keyof BranchTargetBuilder<States, Source> ? {
4646
- readonly [Key in Root]: SelectionNode<
4647
- States,
4648
- States[Key],
4649
- Key,
4650
- "branch",
4651
- BranchTargetBuilder<States, Source>[Key]
4652
- >
4839
+ readonly [Key in Root]:
4840
+ & SelectionNode<
4841
+ States,
4842
+ States[Key],
4843
+ Key,
4844
+ "branch",
4845
+ BranchTargetBuilder<States, Source>[Key]
4846
+ >
4847
+ & (Source extends ChoiceIdentifier<States> ? {}
4848
+ : Source extends `${Key}.${infer Rest}` ? BranchUpdateSelectionPath<States, States[Key], Key, Rest>
4849
+ : StateUpdateSelectionForNode<States, States[Key], Key>)
4653
4850
  }
4654
4851
  : {}
4655
4852
  : {}
@@ -4657,14 +4854,21 @@ export declare namespace Machine {
4657
4854
  type LocalTargetSelector<
4658
4855
  States extends StateSchemas,
4659
4856
  Source extends StateNodeIdentifier<States>
4660
- > = NearestCompoundScope<States, Source> extends infer Scope extends StateIdentifier<States> ?
4661
- ChildrenOf<States, Scope> extends infer Children extends StateSchemas ?
4662
- LocalTargetBuilder<States, Source> extends infer Builder ?
4663
- & SelectionTreeWithPrefix<States, Children, Scope, "local", Builder>
4664
- & ("with" extends keyof Builder ? {
4665
- readonly with: SelectionValue<Builder["with"], Scope>
4666
- }
4667
- : {})
4857
+ > = NearestCompoundScope<States, Source> extends infer Scope ? [Scope] extends [never] ? {}
4858
+ : Scope extends StateIdentifier<States> ?
4859
+ ChildrenOf<States, Scope> extends infer Children extends StateSchemas ?
4860
+ LocalTargetBuilder<States, Source> extends infer Builder ?
4861
+ & SelectionTreeWithPrefix<States, Children, Scope, "local", Builder>
4862
+ & ("with" extends keyof Builder ? {
4863
+ readonly with: SelectionValue<Builder["with"], Scope>
4864
+ }
4865
+ : {})
4866
+ & (Source extends ChoiceIdentifier<States> ? {}
4867
+ : Scope extends ValuedStateIdentifier<States> ? {
4868
+ readonly update: SelectionValue<StateUpdateBuilder<States, Scope>, Scope, "update">
4869
+ }
4870
+ : {})
4871
+ : {}
4668
4872
  : {}
4669
4873
  : {}
4670
4874
  : {}
@@ -4705,9 +4909,9 @@ export declare namespace Machine {
4705
4909
  > {
4706
4910
  /** Handles the trigger without selecting a destination. */
4707
4911
  readonly none: SelectionValue<TargetBuilder<States, Source>["none"], never, "none">
4708
- /** Selects a destination inside the nearest active compound scope. */
4912
+ /** Selects a destination or updates the nearest active compound scope. */
4709
4913
  readonly local: LocalTargetSelector<States, Source>
4710
- /** Selects a destination elsewhere under the currently active root. */
4914
+ /** Selects a destination or updates a valued active ancestor under the current root. */
4711
4915
  readonly branch: BranchTargetSelector<States, Source>
4712
4916
  /** Selects a complete destination under any top-level state. */
4713
4917
  readonly full: FullTargetSelector<States>
@@ -4799,6 +5003,8 @@ export declare namespace Machine {
4799
5003
  InputEvents extends ReadonlyArray<TaggedSchema> = Events,
4800
5004
  ParentEvents extends ReadonlyArray<TaggedSchema> = readonly []
4801
5005
  > = MachineReferences<InputEvents, ParentEvents> & {
5006
+ /** Process-owned child operations for dynamic child machine lifecycles. */
5007
+ readonly children: ChildOwner<EventOf<InputEvents>>
4802
5008
  /** Value owned by the state that owns this invocation. */
4803
5009
  readonly state: StateByIdentifier<States, StateId>
4804
5010
  /** Value owned by the nearest schema-backed ancestor, when one exists. */
@@ -5115,9 +5321,9 @@ export declare namespace Machine {
5115
5321
  * **Details**
5116
5322
  *
5117
5323
  * Handlers return snapshots for complete state replacement, target builder
5118
- * results for path-safe partial transitions, or `target.none()` for an
5119
- * explicitly targetless transition. Raw decoded state values and `void` are
5120
- * not accepted at transition boundaries.
5324
+ * results for path-safe partial transitions, state-value updates, or
5325
+ * `target.none()` for an explicitly targetless transition. Raw decoded state
5326
+ * values and `void` are not accepted at transition boundaries.
5121
5327
  *
5122
5328
  * @category utility types
5123
5329
  * @since 0.4.0
@@ -5127,11 +5333,13 @@ export declare namespace Machine {
5127
5333
  | Target<States, StateIdentifier<States>>
5128
5334
  | HistoryTarget<States, HistoryIdentifier<States>>
5129
5335
  | ChoiceTarget<States, ChoiceIdentifier<States>>
5336
+ | StateUpdate<States, ValuedStateIdentifier<States>>
5130
5337
  | StateConstruction<
5131
5338
  | Snapshot<States>
5132
5339
  | Target<States, StateIdentifier<States>>
5133
5340
  | HistoryTarget<States, HistoryIdentifier<States>>
5134
5341
  | ChoiceTarget<States, ChoiceIdentifier<States>>
5342
+ | StateUpdate<States, ValuedStateIdentifier<States>>
5135
5343
  >
5136
5344
  | NoTarget
5137
5345
 
@@ -5511,6 +5719,28 @@ export declare namespace Machine {
5511
5719
  | (SelectionKind<Selection> extends "none" ? undefined : SelectedTargetResult<Selection> | undefined)
5512
5720
  | Declined
5513
5721
 
5722
+ /** @internal */
5723
+ type StateUpdateResolver<
5724
+ Events extends ReadonlyArray<TaggedSchema>,
5725
+ Emits extends ReadonlyArray<TaggedSchema>,
5726
+ Context,
5727
+ Selection
5728
+ > = (
5729
+ context: TransitionResolveContext<Context, Selection>,
5730
+ enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>
5731
+ ) => SelectedTargetResult<Selection>
5732
+
5733
+ /** @internal */
5734
+ type DeclinableStateUpdateResolver<
5735
+ Events extends ReadonlyArray<TaggedSchema>,
5736
+ Emits extends ReadonlyArray<TaggedSchema>,
5737
+ Context,
5738
+ Selection
5739
+ > = (
5740
+ context: TransitionResolveContext<Context, Selection> & DeclineCapability,
5741
+ enqueue: Enqueue<EventOf<Events>, EmitOf<Emits>>
5742
+ ) => SelectedTargetResult<Selection> | Declined
5743
+
5514
5744
  /** One named destination declared by a branching transition. */
5515
5745
  export interface TransitionBranchInput<
5516
5746
  Selection extends TargetSelection<any, any, any> = TargetSelection<any, any, any>
@@ -5752,6 +5982,80 @@ export declare namespace Machine {
5752
5982
  : {}
5753
5983
  : {})
5754
5984
 
5985
+ /** @internal */
5986
+ interface StateUpdateTransitionRequired<
5987
+ States extends StateSchemas,
5988
+ Events extends ReadonlyArray<TaggedSchema>,
5989
+ Emits extends ReadonlyArray<TaggedSchema>,
5990
+ StateId extends StateNodeIdentifier<States>,
5991
+ Context,
5992
+ Reenter extends boolean,
5993
+ Selection extends TargetSelection<any, any, "update">
5994
+ > {
5995
+ (
5996
+ resolve: StateUpdateResolver<Events, Emits, Context, Selection>,
5997
+ options?: TransitionRequiredOptions<Reenter>
5998
+ ): BuiltTransition<
5999
+ States,
6000
+ Events,
6001
+ Emits,
6002
+ StateId,
6003
+ Context,
6004
+ Reenter,
6005
+ SelectedTargetResult<Selection>,
6006
+ "required"
6007
+ >
6008
+ }
6009
+
6010
+ /** @internal */
6011
+ interface StateUpdateTransitionDeclinable<
6012
+ States extends StateSchemas,
6013
+ Events extends ReadonlyArray<TaggedSchema>,
6014
+ Emits extends ReadonlyArray<TaggedSchema>,
6015
+ StateId extends StateNodeIdentifier<States>,
6016
+ Context,
6017
+ Reenter extends boolean,
6018
+ Selection extends TargetSelection<any, any, "update">
6019
+ > {
6020
+ (
6021
+ resolve: DeclinableStateUpdateResolver<Events, Emits, Context, Selection>,
6022
+ options: TransitionDeclinableOptions<Reenter>
6023
+ ): BuiltTransition<
6024
+ States,
6025
+ Events,
6026
+ Emits,
6027
+ StateId,
6028
+ Context,
6029
+ Reenter,
6030
+ SelectedTargetResult<Selection> | Declined,
6031
+ "declinable"
6032
+ >
6033
+ }
6034
+
6035
+ /** @internal */
6036
+ type StateUpdateTransition<
6037
+ States extends StateSchemas,
6038
+ Events extends ReadonlyArray<TaggedSchema>,
6039
+ Emits extends ReadonlyArray<TaggedSchema>,
6040
+ StateId extends StateNodeIdentifier<States>,
6041
+ Context,
6042
+ Reenter extends boolean,
6043
+ Acceptance extends TransitionAcceptance,
6044
+ Selection extends TargetSelection<any, any, "update">
6045
+ > =
6046
+ & Selection
6047
+ & StateUpdateTransitionRequired<States, Events, Emits, StateId, Context, Reenter, Selection>
6048
+ & ("declinable" extends Acceptance ? StateUpdateTransitionDeclinable<
6049
+ States,
6050
+ Events,
6051
+ Emits,
6052
+ StateId,
6053
+ Context,
6054
+ Reenter,
6055
+ Selection
6056
+ >
6057
+ : {})
6058
+
5755
6059
  /** @internal Type evidence retained by a machine initial-entry declaration. */
5756
6060
  export interface InitialBuilderEvidence<out Selection> {
5757
6061
  readonly [InitialBuilderTypeId]: Types.Covariant<Selection>
@@ -5805,19 +6109,18 @@ export declare namespace Machine {
5805
6109
  Reenter extends boolean,
5806
6110
  Acceptance extends TransitionAcceptance,
5807
6111
  Node
5808
- > = Node extends (...args: infer Args) => infer Selection ? Selection extends TargetSelection<any, any, any> ?
5809
- & ((...args: Args) => TransitionTarget<
5810
- States,
5811
- Events,
5812
- Emits,
5813
- StateId,
5814
- Context,
5815
- Reenter,
5816
- Acceptance,
5817
- Selection
5818
- >)
5819
- & {
5820
- readonly [Key in keyof Node]: TransitionSelectorNode<
6112
+ > = Node extends TargetSelection<any, any, "update"> ? StateUpdateTransition<
6113
+ States,
6114
+ Events,
6115
+ Emits,
6116
+ StateId,
6117
+ Context,
6118
+ Reenter,
6119
+ Acceptance,
6120
+ Node
6121
+ >
6122
+ : Node extends (...args: infer Args) => infer Selection ? Selection extends TargetSelection<any, any, any> ?
6123
+ & ((...args: Args) => TransitionTarget<
5821
6124
  States,
5822
6125
  Events,
5823
6126
  Emits,
@@ -5825,10 +6128,21 @@ export declare namespace Machine {
5825
6128
  Context,
5826
6129
  Reenter,
5827
6130
  Acceptance,
5828
- Node[Key]
5829
- >
5830
- }
5831
- : never
6131
+ Selection
6132
+ >)
6133
+ & {
6134
+ readonly [Key in keyof Node]: TransitionSelectorNode<
6135
+ States,
6136
+ Events,
6137
+ Emits,
6138
+ StateId,
6139
+ Context,
6140
+ Reenter,
6141
+ Acceptance,
6142
+ Node[Key]
6143
+ >
6144
+ }
6145
+ : never
5832
6146
  : Node extends TargetSelection<any, any, any> ? TransitionTarget<
5833
6147
  States,
5834
6148
  Events,
@@ -8632,9 +8946,10 @@ export const initialDefinition: <M extends Machine.Any>(machine: M) => Machine.I
8632
8946
  *
8633
8947
  * Event handlers retain their handler-key order within each source state and
8634
8948
  * are followed by eventless and completion handlers. This function does not
8635
- * execute resolvers. Every direct, named, and targetless branch exposes the
8636
- * destination selected by its required static `target` declaration, while
8637
- * `acceptance` reports whether the resolver may decline the transition.
8949
+ * execute resolvers. Every branch exposes its static selection. State updates
8950
+ * retain the updated owner in `selection.path` while leaving `target`
8951
+ * undefined because they do not change topology. `acceptance` reports whether
8952
+ * the resolver may decline the transition.
8638
8953
  *
8639
8954
  * @category getters
8640
8955
  * @since 0.4.0
@@ -8917,6 +9232,17 @@ export const logic: <
8917
9232
  export const child: <const Id extends string, M extends Machine.Any>(id: Id, machine: M) => ChildMachine<Id, M> =
8918
9233
  internal.child
8919
9234
 
9235
+ /**
9236
+ * Binds one machine definition to an open family of runtime child ids.
9237
+ *
9238
+ * Descriptors created by the returned function are interchangeable with
9239
+ * {@link child} descriptors for the same id and machine definition.
9240
+ *
9241
+ * @category constructors
9242
+ * @since 0.20.0
9243
+ */
9244
+ export const childFamily: <M extends Machine.Any>(machine: M) => ChildMachine.Family<M> = internal.childFamily
9245
+
8920
9246
  /**
8921
9247
  * Creates a typed parent-local address for lower-level child process logic.
8922
9248
  *
@@ -342,15 +342,7 @@ const makeChildFromRefAtom = <Child extends Machine.ChildMachine.Any, StartError
342
342
  }
343
343
  )
344
344
 
345
- const childFamily = Atom.family((nested: Machine.ChildMachine.Any) =>
346
- makeChildFromRefAtom(
347
- makeChildRefAtom(ref as any, nested),
348
- nested
349
- )
350
- )
351
- const child = <Nested extends Machine.ChildMachine.Any>(
352
- nested: Nested
353
- ): ChildMachineAtom<Nested, StartError> => childFamily(nested) as ChildMachineAtom<Nested, StartError>
345
+ const child = makeChildSelector<StartError>(ref as any)
354
346
 
355
347
  return {
356
348
  ref,
@@ -363,6 +355,30 @@ const makeChildFromRefAtom = <Child extends Machine.ChildMachine.Any, StartError
363
355
  }
364
356
  }
365
357
 
358
+ const makeChildSelector = <StartError>(
359
+ parentRef: Atom.Atom<
360
+ AsyncResult.AsyncResult<Option.Option<Machine.MachineRef<any, any, any, any, any>>, StartError>
361
+ >
362
+ ) => {
363
+ const byMachine = new WeakMap<object, (id: string) => ChildMachineAtom<Machine.ChildMachine.Any, StartError>>()
364
+ return <Child extends Machine.ChildMachine.Any>(descriptor: Child): ChildMachineAtom<Child, StartError> => {
365
+ let family = byMachine.get(descriptor.machine)
366
+ if (family === undefined) {
367
+ const machine = descriptor.machine
368
+ const atoms = Atom.family((id: string) => {
369
+ const child = internalMachine.child(id, machine)
370
+ return makeChildFromRefAtom(
371
+ makeChildRefAtom(parentRef as any, child),
372
+ child
373
+ )
374
+ })
375
+ family = (id) => atoms(id) as ChildMachineAtom<Machine.ChildMachine.Any, StartError>
376
+ byMachine.set(machine, family)
377
+ }
378
+ return family(descriptor.id) as ChildMachineAtom<Child, StartError>
379
+ }
380
+ }
381
+
366
382
  const makeFromRefAtom = <State, Event, Error, Output, StartError, Emitted>(
367
383
  ref: Atom.Atom<AsyncResult.AsyncResult<Machine.MachineRef<State, Event, Error, Output, Emitted>, StartError>>
368
384
  ): MachineAtom<State, Event, Error, Output, StartError, Emitted> => {
@@ -438,15 +454,7 @@ const makeFromRefAtom = <State, Event, Error, Output, StartError, Emitted>(
438
454
  )
439
455
 
440
456
  const optionalRef = Atom.mapResult(ref, Option.some)
441
- const childFamily = Atom.family((descriptor: Machine.ChildMachine.Any) =>
442
- makeChildFromRefAtom(
443
- makeChildRefAtom(optionalRef as any, descriptor),
444
- descriptor
445
- )
446
- )
447
- const child = <Child extends Machine.ChildMachine.Any>(
448
- descriptor: Child
449
- ): ChildMachineAtom<Child, StartError> => childFamily(descriptor) as ChildMachineAtom<Child, StartError>
457
+ const child = makeChildSelector<StartError>(optionalRef as any)
450
458
 
451
459
  return {
452
460
  ref,