@typeonce/effect-machine 0.27.1 → 0.29.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.
@@ -4,6 +4,7 @@
4
4
  * @since 0.4.0
5
5
  */
6
6
 
7
+ import { dual } from "effect/Function"
7
8
  import type * as Option from "effect/Option"
8
9
  import type * as Schema from "effect/Schema"
9
10
  import type * as Scope from "effect/Scope"
@@ -351,12 +352,43 @@ type SnapshotByIdentifier<State, Path extends SnapshotIdentifier<State>> = Snaps
351
352
 
352
353
  type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.ChildMachine.Ref<Child>>
353
354
 
355
+ type ChildSnapshot<Child extends Machine.ChildMachine.Any> = Machine.Machine.Snapshot<
356
+ Machine.Machine.States<Child["machine"]>
357
+ >
358
+
359
+ const InvalidSelectorPathTypeId = "~effect/reactivity/AtomMachine/InvalidSelectorPath"
360
+ const SelectorProjectionTypeId = "~effect/reactivity/AtomMachine/SelectorProjection"
361
+
362
+ type SelectorProjectionKind =
363
+ | "select"
364
+ | "selectSnapshot"
365
+ | "matches"
366
+ | "selectChild"
367
+ | "selectSnapshotChild"
368
+ | "matchesChild"
369
+
370
+ interface SelectorProjection<Kind extends SelectorProjectionKind, Path extends string> {
371
+ readonly [SelectorProjectionTypeId]: {
372
+ readonly kind: Kind
373
+ readonly path: Path
374
+ }
375
+ }
376
+
377
+ type EnsureSelectorPath<State, Path extends string> = [Path] extends [SnapshotIdentifier<State>] ? unknown : {
378
+ readonly [InvalidSelectorPathTypeId]: Path
379
+ }
380
+
381
+ type EnsureValuedSelectorPath<State, Path extends string> = [Path] extends [ValuedSnapshotIdentifier<State>] ? unknown
382
+ : {
383
+ readonly [InvalidSelectorPathTypeId]: Path
384
+ }
385
+
354
386
  /**
355
387
  * Selects the typed value for an active state path.
356
388
  *
357
389
  * Valid paths and their selected value types are inferred from the bridge.
358
- * The derived atom suppresses structurally equal updates. Keep the returned
359
- * atom stable when constructing it inside a component.
390
+ * The derived atom suppresses structurally equal updates. Repeated calls with
391
+ * the same bridge and path return the same atom.
360
392
  *
361
393
  * **Example**
362
394
  *
@@ -385,46 +417,110 @@ type ChildState<Child extends Machine.ChildMachine.Any> = RefState<Machine.Child
385
417
  * @category combinators
386
418
  * @since 0.4.0
387
419
  */
388
- export const select: <
389
- State extends Machine.Machine.AtomicSnapshot<string, unknown>,
390
- Event,
391
- Error,
392
- Output,
393
- StartError,
394
- Emitted,
395
- const Path extends ValuedSnapshotIdentifier<State>
396
- >(self: MachineAtom<State, Event, Error, Output, StartError, Emitted>, path: Path) => Atom.Atom<
397
- AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
398
- > = internal.select
420
+ export const select: {
421
+ <
422
+ State extends Machine.Machine.AtomicSnapshot<string, unknown> = never,
423
+ Event = never,
424
+ Error = never,
425
+ Output = never,
426
+ StartError = never,
427
+ Emitted = never,
428
+ const Path extends ValuedSnapshotIdentifier<State> = ValuedSnapshotIdentifier<State>
429
+ >(path: Path):
430
+ & SelectorProjection<"select", Path>
431
+ & ((self: MachineAtom<State, Event, Error, Output, StartError, Emitted>) => Atom.Atom<
432
+ AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
433
+ >)
434
+ <const Path extends string>(path: Path):
435
+ & SelectorProjection<"select", Path>
436
+ & (<
437
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
438
+ Event,
439
+ Error,
440
+ Output,
441
+ StartError,
442
+ Emitted
443
+ >(
444
+ self: MachineAtom<State, Event, Error, Output, StartError, Emitted> & EnsureValuedSelectorPath<State, Path>
445
+ ) => Atom.Atom<
446
+ AsyncResult.AsyncResult<
447
+ Option.Option<SnapshotValueByIdentifier<State, Extract<Path, ValuedSnapshotIdentifier<State>>>>,
448
+ StartError | Error
449
+ >
450
+ >)
451
+ <
452
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
453
+ Event,
454
+ Error,
455
+ Output,
456
+ StartError,
457
+ Emitted,
458
+ const Path extends ValuedSnapshotIdentifier<State>
459
+ >(self: MachineAtom<State, Event, Error, Output, StartError, Emitted>, path: Path): Atom.Atom<
460
+ AsyncResult.AsyncResult<Option.Option<SnapshotValueByIdentifier<State, Path>>, StartError | Error>
461
+ >
462
+ } = dual(2, internal.select)
399
463
 
400
464
  /**
401
465
  * Selects the typed logical snapshot for an active state path.
402
466
  *
403
467
  * Unlike {@link select}, the selected value retains its child snapshot
404
- * topology. The derived atom suppresses structurally equal updates. Keep the
405
- * returned atom stable when constructing it inside a component.
468
+ * topology. The derived atom suppresses structurally equal updates. Repeated
469
+ * calls with the same bridge and path return the same atom.
406
470
  *
407
471
  * @category combinators
408
472
  * @since 0.7.0
409
473
  */
410
- export const selectSnapshot: <
411
- State extends Machine.Machine.AtomicSnapshot<string, unknown>,
412
- Event,
413
- Error,
414
- Output,
415
- StartError,
416
- Emitted,
417
- const Path extends SnapshotIdentifier<State>
418
- >(self: MachineAtom<State, Event, Error, Output, StartError, Emitted>, path: Path) => Atom.Atom<
419
- AsyncResult.AsyncResult<Option.Option<SnapshotByIdentifier<State, Path>>, StartError | Error>
420
- > = internal.selectSnapshot
474
+ export const selectSnapshot: {
475
+ <
476
+ State extends Machine.Machine.AtomicSnapshot<string, unknown> = never,
477
+ Event = never,
478
+ Error = never,
479
+ Output = never,
480
+ StartError = never,
481
+ Emitted = never,
482
+ const Path extends SnapshotIdentifier<State> = SnapshotIdentifier<State>
483
+ >(path: Path):
484
+ & SelectorProjection<"selectSnapshot", Path>
485
+ & ((self: MachineAtom<State, Event, Error, Output, StartError, Emitted>) => Atom.Atom<
486
+ AsyncResult.AsyncResult<Option.Option<SnapshotByIdentifier<State, Path>>, StartError | Error>
487
+ >)
488
+ <const Path extends string>(path: Path):
489
+ & SelectorProjection<"selectSnapshot", Path>
490
+ & (<
491
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
492
+ Event,
493
+ Error,
494
+ Output,
495
+ StartError,
496
+ Emitted
497
+ >(
498
+ self: MachineAtom<State, Event, Error, Output, StartError, Emitted> & EnsureSelectorPath<State, Path>
499
+ ) => Atom.Atom<
500
+ AsyncResult.AsyncResult<
501
+ Option.Option<SnapshotByIdentifier<State, Extract<Path, SnapshotIdentifier<State>>>>,
502
+ StartError | Error
503
+ >
504
+ >)
505
+ <
506
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
507
+ Event,
508
+ Error,
509
+ Output,
510
+ StartError,
511
+ Emitted,
512
+ const Path extends SnapshotIdentifier<State>
513
+ >(self: MachineAtom<State, Event, Error, Output, StartError, Emitted>, path: Path): Atom.Atom<
514
+ AsyncResult.AsyncResult<Option.Option<SnapshotByIdentifier<State, Path>>, StartError | Error>
515
+ >
516
+ } = dual(2, internal.selectSnapshot)
421
517
 
422
518
  /**
423
519
  * Selects the typed value for an active state path in a directly owned child.
424
520
  *
425
521
  * Valid paths and their selected value types are inferred from the child
426
- * bridge. An inactive child produces `Option.none()`. Keep the returned atom
427
- * stable when constructing it inside a component.
522
+ * bridge. An inactive child produces `Option.none()`. Repeated calls with the
523
+ * same child bridge and path return the same atom.
428
524
  *
429
525
  * **Example**
430
526
  *
@@ -436,16 +532,45 @@ export const selectSnapshot: <
436
532
  * @category combinators
437
533
  * @since 0.4.0
438
534
  */
439
- export const selectChild: <
440
- Child extends Machine.ChildMachine.Any,
441
- StartError,
442
- const Path extends ValuedSnapshotIdentifier<ChildState<Child>>
443
- >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
444
- AsyncResult.AsyncResult<
445
- Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
446
- StartError | RefError<Machine.ChildMachine.Ref<Child>>
535
+ export const selectChild: {
536
+ <
537
+ Child extends Machine.ChildMachine.Any = never,
538
+ StartError = never,
539
+ const Path extends ValuedSnapshotIdentifier<ChildState<Child>> = ValuedSnapshotIdentifier<ChildState<Child>>
540
+ >(path: Path):
541
+ & SelectorProjection<"selectChild", Path>
542
+ & ((self: ChildMachineAtom<Child, StartError>) => Atom.Atom<
543
+ AsyncResult.AsyncResult<
544
+ Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
545
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
546
+ >
547
+ >)
548
+ <const Path extends string>(path: Path):
549
+ & SelectorProjection<"selectChild", Path>
550
+ & (<
551
+ Child extends Machine.ChildMachine.Any,
552
+ StartError
553
+ >(
554
+ self: ChildMachineAtom<Child, StartError> & EnsureValuedSelectorPath<ChildState<Child>, Path>
555
+ ) => Atom.Atom<
556
+ AsyncResult.AsyncResult<
557
+ Option.Option<
558
+ SnapshotValueByIdentifier<ChildState<Child>, Extract<Path, ValuedSnapshotIdentifier<ChildState<Child>>>>
559
+ >,
560
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
561
+ >
562
+ >)
563
+ <
564
+ Child extends Machine.ChildMachine.Any,
565
+ StartError,
566
+ const Path extends ValuedSnapshotIdentifier<ChildState<Child>>
567
+ >(self: ChildMachineAtom<Child, StartError>, path: Path): Atom.Atom<
568
+ AsyncResult.AsyncResult<
569
+ Option.Option<SnapshotValueByIdentifier<ChildState<Child>, Path>>,
570
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
571
+ >
447
572
  >
448
- > = internal.selectChild
573
+ } = dual(2, internal.selectChild)
449
574
 
450
575
  /**
451
576
  * Selects the typed logical snapshot for an active state path in an invoked
@@ -453,28 +578,57 @@ export const selectChild: <
453
578
  *
454
579
  * An inactive child or state path produces `Option.none()`. Unlike
455
580
  * {@link selectChild}, the selected value retains its child snapshot topology.
456
- * The derived atom suppresses structurally equal updates.
581
+ * The derived atom suppresses structurally equal updates. Repeated calls with
582
+ * the same child bridge and path return the same atom.
457
583
  *
458
584
  * @category combinators
459
585
  * @since 0.7.0
460
586
  */
461
- export const selectSnapshotChild: <
462
- Child extends Machine.ChildMachine.Any,
463
- StartError,
464
- const Path extends SnapshotIdentifier<ChildState<Child>>
465
- >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
466
- AsyncResult.AsyncResult<
467
- Option.Option<SnapshotByIdentifier<ChildState<Child>, Path>>,
468
- StartError | RefError<Machine.ChildMachine.Ref<Child>>
587
+ export const selectSnapshotChild: {
588
+ <
589
+ Child extends Machine.ChildMachine.Any = never,
590
+ StartError = never,
591
+ const Path extends SnapshotIdentifier<ChildState<Child>> = SnapshotIdentifier<ChildState<Child>>
592
+ >(path: Path):
593
+ & SelectorProjection<"selectSnapshotChild", Path>
594
+ & ((self: ChildMachineAtom<Child, StartError>) => Atom.Atom<
595
+ AsyncResult.AsyncResult<
596
+ Option.Option<SnapshotByIdentifier<ChildState<Child>, Path>>,
597
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
598
+ >
599
+ >)
600
+ <const Path extends string>(path: Path):
601
+ & SelectorProjection<"selectSnapshotChild", Path>
602
+ & (<
603
+ Child extends Machine.ChildMachine.Any,
604
+ StartError
605
+ >(
606
+ self: ChildMachineAtom<Child, StartError> & EnsureSelectorPath<ChildState<Child>, Path>
607
+ ) => Atom.Atom<
608
+ AsyncResult.AsyncResult<
609
+ Option.Option<SnapshotByIdentifier<ChildState<Child>, Extract<Path, SnapshotIdentifier<ChildState<Child>>>>>,
610
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
611
+ >
612
+ >)
613
+ <
614
+ Child extends Machine.ChildMachine.Any,
615
+ StartError,
616
+ const Path extends SnapshotIdentifier<ChildState<Child>>
617
+ >(self: ChildMachineAtom<Child, StartError>, path: Path): Atom.Atom<
618
+ AsyncResult.AsyncResult<
619
+ Option.Option<SnapshotByIdentifier<ChildState<Child>, Path>>,
620
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
621
+ >
469
622
  >
470
- > = internal.selectSnapshotChild
623
+ } = dual(2, internal.selectSnapshotChild)
471
624
 
472
625
  /**
473
626
  * Returns whether a state path is active.
474
627
  *
475
628
  * Valid paths are inferred from the bridge snapshot.
476
- * The derived atom suppresses equal updates. Runtime failures remain in the
477
- * typed failure channel.
629
+ * The derived atom suppresses equal updates. Repeated calls with the same
630
+ * bridge and path return the same atom. Runtime failures remain in the typed
631
+ * failure channel.
478
632
  *
479
633
  * **Example**
480
634
  *
@@ -501,36 +655,84 @@ export const selectSnapshotChild: <
501
655
  * @category combinators
502
656
  * @since 0.4.0
503
657
  */
504
- export const matches: <
505
- State extends Machine.Machine.AtomicSnapshot<string, unknown>,
506
- Event,
507
- Error,
508
- Output,
509
- StartError,
510
- Emitted,
511
- const Path extends SnapshotIdentifier<State>
512
- >(
513
- self: MachineAtom<State, Event, Error, Output, StartError, Emitted>,
514
- path: Path
515
- ) => Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>> = internal.matches
658
+ export const matches: {
659
+ <
660
+ State extends Machine.Machine.AtomicSnapshot<string, unknown> = never,
661
+ Event = never,
662
+ Error = never,
663
+ Output = never,
664
+ StartError = never,
665
+ Emitted = never,
666
+ const Path extends SnapshotIdentifier<State> = SnapshotIdentifier<State>
667
+ >(path: Path):
668
+ & SelectorProjection<"matches", Path>
669
+ & ((self: MachineAtom<State, Event, Error, Output, StartError, Emitted>) => Atom.Atom<
670
+ AsyncResult.AsyncResult<boolean, StartError | Error>
671
+ >)
672
+ <const Path extends string>(path: Path):
673
+ & SelectorProjection<"matches", Path>
674
+ & (<
675
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
676
+ Event,
677
+ Error,
678
+ Output,
679
+ StartError,
680
+ Emitted
681
+ >(
682
+ self: MachineAtom<State, Event, Error, Output, StartError, Emitted> & EnsureSelectorPath<State, Path>
683
+ ) => Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>>)
684
+ <
685
+ State extends Machine.Machine.AtomicSnapshot<string, unknown>,
686
+ Event,
687
+ Error,
688
+ Output,
689
+ StartError,
690
+ Emitted,
691
+ const Path extends SnapshotIdentifier<State>
692
+ >(
693
+ self: MachineAtom<State, Event, Error, Output, StartError, Emitted>,
694
+ path: Path
695
+ ): Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>>
696
+ } = dual(2, internal.matches)
516
697
 
517
698
  /**
518
699
  * Returns whether a state path is active in a directly owned child.
519
700
  *
520
701
  * Valid paths are inferred from the child bridge snapshot.
521
- * An inactive child produces `false`. Keep the returned atom stable when
522
- * constructing it inside a component.
702
+ * An inactive child produces `false`. Repeated calls with the same child
703
+ * bridge and path return the same atom.
523
704
  *
524
705
  * @category combinators
525
706
  * @since 0.4.0
526
707
  */
527
- export const matchesChild: <
528
- Child extends Machine.ChildMachine.Any,
529
- StartError,
530
- const Path extends SnapshotIdentifier<ChildState<Child>>
531
- >(self: ChildMachineAtom<Child, StartError>, path: Path) => Atom.Atom<
532
- AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
533
- > = internal.matchesChild
708
+ export const matchesChild: {
709
+ <
710
+ Child extends Machine.ChildMachine.Any = never,
711
+ StartError = never,
712
+ const Path extends SnapshotIdentifier<ChildState<Child>> = SnapshotIdentifier<ChildState<Child>>
713
+ >(path: Path):
714
+ & SelectorProjection<"matchesChild", Path>
715
+ & ((self: ChildMachineAtom<Child, StartError>) => Atom.Atom<
716
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
717
+ >)
718
+ <const Path extends string>(path: Path):
719
+ & SelectorProjection<"matchesChild", Path>
720
+ & (<
721
+ Child extends Machine.ChildMachine.Any,
722
+ StartError
723
+ >(
724
+ self: ChildMachineAtom<Child, StartError> & EnsureSelectorPath<ChildState<Child>, Path>
725
+ ) => Atom.Atom<
726
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
727
+ >)
728
+ <
729
+ Child extends Machine.ChildMachine.Any,
730
+ StartError,
731
+ const Path extends SnapshotIdentifier<ChildState<Child>>
732
+ >(self: ChildMachineAtom<Child, StartError>, path: Path): Atom.Atom<
733
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
734
+ >
735
+ } = dual(2, internal.matchesChild)
534
736
 
535
737
  const BoundRequirementsTypeId = "~effect/reactivity/AtomMachine/BoundRequirements"
536
738
 
@@ -602,6 +804,98 @@ type MachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
602
804
  Machine.Machine.EmittedEvent<M>
603
805
  >
604
806
 
807
+ type FamilyBridge = MachineAtom<any, never, any, any, any, any> | ChildMachineAtom<any, any>
808
+
809
+ type RootFamilySelectorProjection<State> =
810
+ | SelectorProjection<"select", ValuedSnapshotIdentifier<State>>
811
+ | SelectorProjection<"selectSnapshot", SnapshotIdentifier<State>>
812
+ | SelectorProjection<"matches", SnapshotIdentifier<State>>
813
+
814
+ type ChildFamilySelectorProjection<Child extends Machine.ChildMachine.Any> =
815
+ | SelectorProjection<"selectChild", ValuedSnapshotIdentifier<ChildSnapshot<Child>>>
816
+ | SelectorProjection<"selectSnapshotChild", SnapshotIdentifier<ChildSnapshot<Child>>>
817
+ | SelectorProjection<"matchesChild", SnapshotIdentifier<ChildSnapshot<Child>>>
818
+
819
+ type FamilyProjectionRecord<Bridge extends FamilyBridge, SelectorProjection = never> = Readonly<
820
+ Record<string, ((bridge: Bridge) => Atom.Atom<any>) | SelectorProjection>
821
+ >
822
+
823
+ type FamilyProjectedSelectorAtom<
824
+ Kind extends SelectorProjectionKind,
825
+ Path extends string,
826
+ Bridge extends FamilyBridge
827
+ > = Bridge extends
828
+ MachineAtom<infer State, infer _Event, infer Error, infer _Output, infer StartError, infer _Emitted> ?
829
+ Kind extends "select" ? Atom.Atom<
830
+ AsyncResult.AsyncResult<
831
+ Option.Option<SnapshotValueByIdentifier<State, Extract<Path, ValuedSnapshotIdentifier<State>>>>,
832
+ StartError | Error
833
+ >
834
+ >
835
+ : Kind extends "selectSnapshot" ? Atom.Atom<
836
+ AsyncResult.AsyncResult<
837
+ Option.Option<SnapshotByIdentifier<State, Extract<Path, SnapshotIdentifier<State>>>>,
838
+ StartError | Error
839
+ >
840
+ >
841
+ : Kind extends "matches" ? Atom.Atom<AsyncResult.AsyncResult<boolean, StartError | Error>>
842
+ : never
843
+ : Bridge extends ChildMachineAtom<infer Child, infer StartError> ? Kind extends "selectChild" ? Atom.Atom<
844
+ AsyncResult.AsyncResult<
845
+ Option.Option<
846
+ SnapshotValueByIdentifier<
847
+ ChildSnapshot<Child>,
848
+ Extract<Path, ValuedSnapshotIdentifier<ChildSnapshot<Child>>>
849
+ >
850
+ >,
851
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
852
+ >
853
+ >
854
+ : Kind extends "selectSnapshotChild" ? Atom.Atom<
855
+ AsyncResult.AsyncResult<
856
+ Option.Option<
857
+ SnapshotByIdentifier<ChildSnapshot<Child>, Extract<Path, SnapshotIdentifier<ChildSnapshot<Child>>>>
858
+ >,
859
+ StartError | RefError<Machine.ChildMachine.Ref<Child>>
860
+ >
861
+ >
862
+ : Kind extends "matchesChild" ? Atom.Atom<
863
+ AsyncResult.AsyncResult<boolean, StartError | RefError<Machine.ChildMachine.Ref<Child>>>
864
+ >
865
+ : never
866
+ : never
867
+
868
+ type FamilyProjectedAtom<Projection, Bridge extends FamilyBridge> = Projection extends
869
+ SelectorProjection<infer Kind, infer Path> ? FamilyProjectedSelectorAtom<Kind, Path, Bridge>
870
+ : Projection extends (bridge: Bridge) => infer Source ? Source extends Atom.Atom<any> ? Source : never
871
+ : never
872
+
873
+ type FamilyAtoms<
874
+ Key,
875
+ Bridge extends FamilyBridge,
876
+ Projections extends Readonly<Record<string, unknown>>
877
+ > = {
878
+ readonly [Name in keyof Projections]: (
879
+ key: Key
880
+ ) => Atom.WithoutSerializable<FamilyProjectedAtom<Projections[Name], Bridge>>
881
+ }
882
+
883
+ const FamilyInputRequiredTypeId = "~effect/reactivity/AtomMachine/FamilyInputRequired"
884
+
885
+ type EnsureFamilyInput<M extends Machine.Machine.Any> = [Machine.Machine.Input<M>] extends [never] ? {
886
+ readonly [FamilyInputRequiredTypeId]: "AtomMachine.family requires a machine with startup input"
887
+ }
888
+ : unknown
889
+
890
+ type FamilyOptions<
891
+ Key,
892
+ Bridge extends FamilyBridge,
893
+ Projections extends Readonly<Record<string, unknown>>
894
+ > = {
895
+ readonly atoms: Projections
896
+ readonly label?: (key: Key, atomName: keyof Projections & string) => string | undefined
897
+ }
898
+
605
899
  type ResumedMachineAtomOf<M extends Machine.Machine.Any, RuntimeError> = MachineAtom<
606
900
  Machine.Machine.Snapshot<Machine.Machine.States<M>>,
607
901
  Machine.Machine.EventInput<Machine.Machine.InputEvent<M>>,
@@ -644,8 +938,123 @@ export interface Bound<Services, RuntimeError = never> {
644
938
  & Machine.Machine.RootCompatible<Machine.Machine.ParentEvents<NoInfer<M>>>,
645
939
  snapshot: Machine.Machine.Snapshot<Machine.Machine.States<M>>
646
940
  ) => ResumedMachineAtomOf<M, RuntimeError>
941
+
942
+ /**
943
+ * Creates retained atom families for independent machine inputs using the
944
+ * bound runtime.
945
+ *
946
+ * Each machine input is also the family key. Every projected atom retains
947
+ * its private machine bridge while the projected atom remains reachable.
948
+ *
949
+ * @since 0.28.0
950
+ */
951
+ readonly family: <
952
+ M extends Machine.Machine.Any,
953
+ const Projections extends FamilyProjectionRecord<
954
+ MachineAtomOf<NoInfer<M>, RuntimeError>,
955
+ RootFamilySelectorProjection<Machine.Machine.Snapshot<Machine.Machine.States<NoInfer<M>>>>
956
+ >
957
+ >(
958
+ machine:
959
+ & M
960
+ & EnsureBoundRequirements<Services, NoInfer<M>>
961
+ & EnsureMachineExecutable<NoInfer<M>>
962
+ & Machine.Machine.RootCompatible<Machine.Machine.ParentEvents<NoInfer<M>>>
963
+ & EnsureFamilyInput<NoInfer<M>>,
964
+ options: FamilyOptions<
965
+ Machine.Machine.Input<NoInfer<M>>,
966
+ MachineAtomOf<NoInfer<M>, RuntimeError>,
967
+ Projections
968
+ >
969
+ ) => FamilyAtoms<Machine.Machine.Input<M>, MachineAtomOf<M, RuntimeError>, Projections>
647
970
  }
648
971
 
972
+ /**
973
+ * Creates retained atom families for independent machine inputs.
974
+ *
975
+ * The machine input is both startup input and family identity. Each property
976
+ * in `atoms` projects one public atom family from a private machine bridge.
977
+ * Retaining any projected atom retains that bridge without keeping its
978
+ * registry runtime mounted. Keys follow Effect `Equal` and `Hash` semantics.
979
+ * The optional `label` function labels each public projected atom.
980
+ *
981
+ * **Example**
982
+ *
983
+ * ```ts
984
+ * const processAtoms = AtomMachine.family(processMachine, {
985
+ * atoms: {
986
+ * ready: AtomMachine.matches("Ready"),
987
+ * state: (machine) => machine.state,
988
+ * send: (machine) => machine.send
989
+ * }
990
+ * })
991
+ *
992
+ * const readyAtom = processAtoms.ready("effect")
993
+ * const sendAtom = processAtoms.send("effect")
994
+ * ```
995
+ *
996
+ * @category constructors
997
+ * @since 0.28.0
998
+ */
999
+ export const family: <
1000
+ M extends Machine.Machine.Any,
1001
+ const Projections extends FamilyProjectionRecord<
1002
+ MachineAtomOf<NoInfer<M>, never>,
1003
+ RootFamilySelectorProjection<Machine.Machine.Snapshot<Machine.Machine.States<NoInfer<M>>>>
1004
+ >
1005
+ >(
1006
+ machine:
1007
+ & M
1008
+ & EnsureNoExternalRequirements<MachineRequirementsOf<NoInfer<M>>>
1009
+ & EnsureMachineExecutable<NoInfer<M>>
1010
+ & Machine.Machine.RootCompatible<Machine.Machine.ParentEvents<NoInfer<M>>>
1011
+ & EnsureFamilyInput<NoInfer<M>>,
1012
+ options: FamilyOptions<
1013
+ Machine.Machine.Input<NoInfer<M>>,
1014
+ MachineAtomOf<NoInfer<M>, never>,
1015
+ Projections
1016
+ >
1017
+ ) => FamilyAtoms<Machine.Machine.Input<M>, MachineAtomOf<M, never>, Projections> = internal.family as any
1018
+
1019
+ /**
1020
+ * Creates retained atom families for keyed direct-child lookup.
1021
+ *
1022
+ * The `child` function maps each family key to one direct child descriptor.
1023
+ * Every projected atom retains the resulting child bridge while the projected
1024
+ * atom remains reachable. Keys follow Effect `Equal` and `Hash` semantics.
1025
+ *
1026
+ * **Example**
1027
+ *
1028
+ * ```ts
1029
+ * const Plant = Machine.childFamily(plantMachine)
1030
+ *
1031
+ * const plantAtoms = AtomMachine.familyChild(parentMachineAtom, {
1032
+ * child: (plantId: string) => Plant(plantId),
1033
+ * atoms: {
1034
+ * broken: AtomMachine.matchesChild("Broken"),
1035
+ * state: (child) => child.state,
1036
+ * send: (child) => child.send
1037
+ * }
1038
+ * })
1039
+ * ```
1040
+ *
1041
+ * @category constructors
1042
+ * @since 0.28.0
1043
+ */
1044
+ export const familyChild: <
1045
+ Key,
1046
+ Parent extends MachineAtom<any, never, any, any, any, any> | ChildMachineAtom<any, any>,
1047
+ Child extends Machine.ChildMachine.Any,
1048
+ const Projections extends FamilyProjectionRecord<ChildOf<Parent, Child>, ChildFamilySelectorProjection<Child>>
1049
+ >(
1050
+ parent: Parent,
1051
+ options: {
1052
+ readonly child: (key: Key) => Child
1053
+ readonly atoms: Projections
1054
+ readonly label?: (key: Key, atomName: keyof Projections & string) => string | undefined
1055
+ }
1056
+ ) => FamilyAtoms<Key, ChildOf<Parent, Child>, Projections> = internal.familyChild as any
1057
+
649
1058
  /**
650
1059
  * Creates atoms backed by a running machine.
651
1060
  *