atom.io 0.36.3 → 0.37.1

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 (121) hide show
  1. package/dist/data/index.d.ts.map +1 -1
  2. package/dist/data/index.js.map +1 -1
  3. package/dist/eslint-plugin/index.js +1 -2
  4. package/dist/eslint-plugin/index.js.map +1 -1
  5. package/dist/internal/index.d.ts +71 -102
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +566 -515
  8. package/dist/internal/index.js.map +1 -1
  9. package/dist/introspection/index.d.ts +2 -2
  10. package/dist/introspection/index.d.ts.map +1 -1
  11. package/dist/introspection/index.js +1 -1
  12. package/dist/introspection/index.js.map +1 -1
  13. package/dist/json/index.d.ts +2 -1
  14. package/dist/json/index.d.ts.map +1 -1
  15. package/dist/json/index.js.map +1 -1
  16. package/dist/main/index.d.ts +154 -139
  17. package/dist/main/index.d.ts.map +1 -1
  18. package/dist/main/index.js.map +1 -1
  19. package/dist/react/index.d.ts.map +1 -1
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/react-devtools/index.d.ts.map +1 -1
  22. package/dist/react-devtools/index.js +54 -56
  23. package/dist/react-devtools/index.js.map +1 -1
  24. package/dist/realtime/index.d.ts.map +1 -1
  25. package/dist/realtime/index.js.map +1 -1
  26. package/dist/realtime-client/index.d.ts +3 -3
  27. package/dist/realtime-client/index.d.ts.map +1 -1
  28. package/dist/realtime-client/index.js +6 -6
  29. package/dist/realtime-client/index.js.map +1 -1
  30. package/dist/realtime-react/index.d.ts.map +1 -1
  31. package/dist/realtime-react/index.js.map +1 -1
  32. package/dist/realtime-server/index.d.ts +5 -5
  33. package/dist/realtime-server/index.d.ts.map +1 -1
  34. package/dist/realtime-server/index.js +10 -12
  35. package/dist/realtime-server/index.js.map +1 -1
  36. package/dist/realtime-testing/index.d.ts.map +1 -1
  37. package/dist/realtime-testing/index.js.map +1 -1
  38. package/dist/transceivers/set-rtx/index.d.ts +1 -1
  39. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  40. package/dist/transceivers/set-rtx/index.js +1 -3
  41. package/dist/transceivers/set-rtx/index.js.map +1 -1
  42. package/dist/use-o-DXPncKmZ.js.map +1 -1
  43. package/dist/web/index.d.ts +2 -2
  44. package/dist/web/index.d.ts.map +1 -1
  45. package/dist/web/index.js.map +1 -1
  46. package/package.json +6 -6
  47. package/src/internal/atom/dispose-atom.ts +16 -9
  48. package/src/internal/caching.ts +1 -1
  49. package/src/internal/families/create-readonly-held-selector-family.ts +3 -5
  50. package/src/internal/families/create-readonly-pure-selector-family.ts +3 -5
  51. package/src/internal/families/create-regular-atom-family.ts +7 -7
  52. package/src/internal/families/create-writable-held-selector-family.ts +3 -5
  53. package/src/internal/families/create-writable-pure-selector-family.ts +3 -5
  54. package/src/internal/families/find-in-store.ts +17 -34
  55. package/src/internal/families/init-family-member.ts +5 -87
  56. package/src/internal/families/mint-in-store.ts +74 -0
  57. package/src/internal/get-state/get-from-store.ts +19 -6
  58. package/src/internal/get-state/read-or-compute-value.ts +4 -2
  59. package/src/internal/index.ts +25 -36
  60. package/src/internal/ingest-updates/ingest-atom-update.ts +7 -7
  61. package/src/internal/ingest-updates/ingest-creation-disposal.ts +11 -11
  62. package/src/internal/ingest-updates/ingest-selector-update.ts +8 -4
  63. package/src/internal/ingest-updates/ingest-transaction-update.ts +5 -6
  64. package/src/internal/install-into-store.ts +2 -2
  65. package/src/internal/join/join-internal.ts +1 -1
  66. package/src/internal/molecule.ts +12 -9
  67. package/src/internal/mutable/create-mutable-atom-family.ts +4 -6
  68. package/src/internal/mutable/tracker.ts +2 -2
  69. package/src/internal/mutable/transceiver.ts +6 -4
  70. package/src/internal/operation.ts +17 -14
  71. package/src/internal/selector/create-readonly-held-selector.ts +9 -7
  72. package/src/internal/selector/create-readonly-pure-selector.ts +8 -5
  73. package/src/internal/selector/create-writable-held-selector.ts +12 -21
  74. package/src/internal/selector/create-writable-pure-selector.ts +15 -28
  75. package/src/internal/selector/dispose-selector.ts +6 -1
  76. package/src/internal/selector/get-selector-dependency-keys.ts +2 -6
  77. package/src/internal/selector/register-selector.ts +64 -74
  78. package/src/internal/selector/trace-selector-atoms.ts +2 -2
  79. package/src/internal/selector/update-selector-atoms.ts +2 -2
  80. package/src/internal/set-state/dispatch-state-update.ts +101 -0
  81. package/src/internal/set-state/operate-on-store.ts +126 -0
  82. package/src/internal/set-state/reset-atom-or-selector.ts +24 -15
  83. package/src/internal/set-state/set-atom-or-selector.ts +9 -4
  84. package/src/internal/set-state/set-atom.ts +4 -49
  85. package/src/internal/set-state/set-into-store.ts +11 -77
  86. package/src/internal/set-state/set-selector.ts +35 -0
  87. package/src/internal/store/store.ts +4 -4
  88. package/src/internal/subscribe/subscribe-in-store.ts +3 -3
  89. package/src/internal/subscribe/subscribe-to-timeline.ts +2 -2
  90. package/src/internal/timeline/create-timeline.ts +57 -101
  91. package/src/internal/timeline/time-travel.ts +1 -1
  92. package/src/internal/transaction/abort-transaction.ts +1 -1
  93. package/src/internal/transaction/apply-transaction.ts +7 -7
  94. package/src/internal/transaction/build-transaction.ts +10 -9
  95. package/src/internal/transaction/create-transaction.ts +4 -3
  96. package/src/internal/transaction/index.ts +6 -2
  97. package/src/introspection/attach-introspection-states.ts +2 -2
  98. package/src/introspection/attach-transaction-logs.ts +13 -6
  99. package/src/json/index.ts +3 -1
  100. package/src/main/atom.ts +2 -1
  101. package/src/main/events.ts +109 -0
  102. package/src/main/get-state.ts +1 -1
  103. package/src/main/index.ts +3 -0
  104. package/src/main/subscribe.ts +9 -19
  105. package/src/main/timeline.ts +3 -21
  106. package/src/main/transaction.ts +0 -65
  107. package/src/main/validators.ts +8 -2
  108. package/src/react-devtools/TimelineIndex.tsx +1 -1
  109. package/src/react-devtools/TransactionIndex.tsx +5 -3
  110. package/src/react-devtools/Updates.tsx +54 -46
  111. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +20 -10
  112. package/src/realtime-client/realtime-client-stores/client-sync-store.ts +4 -4
  113. package/src/realtime-client/sync-continuity.ts +1 -1
  114. package/src/realtime-server/continuity/prepare-to-serve-transaction-request.ts +14 -8
  115. package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +5 -2
  116. package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
  117. package/src/realtime-server/realtime-action-receiver.ts +6 -3
  118. package/src/realtime-server/realtime-server-stores/server-sync-store.ts +13 -16
  119. package/src/transceivers/set-rtx/set-rtx.ts +1 -3
  120. package/src/web/persist-sync.ts +2 -2
  121. package/src/internal/set-state/emit-update.ts +0 -40
@@ -449,7 +449,7 @@ function isChildStore(store) {
449
449
 
450
450
  //#endregion
451
451
  //#region src/internal/operation.ts
452
- const openOperation = (store, token) => {
452
+ function openOperation(store, token) {
453
453
  if (store.operation.open) {
454
454
  const rejectionTime = performance.now();
455
455
  store.logger.info(`❗`, token.type, token.key, `deferring setState at T-${rejectionTime} until setState for "${store.operation.token.key}" is done`);
@@ -459,16 +459,17 @@ const openOperation = (store, token) => {
459
459
  open: true,
460
460
  done: /* @__PURE__ */ new Set(),
461
461
  prev: /* @__PURE__ */ new Map(),
462
- time: Date.now(),
462
+ timestamp: Date.now(),
463
463
  token
464
464
  };
465
- store.logger.info(`⭕`, token.type, token.key, `operation start in store "${store.config.name}"${!isChildStore(store) ? `` : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`}`);
466
- };
467
- const closeOperation = (store) => {
465
+ store.logger.info(`⭕`, token.type, token.key, `operation start in store "${store.config.name}"${isChildStore(store) ? ` ${store.transactionMeta.phase} "${store.transactionMeta.update.token.key}"` : ``}`);
466
+ return store;
467
+ }
468
+ function closeOperation(store) {
468
469
  if (store.operation.open) store.logger.info(`🔴`, store.operation.token.type, store.operation.token.key, `operation done in store "${store.config.name}"`);
469
470
  store.operation = { open: false };
470
471
  store.on.operationClose.next(store.operation);
471
- };
472
+ }
472
473
  const isDone = (store, key) => {
473
474
  if (!store.operation.open) {
474
475
  store.logger.error(`🐞`, `unknown`, key, `isDone called outside of an operation. This is probably a bug in AtomIO.`);
@@ -585,7 +586,7 @@ function evictCachedValue(target, key) {
585
586
  const currentValue = target.valueMap.get(key);
586
587
  if (currentValue instanceof Future) {
587
588
  const selector = target.writableSelectors.get(key) ?? target.readonlySelectors.get(key);
588
- if (selector) selector.get();
589
+ if (selector) selector.getFrom(target);
589
590
  return;
590
591
  }
591
592
  if (target.operation.open) target.operation.prev.set(key, currentValue);
@@ -604,7 +605,7 @@ function readOrComputeValue(target, state, mut) {
604
605
  case `writable_held_selector`:
605
606
  case `writable_pure_selector`:
606
607
  target.logger.info(`🧮`, state.type, key, `computing value`);
607
- return state.get();
608
+ return state.getFrom(target);
608
609
  case `atom`: {
609
610
  let def;
610
611
  if (state.default instanceof Function) def = state.default();
@@ -623,33 +624,104 @@ function readOrComputeValue(target, state, mut) {
623
624
  }
624
625
 
625
626
  //#endregion
626
- //#region src/internal/set-state/become.ts
627
- const become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(originalThing) : nextVersionOfThing;
627
+ //#region src/internal/families/get-family-of-token.ts
628
+ function getFamilyOfToken(store, token) {
629
+ if (token.family) {
630
+ const family = store.families.get(token.family.key);
631
+ if (family) return family;
632
+ }
633
+ }
628
634
 
629
635
  //#endregion
630
- //#region src/internal/atom/has-role.ts
631
- const INTERNAL_ROLES = [`tracker:signal`];
632
- function hasRole(atom, role) {
633
- if (`internalRoles` in atom === false) return false;
634
- return atom.internalRoles.includes(role);
636
+ //#region src/internal/transaction/abort-transaction.ts
637
+ const abortTransaction = (store) => {
638
+ const target = newest(store);
639
+ if (!isChildStore(target)) {
640
+ store.logger.warn(`🐞`, `transaction`, `???`, `abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`);
641
+ return;
642
+ }
643
+ store.logger.info(`🪂`, `transaction`, target.transactionMeta.update.token.key, `Aborting transaction`);
644
+ target.parent.child = null;
645
+ };
646
+
647
+ //#endregion
648
+ //#region src/internal/capitalize.ts
649
+ function capitalize(string) {
650
+ return string[0].toUpperCase() + string.slice(1);
635
651
  }
636
652
 
637
653
  //#endregion
638
- //#region src/internal/set-state/emit-update.ts
639
- const emitUpdate = (store, state, update) => {
640
- switch (state.type) {
641
- case `mutable_atom`:
642
- store.logger.info(`📢`, state.type, state.key, `is now (`, update.newValue, `) subscribers:`, state.subject.subscribers);
643
- break;
644
- case `atom`:
645
- case `writable_pure_selector`:
646
- case `readonly_pure_selector`:
647
- case `writable_held_selector`:
648
- case `readonly_held_selector`: store.logger.info(`📢`, state.type, state.key, `went (`, update.oldValue, `->`, update.newValue, `) subscribers:`, state.subject.subscribers);
654
+ //#region src/internal/pretty-print.ts
655
+ function prettyPrintTokenType(token) {
656
+ return token.type.split(`_`).map(capitalize).join(` `);
657
+ }
658
+
659
+ //#endregion
660
+ //#region src/internal/not-found-error.ts
661
+ var NotFoundError = class extends Error {
662
+ constructor(token, store) {
663
+ super(`${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${store.config.name}".`);
649
664
  }
650
- state.subject.next(update);
651
665
  };
652
666
 
667
+ //#endregion
668
+ //#region src/internal/transaction/act-upon-store.ts
669
+ function actUponStore(store, token, id) {
670
+ return (...parameters) => {
671
+ const tx = withdraw(store, token);
672
+ if (tx) return tx.run(parameters, id);
673
+ throw new NotFoundError(token, store);
674
+ };
675
+ }
676
+
677
+ //#endregion
678
+ //#region src/internal/set-state/become.ts
679
+ const become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(originalThing) : nextVersionOfThing;
680
+
681
+ //#endregion
682
+ //#region src/internal/set-state/dispatch-state-update.ts
683
+ function dispatchOrDeferStateUpdate(target, state, [oldValue, newValue], _stateIsNewlyCreated) {
684
+ const { key, subject, type } = state;
685
+ const update = {
686
+ oldValue: isTransceiver(oldValue) ? oldValue.READONLY_VIEW : oldValue,
687
+ newValue: isTransceiver(newValue) ? newValue.READONLY_VIEW : newValue
688
+ };
689
+ if (isRootStore(target)) {
690
+ switch (type) {
691
+ case `mutable_atom`:
692
+ target.logger.info(`📢`, type, key, `is now (`, newValue, `) subscribers:`, subject.subscribers);
693
+ break;
694
+ case `atom`:
695
+ case `writable_pure_selector`:
696
+ case `writable_held_selector`: target.logger.info(`📢`, type, key, `went (`, oldValue, `->`, newValue, `) subscribers:`, subject.subscribers);
697
+ }
698
+ subject.next(update);
699
+ }
700
+ if (isChildStore(target) && (type === `mutable_atom` || type === `atom`)) {
701
+ if (target.on.transactionApplying.state === null) {
702
+ const token = deposit(state);
703
+ if (isTransceiver(newValue)) return;
704
+ const { timestamp } = target.operation;
705
+ const atomUpdate = {
706
+ type: `atom_update`,
707
+ token,
708
+ timestamp,
709
+ update
710
+ };
711
+ target.transactionMeta.update.subEvents.push(atomUpdate);
712
+ target.logger.info(`📁`, `atom`, key, `stowed (`, oldValue, `->`, newValue, `)`);
713
+ return;
714
+ }
715
+ if (hasRole(state, `tracker:signal`)) {
716
+ const keyOfMutable = key.slice(1);
717
+ const mutable = target.atoms.get(keyOfMutable);
718
+ const transceiver = readOrComputeValue(target, mutable, `mut`);
719
+ const accepted = transceiver.do(update.newValue) === null;
720
+ if (accepted === true) evictDownstreamFromAtom(target, mutable);
721
+ }
722
+ }
723
+ }
724
+
653
725
  //#endregion
654
726
  //#region src/internal/set-state/set-atom.ts
655
727
  const setAtom = (target, atom, next) => {
@@ -659,129 +731,49 @@ const setAtom = (target, atom, next) => {
659
731
  newValue = writeToCache(target, atom, newValue);
660
732
  markDone(target, atom.key);
661
733
  evictDownstreamFromAtom(target, atom);
662
- const update = {
663
- oldValue,
664
- newValue
665
- };
666
- if (!isChildStore(target)) {
667
- emitUpdate(target, atom, update);
668
- return;
669
- }
670
- if (target.on.transactionApplying.state === null) {
671
- const { key } = atom;
672
- if (isTransceiver(update.newValue)) return;
673
- const atomUpdate = {
674
- type: `atom_update`,
675
- key,
676
- ...update
677
- };
678
- if (atom.family) atomUpdate.family = atom.family;
679
- target.transactionMeta.update.updates.push(atomUpdate);
680
- target.logger.info(`📁`, `atom`, key, `stowed (`, update.oldValue, `->`, update.newValue, `)`);
681
- } else if (hasRole(atom, `tracker:signal`)) {
682
- const key = atom.key.slice(1);
683
- const mutable = target.atoms.get(key);
684
- const transceiver = readOrComputeValue(target, mutable, `mut`);
685
- const accepted = transceiver.do(update.newValue) === null;
686
- if (accepted === true) evictDownstreamFromAtom(target, mutable);
687
- }
734
+ return [oldValue, newValue];
688
735
  };
689
736
 
690
737
  //#endregion
691
738
  //#region src/internal/set-state/reset-atom-or-selector.ts
692
- function resetAtom(store, state) {
693
- switch (state.type) {
694
- case `mutable_atom`:
695
- setAtom(store, state, new state.class());
696
- return;
739
+ function resetAtom(target, atom) {
740
+ switch (atom.type) {
741
+ case `mutable_atom`: return setAtom(target, atom, new atom.class());
697
742
  case `atom`: {
698
- let def = state.default;
743
+ let def = atom.default;
699
744
  if (def instanceof Function) def = def();
700
- setAtom(store, state, def);
745
+ return setAtom(target, atom, def);
701
746
  }
702
747
  }
703
748
  }
704
- function resetAtomOrSelector(store, state) {
749
+ function resetAtomOrSelector(target, state) {
750
+ let protoUpdate;
705
751
  switch (state.type) {
706
752
  case `atom`:
707
753
  case `mutable_atom`:
708
- resetAtom(store, state);
754
+ protoUpdate = resetAtom(target, state);
709
755
  break;
710
756
  case `writable_pure_selector`:
711
757
  case `writable_held_selector`:
712
758
  {
713
- const atoms = traceRootSelectorAtoms(store, state.key);
714
- for (const atom of atoms.values()) resetAtom(store, atom);
759
+ const oldValue = state.getFrom(target);
760
+ const atoms = traceRootSelectorAtoms(target, state.key);
761
+ for (const atom of atoms.values()) {
762
+ const rootProtoUpdate = resetAtom(target, atom);
763
+ dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false);
764
+ }
765
+ const newValue = state.getFrom(target);
766
+ protoUpdate = [oldValue, newValue];
715
767
  }
716
768
  break;
717
769
  }
770
+ return protoUpdate;
718
771
  }
719
772
 
720
- //#endregion
721
- //#region src/internal/families/get-family-of-token.ts
722
- function getFamilyOfToken(store, token) {
723
- if (token.family) {
724
- const family = store.families.get(token.family.key);
725
- if (family) return family;
726
- }
727
- }
728
-
729
- //#endregion
730
- //#region src/internal/set-state/set-atom-or-selector.ts
731
- const setAtomOrSelector = (store, state, value) => {
732
- switch (state.type) {
733
- case `atom`:
734
- case `mutable_atom`:
735
- setAtom(store, state, value);
736
- break;
737
- case `writable_pure_selector`:
738
- case `writable_held_selector`:
739
- state.set(value);
740
- break;
741
- }
742
- };
743
-
744
773
  //#endregion
745
774
  //#region src/internal/set-state/set-into-store.ts
746
775
  function setIntoStore(store, ...params) {
747
- let token;
748
- let family;
749
- let key;
750
- let value;
751
- if (params.length === 2) {
752
- token = params[0];
753
- value = params[1];
754
- if (token.family) {
755
- family = getFamilyOfToken(store, token);
756
- key = parseJson(token.family.subKey);
757
- token = findInStore(store, family, key);
758
- }
759
- } else {
760
- family = params[0];
761
- key = params[1];
762
- value = params[2];
763
- token = findInStore(store, family, key);
764
- }
765
- const action = value === RESET_STATE ? `reset` : `set`;
766
- if (`counterfeit` in token && `family` in token) {
767
- const subKey = token.family.subKey;
768
- const disposal = store.disposalTraces.buffer.find((item) => item?.key === subKey);
769
- store.logger.error(`❌`, token.type, token.key, `could not be`, action, `because it was not found in the store "${store.config.name}".`, disposal ? `This state was previously disposed:\n${disposal.trace}` : `No previous disposal trace was found.`);
770
- return;
771
- }
772
- const rejectionTime = openOperation(store, token);
773
- if (rejectionTime) {
774
- const unsubscribe = store.on.operationClose.subscribe(`waiting to ${action} "${token.key}" at T-${rejectionTime}`, function waitUntilOperationCloseToSetState() {
775
- unsubscribe();
776
- store.logger.info(`🟢`, token.type, token.key, `resuming deferred`, action, `from T-${rejectionTime}`);
777
- setIntoStore(store, token, value);
778
- });
779
- return;
780
- }
781
- const state = withdraw(store, token);
782
- if (value === RESET_STATE) resetAtomOrSelector(store, state);
783
- else setAtomOrSelector(store, state, value);
784
- closeOperation(store);
776
+ operateOnStore(store, true, ...params);
785
777
  }
786
778
 
787
779
  //#endregion
@@ -802,233 +794,52 @@ function resetInStore(store, ...params) {
802
794
  }
803
795
 
804
796
  //#endregion
805
- //#region src/internal/keys.ts
806
- const isAtomKey = (store, key) => newest(store).atoms.has(key);
807
- const isSelectorKey = (store, key) => newest(store).writableSelectors.has(key);
808
- const isReadonlySelectorKey = (store, key) => newest(store).readonlySelectors.has(key);
809
- const isStateKey = (store, key) => isAtomKey(store, key) || isSelectorKey(store, key) || isReadonlySelectorKey(store, key);
810
-
811
- //#endregion
812
- //#region src/internal/selector/get-selector-dependency-keys.ts
813
- const getSelectorDependencyKeys = (store, key) => {
814
- const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(store, source));
815
- return sources;
816
- };
817
-
818
- //#endregion
819
- //#region src/internal/selector/trace-selector-atoms.ts
820
- const traceRootSelectorAtoms = (store, selectorKey, covered = /* @__PURE__ */ new Set()) => {
821
- const dependencies = getSelectorDependencyKeys(store, selectorKey);
822
- const roots = /* @__PURE__ */ new Map();
823
- while (dependencies.length > 0) {
824
- const dependencyKey = dependencies.pop();
825
- if (covered.has(dependencyKey)) continue;
826
- covered.add(dependencyKey);
827
- if (isAtomKey(store, dependencyKey)) {
828
- const atom = store.atoms.get(dependencyKey);
829
- roots.set(atom.key, atom);
830
- } else dependencies.push(...getSelectorDependencyKeys(store, dependencyKey));
831
- }
832
- return roots;
833
- };
834
-
835
- //#endregion
836
- //#region src/internal/selector/update-selector-atoms.ts
837
- const updateSelectorAtoms = (store, selectorType, selectorKey, dependency, covered) => {
838
- const target = newest(store);
839
- const { type: dependencyType, key: dependencyKey } = dependency;
840
- if (dependencyType === `atom` || dependencyType === `mutable_atom`) {
841
- target.selectorAtoms.set({
842
- selectorKey,
843
- atomKey: dependencyKey
844
- });
845
- store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atom "${dependencyKey}"`);
846
- } else {
847
- const rootKeys = traceRootSelectorAtoms(store, dependencyKey, covered);
848
- store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atoms: [ ${[...rootKeys.values()].map((root) => `"${root.key}"`).join(`, `)} ]`);
849
- for (const { key: atomKey } of rootKeys.values()) target.selectorAtoms = target.selectorAtoms.set({
850
- selectorKey,
851
- atomKey
852
- });
853
- }
854
- covered.add(dependencyKey);
855
- };
856
-
857
- //#endregion
858
- //#region src/internal/selector/register-selector.ts
859
- const registerSelector = (store, selectorType, selectorKey, covered) => ({
860
- get: (...params) => {
861
- const target = newest(store);
862
- let dependency;
863
- if (params.length === 2) {
864
- const [family, key] = params;
865
- dependency = findInStore(store, family, key);
866
- } else [dependency] = params;
867
- const dependencyState = withdraw(store, dependency);
868
- const dependencyValue = readOrComputeValue(store, dependencyState);
869
- const dependencyKey = dependency.key;
870
- store.logger.info(`🔌`, selectorType, selectorKey, `registers dependency ( "${dependencyKey}" =`, dependencyValue, `)`);
871
- target.selectorGraph.set({
872
- upstreamSelectorKey: dependencyKey,
873
- downstreamSelectorKey: selectorKey
874
- }, { source: dependency.key });
875
- updateSelectorAtoms(store, selectorType, selectorKey, dependency, covered);
876
- return dependencyValue;
877
- },
878
- set: ((...params) => {
879
- let token;
880
- let value;
881
- if (params.length === 2) {
882
- token = params[0];
883
- value = params[1];
884
- } else {
885
- const family = params[0];
886
- const key = params[1];
887
- value = params[2];
888
- token = findInStore(store, family, key);
889
- }
890
- const target = newest(store);
891
- const state = withdraw(target, token);
892
- setAtomOrSelector(target, state, value);
893
- }),
894
- find: ((...args) => findInStore(store, ...args)),
895
- json: (token) => getJsonToken(store, token)
896
- });
897
-
898
- //#endregion
899
- //#region src/internal/selector/create-readonly-held-selector.ts
900
- const createReadonlyHeldSelector = (store, options, family) => {
901
- const target = newest(store);
902
- const subject = new Subject();
903
- const covered = /* @__PURE__ */ new Set();
904
- const { key, const: constant } = options;
905
- const type = `readonly_held_selector`;
906
- const { get, find, json } = registerSelector(target, type, key, covered);
907
- const getSelf = () => {
908
- const innerTarget = newest(store);
909
- const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
910
- for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
911
- innerTarget.selectorAtoms.delete(key);
912
- options.get({
913
- get,
914
- find,
915
- json
916
- }, constant);
917
- writeToCache(newest(store), readonlySelector, constant);
918
- covered.clear();
919
- return constant;
920
- };
921
- const readonlySelector = {
922
- ...options,
923
- type,
924
- subject,
925
- install: (s) => createReadonlyHeldSelector(s, options, family),
926
- get: getSelf,
927
- ...family && { family }
928
- };
929
- target.readonlySelectors.set(key, readonlySelector);
930
- store.logger.info(`✨`, type, key, `=`, constant);
931
- const token = {
932
- key,
933
- type
934
- };
935
- if (family) token.family = family;
936
- return token;
937
- };
938
-
939
- //#endregion
940
- //#region src/internal/selector/create-readonly-pure-selector.ts
941
- const createReadonlyPureSelector = (store, options, family) => {
942
- const target = newest(store);
943
- const subject = new Subject();
944
- const covered = /* @__PURE__ */ new Set();
945
- const key = options.key;
946
- const type = `readonly_pure_selector`;
947
- const { get, find, json } = registerSelector(target, type, key, covered);
948
- const getSelf = () => {
949
- const innerTarget = newest(store);
950
- const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
951
- for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
952
- innerTarget.selectorAtoms.delete(key);
953
- const value = options.get({
954
- get,
955
- find,
956
- json
957
- });
958
- const cached = writeToCache(innerTarget, readonlySelector, value);
959
- store.logger.info(`✨`, type, key, `=`, cached);
960
- covered.clear();
961
- return cached;
962
- };
963
- const readonlySelector = {
964
- ...options,
965
- type,
966
- subject,
967
- install: (s) => createReadonlyPureSelector(s, options, family),
968
- get: getSelf,
969
- ...family && { family }
970
- };
971
- target.readonlySelectors.set(key, readonlySelector);
972
- const token = {
973
- key,
974
- type
975
- };
976
- if (family) token.family = family;
977
- return token;
978
- };
979
-
980
- //#endregion
981
- //#region src/internal/transaction/abort-transaction.ts
982
- const abortTransaction = (store) => {
983
- const target = newest(store);
984
- if (!isChildStore(target)) {
985
- store.logger.warn(`🐞`, `transaction`, `???`, `abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`);
986
- return;
797
+ //#region src/internal/set-state/set-selector.ts
798
+ function setSelector(target, selector, next) {
799
+ let oldValue;
800
+ let newValue;
801
+ let constant;
802
+ const { type, key } = selector;
803
+ switch (selector.type) {
804
+ case `writable_pure_selector`:
805
+ oldValue = selector.getFrom(target);
806
+ newValue = become(next)(oldValue);
807
+ writeToCache(target, selector, newValue);
808
+ break;
809
+ case `writable_held_selector`:
810
+ constant = selector.const;
811
+ become(next)(constant);
812
+ oldValue = constant;
813
+ newValue = constant;
987
814
  }
988
- store.logger.info(`🪂`, `transaction`, target.transactionMeta.update.key, `Aborting transaction`);
989
- target.parent.child = null;
990
- };
991
-
992
- //#endregion
993
- //#region src/internal/capitalize.ts
994
- function capitalize(string) {
995
- return string[0].toUpperCase() + string.slice(1);
996
- }
997
-
998
- //#endregion
999
- //#region src/internal/pretty-print.ts
1000
- function prettyPrintTokenType(token) {
1001
- return token.type.split(`_`).map(capitalize).join(` `);
815
+ target.logger.info(`📝`, type, key, `setting to`, newValue);
816
+ markDone(target, key);
817
+ selector.setSelf(newValue);
818
+ return [oldValue, newValue];
1002
819
  }
1003
820
 
1004
821
  //#endregion
1005
- //#region src/internal/not-found-error.ts
1006
- var NotFoundError = class extends Error {
1007
- constructor(token, store) {
1008
- super(`${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${store.config.name}".`);
1009
- }
1010
- };
1011
-
1012
- //#endregion
1013
- //#region src/internal/transaction/act-upon-store.ts
1014
- function actUponStore(store, token, id) {
1015
- return (...parameters) => {
1016
- const tx = withdraw(store, token);
1017
- if (tx) return tx.run(parameters, id);
1018
- throw new NotFoundError(token, store);
1019
- };
1020
- }
822
+ //#region src/internal/set-state/set-atom-or-selector.ts
823
+ const setAtomOrSelector = (target, state, value) => {
824
+ let protoUpdate;
825
+ switch (state.type) {
826
+ case `atom`:
827
+ case `mutable_atom`:
828
+ protoUpdate = setAtom(target, state, value);
829
+ break;
830
+ case `writable_pure_selector`:
831
+ case `writable_held_selector`:
832
+ protoUpdate = setSelector(target, state, value);
833
+ break;
834
+ }
835
+ return protoUpdate;
836
+ };
1021
837
 
1022
838
  //#endregion
1023
839
  //#region src/internal/ingest-updates/ingest-atom-update.ts
1024
840
  function ingestAtomUpdate(applying, atomUpdate, store) {
1025
- const { key, newValue, oldValue } = atomUpdate;
841
+ const { token, update: { newValue, oldValue } } = atomUpdate;
1026
842
  const value = applying === `newValue` ? newValue : oldValue;
1027
- const token = {
1028
- key,
1029
- type: `atom`
1030
- };
1031
- if (atomUpdate.family) Object.assign(token, { family: atomUpdate.family });
1032
843
  setIntoStore(store, token, value);
1033
844
  }
1034
845
 
@@ -1076,10 +887,11 @@ function allocateIntoStore(store, provenance, key, dependsOn = `any`) {
1076
887
  const creationEvent = {
1077
888
  type: `molecule_creation`,
1078
889
  key,
1079
- provenance: origin
890
+ provenance: origin,
891
+ timestamp: Date.now()
1080
892
  };
1081
893
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1082
- if (isTransaction) target.transactionMeta.update.updates.push(creationEvent);
894
+ if (isTransaction) target.transactionMeta.update.subEvents.push(creationEvent);
1083
895
  else target.on.moleculeCreation.next(creationEvent);
1084
896
  for (const claim of invalidKeys) {
1085
897
  const disposal = store.disposalTraces.buffer.find((item) => item?.key === claim);
@@ -1116,12 +928,13 @@ function deallocateFromStore(store, claim) {
1116
928
  type: `molecule_disposal`,
1117
929
  key: molecule.key,
1118
930
  values,
1119
- provenance
931
+ provenance,
932
+ timestamp: Date.now()
1120
933
  };
1121
934
  const target = newest(store);
1122
935
  target.molecules.delete(stringKey);
1123
936
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1124
- if (isTransaction) target.transactionMeta.update.updates.push(disposalEvent);
937
+ if (isTransaction) target.transactionMeta.update.subEvents.push(disposalEvent);
1125
938
  const relatedMolecules = store.moleculeGraph.getRelationEntries({ downstreamMoleculeKey: molecule.stringKey });
1126
939
  if (relatedMolecules) for (const [relatedStringKey, { source }] of relatedMolecules) if (source === molecule.stringKey) {
1127
940
  const relatedKey = parseJson(relatedStringKey);
@@ -1172,10 +985,11 @@ function claimWithinStore(store, newProvenance, claim, exclusive) {
1172
985
  key: molecule.key,
1173
986
  exclusive: Boolean(exclusive),
1174
987
  from: priorProvenance,
1175
- to: [newProvenanceMolecule.key]
988
+ to: [newProvenanceMolecule.key],
989
+ timestamp: Date.now()
1176
990
  };
1177
991
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1178
- if (isTransaction) target.transactionMeta.update.updates.push(transferEvent);
992
+ if (isTransaction) target.transactionMeta.update.subEvents.push(transferEvent);
1179
993
  return claim;
1180
994
  }
1181
995
 
@@ -1269,10 +1083,9 @@ function ingestSelectorUpdate(applying, selectorUpdate, store) {
1269
1083
  //#endregion
1270
1084
  //#region src/internal/ingest-updates/ingest-transaction-update.ts
1271
1085
  function ingestTransactionUpdate(applying, transactionUpdate, store) {
1272
- const updates = applying === `newValue` ? transactionUpdate.updates : [...transactionUpdate.updates].reverse();
1086
+ const updates = applying === `newValue` ? transactionUpdate.subEvents : [...transactionUpdate.subEvents].reverse();
1273
1087
  for (const updateFromTransaction of updates) switch (updateFromTransaction.type) {
1274
1088
  case `atom_update`:
1275
- case `selector_update`:
1276
1089
  ingestAtomUpdate(applying, updateFromTransaction, store);
1277
1090
  break;
1278
1091
  case `state_creation`:
@@ -1290,7 +1103,7 @@ function ingestTransactionUpdate(applying, transactionUpdate, store) {
1290
1103
  case `molecule_transfer`:
1291
1104
  ingestMoleculeTransferEvent(updateFromTransaction, applying, store);
1292
1105
  break;
1293
- case `transaction_update`:
1106
+ case `transaction_outcome`:
1294
1107
  ingestTransactionUpdate(applying, updateFromTransaction, store);
1295
1108
  break;
1296
1109
  }
@@ -1340,18 +1153,18 @@ const applyTransaction = (output, store) => {
1340
1153
  child.transactionMeta.update.output = output;
1341
1154
  parent.child = null;
1342
1155
  parent.on.transactionApplying.next(child.transactionMeta);
1343
- const { updates } = child.transactionMeta.update;
1344
- store.logger.info(`🛄`, `transaction`, child.transactionMeta.update.key, `Applying transaction with ${updates.length} updates:`, updates);
1156
+ const { subEvents: updates } = child.transactionMeta.update;
1157
+ store.logger.info(`🛄`, `transaction`, child.transactionMeta.update.token.key, `Applying transaction with ${updates.length} updates:`, updates);
1345
1158
  ingestTransactionUpdate(`newValue`, child.transactionMeta.update, parent);
1346
1159
  if (isRootStore(parent)) {
1347
- setEpochNumberOfAction(parent, child.transactionMeta.update.key, child.transactionMeta.update.epoch);
1160
+ setEpochNumberOfAction(parent, child.transactionMeta.update.token.key, child.transactionMeta.update.epoch);
1348
1161
  const myTransaction = withdraw(store, {
1349
- key: child.transactionMeta.update.key,
1162
+ key: child.transactionMeta.update.token.key,
1350
1163
  type: `transaction`
1351
1164
  });
1352
1165
  myTransaction?.subject.next(child.transactionMeta.update);
1353
- store.logger.info(`🛬`, `transaction`, child.transactionMeta.update.key, `Finished applying transaction.`);
1354
- } else if (isChildStore(parent)) parent.transactionMeta.update.updates.push(child.transactionMeta.update);
1166
+ store.logger.info(`🛬`, `transaction`, child.transactionMeta.update.token.key, `Finished applying transaction.`);
1167
+ } else if (isChildStore(parent)) parent.transactionMeta.update.subEvents.push(child.transactionMeta.update);
1355
1168
  parent.on.transactionApplying.next(null);
1356
1169
  };
1357
1170
 
@@ -1407,7 +1220,7 @@ var LazyMap = class extends Map {
1407
1220
 
1408
1221
  //#endregion
1409
1222
  //#region src/internal/transaction/build-transaction.ts
1410
- const buildTransaction = (store, key, params, id) => {
1223
+ const buildTransaction = (store, token, params, id) => {
1411
1224
  const parent = newest(store);
1412
1225
  const childBase = {
1413
1226
  parent,
@@ -1438,15 +1251,16 @@ const buildTransaction = (store, key, params, id) => {
1438
1251
  moleculeJoins: new Junction(parent.moleculeJoins.toJSON(), { makeContentKey: parent.moleculeJoins.makeContentKey }),
1439
1252
  miscResources: new LazyMap(parent.miscResources)
1440
1253
  };
1441
- const epoch = getEpochNumberOfAction(store, key);
1254
+ const epoch = getEpochNumberOfAction(store, token.key);
1442
1255
  const transactionMeta = {
1443
1256
  phase: `building`,
1444
1257
  update: {
1445
- type: `transaction_update`,
1446
- key,
1258
+ type: `transaction_outcome`,
1259
+ token,
1447
1260
  id,
1448
1261
  epoch: epoch === void 0 ? NaN : epoch + 1,
1449
- updates: [],
1262
+ timestamp: Date.now(),
1263
+ subEvents: [],
1450
1264
  params,
1451
1265
  output: void 0
1452
1266
  },
@@ -1458,9 +1272,9 @@ const buildTransaction = (store, key, params, id) => {
1458
1272
  reset: ((...ps) => {
1459
1273
  resetInStore(child, ...ps);
1460
1274
  }),
1461
- run: (token, identifier = arbitrary()) => actUponStore(child, token, identifier),
1275
+ run: (t, identifier = arbitrary()) => actUponStore(child, t, identifier),
1462
1276
  find: ((...ps) => findInStore(store, ...ps)),
1463
- json: (token) => getJsonToken(child, token),
1277
+ json: (t) => getJsonToken(child, t),
1464
1278
  dispose: ((...ps) => {
1465
1279
  disposeFromStore(child, ...ps);
1466
1280
  }),
@@ -1469,7 +1283,7 @@ const buildTransaction = (store, key, params, id) => {
1469
1283
  };
1470
1284
  const child = Object.assign(childBase, { transactionMeta });
1471
1285
  parent.child = child;
1472
- store.logger.info(`🛫`, `transaction`, key, `Building transaction with params:`, params);
1286
+ store.logger.info(`🛫`, `transaction`, token.key, `Building transaction with params:`, params);
1473
1287
  return child;
1474
1288
  };
1475
1289
 
@@ -1482,7 +1296,8 @@ function createTransaction(store, options) {
1482
1296
  key,
1483
1297
  type: `transaction`,
1484
1298
  run: (params, id) => {
1485
- const childStore = buildTransaction(store, key, params, id);
1299
+ const token$1 = deposit(newTransaction);
1300
+ const childStore = buildTransaction(store, token$1, params, id);
1486
1301
  try {
1487
1302
  const target$1 = newest(store);
1488
1303
  const { toolkit } = childStore.transactionMeta;
@@ -1513,9 +1328,279 @@ const TRANSACTION_PHASES = [
1513
1328
  `applying`
1514
1329
  ];
1515
1330
 
1331
+ //#endregion
1332
+ //#region src/internal/families/init-family-member.ts
1333
+ function initFamilyMemberInStore(store, token, key) {
1334
+ const family = withdraw(store, token);
1335
+ const state = family(key);
1336
+ return state;
1337
+ }
1338
+
1339
+ //#endregion
1340
+ //#region src/internal/families/mint-in-store.ts
1341
+ function mintInStore(store, familyToken, key) {
1342
+ const stringKey = stringifyJson(key);
1343
+ const molecule = store.molecules.get(stringKey);
1344
+ if (!molecule && store.config.lifespan === `immortal`) {
1345
+ const fakeToken = counterfeit(familyToken, key);
1346
+ store.logger.error(`❌`, fakeToken.type, fakeToken.key, `was not found in store "${store.config.name}"; returned a counterfeit token.`);
1347
+ return fakeToken;
1348
+ }
1349
+ const newStateToken = initFamilyMemberInStore(store, familyToken, key);
1350
+ const target = newest(store);
1351
+ if (newStateToken.family) {
1352
+ if (isRootStore(target)) switch (newStateToken.type) {
1353
+ case `atom`:
1354
+ case `mutable_atom`:
1355
+ store.on.atomCreation.next(newStateToken);
1356
+ break;
1357
+ case `writable_pure_selector`:
1358
+ case `readonly_pure_selector`:
1359
+ case `writable_held_selector`:
1360
+ case `readonly_held_selector`:
1361
+ store.on.selectorCreation.next(newStateToken);
1362
+ break;
1363
+ }
1364
+ else if (isChildStore(target) && target.on.transactionApplying.state === null) target.transactionMeta.update.subEvents.push({
1365
+ type: `state_creation`,
1366
+ token: newStateToken,
1367
+ timestamp: Date.now()
1368
+ });
1369
+ }
1370
+ if (molecule) target.moleculeData.set(stringKey, familyToken.key);
1371
+ return newStateToken;
1372
+ }
1373
+
1374
+ //#endregion
1375
+ //#region src/internal/set-state/operate-on-store.ts
1376
+ function operateOnStore(store, ownOp, ...params) {
1377
+ let existingToken;
1378
+ let brandNewToken;
1379
+ let token;
1380
+ let family;
1381
+ let key;
1382
+ let value;
1383
+ if (params.length === 2) {
1384
+ token = params[0];
1385
+ value = params[1];
1386
+ if (token.family) {
1387
+ family = getFamilyOfToken(store, token);
1388
+ key = parseJson(token.family.subKey);
1389
+ existingToken = seekInStore(store, family, key);
1390
+ if (!existingToken) {
1391
+ brandNewToken = mintInStore(store, family, key);
1392
+ token = brandNewToken;
1393
+ } else token = existingToken;
1394
+ }
1395
+ } else {
1396
+ family = params[0];
1397
+ key = params[1];
1398
+ value = params[2];
1399
+ existingToken = seekInStore(store, family, key);
1400
+ if (!existingToken) {
1401
+ brandNewToken = mintInStore(store, family, key);
1402
+ token = brandNewToken;
1403
+ } else token = existingToken;
1404
+ }
1405
+ const action = value === RESET_STATE ? `reset` : `set`;
1406
+ let target;
1407
+ if (ownOp) {
1408
+ const result = openOperation(store, token);
1409
+ const rejected = typeof result === `number`;
1410
+ if (rejected) {
1411
+ const rejectionTime = result;
1412
+ const unsubscribe = store.on.operationClose.subscribe(`waiting to ${action} "${token.key}" at T-${rejectionTime}`, function waitUntilOperationCloseToSetState() {
1413
+ unsubscribe();
1414
+ store.logger.info(`🟢`, token.type, token.key, `resuming deferred`, action, `from T-${rejectionTime}`);
1415
+ operateOnStore(store, ownOp, token, value);
1416
+ });
1417
+ return;
1418
+ }
1419
+ target = result;
1420
+ } else target = store;
1421
+ if (`counterfeit` in token && `family` in token) {
1422
+ const subKey = token.family.subKey;
1423
+ const disposal = store.disposalTraces.buffer.find((item) => item?.key === subKey);
1424
+ store.logger.error(`❌`, token.type, token.key, `could not be`, action, `because it was not found in the store "${store.config.name}".`, disposal ? `This state was previously disposed:\n${disposal.trace}` : `No previous disposal trace was found.`);
1425
+ return;
1426
+ }
1427
+ const state = withdraw(target, token);
1428
+ let protoUpdate;
1429
+ if (value === RESET_STATE) protoUpdate = resetAtomOrSelector(target, state);
1430
+ else protoUpdate = setAtomOrSelector(target, state, value);
1431
+ const isNewlyCreated = Boolean(brandNewToken);
1432
+ dispatchOrDeferStateUpdate(target, state, protoUpdate, isNewlyCreated);
1433
+ if (ownOp) closeOperation(target);
1434
+ }
1435
+
1436
+ //#endregion
1437
+ //#region src/internal/keys.ts
1438
+ const isAtomKey = (store, key) => newest(store).atoms.has(key);
1439
+ const isSelectorKey = (store, key) => newest(store).writableSelectors.has(key);
1440
+ const isReadonlySelectorKey = (store, key) => newest(store).readonlySelectors.has(key);
1441
+ const isStateKey = (store, key) => isAtomKey(store, key) || isSelectorKey(store, key) || isReadonlySelectorKey(store, key);
1442
+
1443
+ //#endregion
1444
+ //#region src/internal/selector/get-selector-dependency-keys.ts
1445
+ function getSelectorDependencyKeys(store, key) {
1446
+ const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(store, source));
1447
+ return sources;
1448
+ }
1449
+
1450
+ //#endregion
1451
+ //#region src/internal/selector/trace-selector-atoms.ts
1452
+ function traceRootSelectorAtoms(store, selectorKey, covered = /* @__PURE__ */ new Set()) {
1453
+ const dependencies = getSelectorDependencyKeys(store, selectorKey);
1454
+ const roots = /* @__PURE__ */ new Map();
1455
+ while (dependencies.length > 0) {
1456
+ const dependencyKey = dependencies.pop();
1457
+ if (covered.has(dependencyKey)) continue;
1458
+ covered.add(dependencyKey);
1459
+ if (isAtomKey(store, dependencyKey)) {
1460
+ const atom = store.atoms.get(dependencyKey);
1461
+ roots.set(atom.key, atom);
1462
+ } else dependencies.push(...getSelectorDependencyKeys(store, dependencyKey));
1463
+ }
1464
+ return roots;
1465
+ }
1466
+
1467
+ //#endregion
1468
+ //#region src/internal/selector/update-selector-atoms.ts
1469
+ function updateSelectorAtoms(store, selectorType, selectorKey, dependency, covered) {
1470
+ const target = newest(store);
1471
+ const { type: dependencyType, key: dependencyKey } = dependency;
1472
+ if (dependencyType === `atom` || dependencyType === `mutable_atom`) {
1473
+ target.selectorAtoms.set({
1474
+ selectorKey,
1475
+ atomKey: dependencyKey
1476
+ });
1477
+ store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atom "${dependencyKey}"`);
1478
+ } else {
1479
+ const rootKeys = traceRootSelectorAtoms(store, dependencyKey, covered);
1480
+ store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atoms: [ ${[...rootKeys.values()].map((root) => `"${root.key}"`).join(`, `)} ]`);
1481
+ for (const { key: atomKey } of rootKeys.values()) target.selectorAtoms = target.selectorAtoms.set({
1482
+ selectorKey,
1483
+ atomKey
1484
+ });
1485
+ }
1486
+ covered.add(dependencyKey);
1487
+ }
1488
+
1489
+ //#endregion
1490
+ //#region src/internal/selector/register-selector.ts
1491
+ function registerSelector(store, selectorType, selectorKey, covered) {
1492
+ return {
1493
+ get: (...params) => {
1494
+ const target = newest(store);
1495
+ let dependency;
1496
+ if (params.length === 2) {
1497
+ const [family, key] = params;
1498
+ dependency = findInStore(store, family, key);
1499
+ } else [dependency] = params;
1500
+ const dependencyState = withdraw(store, dependency);
1501
+ const dependencyValue = readOrComputeValue(store, dependencyState);
1502
+ const dependencyKey = dependency.key;
1503
+ store.logger.info(`🔌`, selectorType, selectorKey, `registers dependency ( "${dependencyKey}" =`, dependencyValue, `)`);
1504
+ target.selectorGraph.set({
1505
+ upstreamSelectorKey: dependencyKey,
1506
+ downstreamSelectorKey: selectorKey
1507
+ }, { source: dependency.key });
1508
+ updateSelectorAtoms(store, selectorType, selectorKey, dependency, covered);
1509
+ return dependencyValue;
1510
+ },
1511
+ set: ((...params) => {
1512
+ const target = newest(store);
1513
+ operateOnStore(target, false, ...params);
1514
+ }),
1515
+ find: ((...args) => findInStore(store, ...args)),
1516
+ json: (token) => getJsonToken(store, token)
1517
+ };
1518
+ }
1519
+
1520
+ //#endregion
1521
+ //#region src/internal/selector/create-readonly-held-selector.ts
1522
+ function createReadonlyHeldSelector(store, options, family) {
1523
+ const target = newest(store);
1524
+ const subject = new Subject();
1525
+ const covered = /* @__PURE__ */ new Set();
1526
+ const { key, const: constant } = options;
1527
+ const type = `readonly_held_selector`;
1528
+ const { get, find, json } = registerSelector(target, type, key, covered);
1529
+ const getFrom = (innerTarget) => {
1530
+ const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1531
+ for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1532
+ innerTarget.selectorAtoms.delete(key);
1533
+ options.get({
1534
+ get,
1535
+ find,
1536
+ json
1537
+ }, constant);
1538
+ writeToCache(innerTarget, readonlySelector, constant);
1539
+ covered.clear();
1540
+ return constant;
1541
+ };
1542
+ const readonlySelector = {
1543
+ ...options,
1544
+ type,
1545
+ subject,
1546
+ getFrom,
1547
+ install: (s) => createReadonlyHeldSelector(s, options, family)
1548
+ };
1549
+ if (family) readonlySelector.family = family;
1550
+ target.readonlySelectors.set(key, readonlySelector);
1551
+ store.logger.info(`✨`, type, key, `=`, constant);
1552
+ const token = {
1553
+ key,
1554
+ type
1555
+ };
1556
+ if (family) token.family = family;
1557
+ return token;
1558
+ }
1559
+
1560
+ //#endregion
1561
+ //#region src/internal/selector/create-readonly-pure-selector.ts
1562
+ function createReadonlyPureSelector(store, options, family) {
1563
+ const target = newest(store);
1564
+ const subject = new Subject();
1565
+ const covered = /* @__PURE__ */ new Set();
1566
+ const key = options.key;
1567
+ const type = `readonly_pure_selector`;
1568
+ const { get, find, json } = registerSelector(target, type, key, covered);
1569
+ const getFrom = () => {
1570
+ const innerTarget = newest(store);
1571
+ const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1572
+ for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1573
+ innerTarget.selectorAtoms.delete(key);
1574
+ const value = options.get({
1575
+ get,
1576
+ find,
1577
+ json
1578
+ });
1579
+ const cached = writeToCache(innerTarget, readonlySelector, value);
1580
+ store.logger.info(`✨`, type, key, `=`, cached);
1581
+ covered.clear();
1582
+ return cached;
1583
+ };
1584
+ const readonlySelector = {
1585
+ ...options,
1586
+ type,
1587
+ subject,
1588
+ getFrom,
1589
+ install: (s) => createReadonlyPureSelector(s, options, family)
1590
+ };
1591
+ if (family) readonlySelector.family = family;
1592
+ target.readonlySelectors.set(key, readonlySelector);
1593
+ const token = {
1594
+ key,
1595
+ type
1596
+ };
1597
+ if (family) token.family = family;
1598
+ return token;
1599
+ }
1600
+
1516
1601
  //#endregion
1517
1602
  //#region src/internal/selector/create-writable-held-selector.ts
1518
- const createWritableHeldSelector = (store, options, family) => {
1603
+ function createWritableHeldSelector(store, options, family) {
1519
1604
  const target = newest(store);
1520
1605
  const subject = new Subject();
1521
1606
  const covered = /* @__PURE__ */ new Set();
@@ -1528,38 +1613,28 @@ const createWritableHeldSelector = (store, options, family) => {
1528
1613
  get,
1529
1614
  json
1530
1615
  };
1531
- const getSelf = (getFn = options.get, innerTarget = newest(store)) => {
1616
+ const getFrom = (innerTarget) => {
1532
1617
  const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1533
1618
  for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1534
1619
  innerTarget.selectorAtoms.delete(key);
1535
- getFn(getterToolkit, constant);
1620
+ options.get(getterToolkit, constant);
1536
1621
  writeToCache(innerTarget, mySelector, constant);
1537
1622
  store.logger.info(`✨`, type, key, `=`, constant);
1538
1623
  covered.clear();
1539
1624
  return constant;
1540
1625
  };
1541
- const setSelf = (next) => {
1542
- const innerTarget = newest(store);
1543
- const oldValue = getSelf(options.get, innerTarget);
1544
- const newValue = become(next)(oldValue);
1545
- store.logger.info(`📝`, type, key, `set (`, oldValue, `->`, newValue, `)`);
1546
- writeToCache(innerTarget, mySelector, newValue);
1547
- markDone(innerTarget, key);
1548
- if (isRootStore(innerTarget)) subject.next({
1549
- newValue,
1550
- oldValue
1551
- });
1552
- options.set(setterToolkit, newValue);
1626
+ const setSelf = () => {
1627
+ options.set(setterToolkit, constant);
1553
1628
  };
1554
1629
  const mySelector = {
1555
1630
  ...options,
1556
1631
  type,
1557
1632
  subject,
1558
- install: (s) => createWritableHeldSelector(s, options, family),
1559
- get: getSelf,
1560
- set: setSelf,
1561
- ...family && { family }
1633
+ getFrom,
1634
+ setSelf,
1635
+ install: (s) => createWritableHeldSelector(s, options, family)
1562
1636
  };
1637
+ if (family) mySelector.family = family;
1563
1638
  target.writableSelectors.set(key, mySelector);
1564
1639
  const token = {
1565
1640
  key,
@@ -1567,11 +1642,11 @@ const createWritableHeldSelector = (store, options, family) => {
1567
1642
  };
1568
1643
  if (family) token.family = family;
1569
1644
  return token;
1570
- };
1645
+ }
1571
1646
 
1572
1647
  //#endregion
1573
1648
  //#region src/internal/selector/create-writable-pure-selector.ts
1574
- const createWritablePureSelector = (store, options, family) => {
1649
+ function createWritablePureSelector(store, options, family) {
1575
1650
  const target = newest(store);
1576
1651
  const subject = new Subject();
1577
1652
  const covered = /* @__PURE__ */ new Set();
@@ -1584,40 +1659,30 @@ const createWritablePureSelector = (store, options, family) => {
1584
1659
  get,
1585
1660
  json
1586
1661
  };
1587
- const getSelf = (getFn = options.get, innerTarget = newest(store)) => {
1662
+ const getFrom = (innerTarget) => {
1588
1663
  const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1589
1664
  for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1590
1665
  innerTarget.selectorAtoms.delete(key);
1591
- const value = getFn(getterToolkit);
1666
+ const value = options.get(getterToolkit);
1592
1667
  const cached = writeToCache(innerTarget, mySelector, value);
1593
1668
  store.logger.info(`✨`, type, key, `=`, cached);
1594
1669
  covered.clear();
1595
1670
  return cached;
1596
1671
  };
1597
- const setSelf = (next) => {
1598
- const innerTarget = newest(store);
1599
- const oldValue = getSelf(options.get, innerTarget);
1600
- const newValue = become(next)(oldValue);
1601
- store.logger.info(`📝`, type, key, `set (`, oldValue, `->`, newValue, `)`);
1602
- writeToCache(innerTarget, mySelector, newValue);
1603
- markDone(innerTarget, options.key);
1604
- if (isRootStore(innerTarget)) subject.next({
1605
- newValue,
1606
- oldValue
1607
- });
1672
+ const setSelf = (newValue) => {
1608
1673
  options.set(setterToolkit, newValue);
1609
1674
  };
1610
1675
  const mySelector = {
1611
1676
  ...options,
1612
1677
  type,
1613
1678
  subject,
1614
- install: (s) => createWritablePureSelector(s, options, family),
1615
- get: getSelf,
1616
- set: setSelf,
1617
- ...family && { family }
1679
+ getFrom,
1680
+ setSelf,
1681
+ install: (s) => createWritablePureSelector(s, options, family)
1618
1682
  };
1683
+ if (family) mySelector.family = family;
1619
1684
  target.writableSelectors.set(key, mySelector);
1620
- const initialValue = getSelf();
1685
+ const initialValue = getFrom(target);
1621
1686
  store.logger.info(`✨`, mySelector.type, mySelector.key, `=`, initialValue);
1622
1687
  const token = {
1623
1688
  key,
@@ -1625,7 +1690,7 @@ const createWritablePureSelector = (store, options, family) => {
1625
1690
  };
1626
1691
  if (family) token.family = family;
1627
1692
  return token;
1628
- };
1693
+ }
1629
1694
 
1630
1695
  //#endregion
1631
1696
  //#region src/internal/selector/create-standalone-selector.ts
@@ -1674,7 +1739,8 @@ function disposeSelector(store, selectorToken) {
1674
1739
  family.subject.next({
1675
1740
  type: `state_disposal`,
1676
1741
  subType: `selector`,
1677
- token: selectorToken
1742
+ token: selectorToken,
1743
+ timestamp: Date.now()
1678
1744
  });
1679
1745
  }
1680
1746
  break;
@@ -1689,7 +1755,8 @@ function disposeSelector(store, selectorToken) {
1689
1755
  family.subject.next({
1690
1756
  type: `state_disposal`,
1691
1757
  subType: `selector`,
1692
- token: selectorToken
1758
+ token: selectorToken,
1759
+ timestamp: Date.now()
1693
1760
  });
1694
1761
  }
1695
1762
  break;
@@ -1704,7 +1771,8 @@ function disposeSelector(store, selectorToken) {
1704
1771
  family.subject.next({
1705
1772
  type: `state_disposal`,
1706
1773
  subType: `selector`,
1707
- token: selectorToken
1774
+ token: selectorToken,
1775
+ timestamp: Date.now()
1708
1776
  });
1709
1777
  }
1710
1778
  break;
@@ -1719,7 +1787,8 @@ function disposeSelector(store, selectorToken) {
1719
1787
  family.subject.next({
1720
1788
  type: `state_disposal`,
1721
1789
  subType: `selector`,
1722
- token: selectorToken
1790
+ token: selectorToken,
1791
+ timestamp: Date.now()
1723
1792
  });
1724
1793
  }
1725
1794
  break;
@@ -1729,10 +1798,11 @@ function disposeSelector(store, selectorToken) {
1729
1798
  target.selectorGraph.delete(key);
1730
1799
  target.moleculeData.delete(familyMeta.key, familyMeta.subKey);
1731
1800
  store.logger.info(`🔥`, selectorToken.type, key, `deleted`);
1732
- if (isChildStore(target) && target.transactionMeta.phase === `building`) target.transactionMeta.update.updates.push({
1801
+ if (isChildStore(target) && target.transactionMeta.phase === `building`) target.transactionMeta.update.subEvents.push({
1733
1802
  type: `state_disposal`,
1734
1803
  subType: `selector`,
1735
- token: selectorToken
1804
+ token: selectorToken,
1805
+ timestamp: Date.now()
1736
1806
  });
1737
1807
  else store.on.selectorDisposal.next(selectorToken);
1738
1808
  }
@@ -1764,7 +1834,8 @@ function createReadonlyPureSelectorFamily(store, options, internalRoles) {
1764
1834
  }, family);
1765
1835
  subject.next({
1766
1836
  type: `state_creation`,
1767
- token
1837
+ token,
1838
+ timestamp: Date.now()
1768
1839
  });
1769
1840
  return token;
1770
1841
  };
@@ -1812,17 +1883,19 @@ function createRegularAtomFamily(store, options, internalRoles) {
1812
1883
  const token = createRegularAtom(target, individualOptions, family);
1813
1884
  subject.next({
1814
1885
  type: `state_creation`,
1815
- token
1886
+ token,
1887
+ timestamp: Date.now()
1816
1888
  });
1817
1889
  return token;
1818
1890
  };
1819
1891
  const atomFamily$1 = Object.assign(familyFunction, familyToken, {
1892
+ default: options.default,
1820
1893
  subject,
1821
1894
  install: (s) => createRegularAtomFamily(s, options),
1822
1895
  internalRoles
1823
1896
  });
1824
1897
  store.families.set(options.key, atomFamily$1);
1825
- store.defaults.set(options.key, options.default);
1898
+ if (options.default instanceof Function === false) store.defaults.set(options.key, options.default);
1826
1899
  return familyToken;
1827
1900
  }
1828
1901
 
@@ -1853,7 +1926,8 @@ function createReadonlyHeldSelectorFamily(store, options, internalRoles) {
1853
1926
  }, family);
1854
1927
  subject.next({
1855
1928
  type: `state_creation`,
1856
- token
1929
+ token,
1930
+ timestamp: Date.now()
1857
1931
  });
1858
1932
  return token;
1859
1933
  };
@@ -1895,7 +1969,8 @@ function createWritableHeldSelectorFamily(store, options, internalRoles) {
1895
1969
  }, family);
1896
1970
  subject.next({
1897
1971
  type: `state_creation`,
1898
- token
1972
+ token,
1973
+ timestamp: Date.now()
1899
1974
  });
1900
1975
  return token;
1901
1976
  };
@@ -1936,7 +2011,8 @@ function createWritablePureSelectorFamily(store, options, internalRoles) {
1936
2011
  }, family);
1937
2012
  subject.next({
1938
2013
  type: `state_creation`,
1939
- token
2014
+ token,
2015
+ timestamp: Date.now()
1940
2016
  });
1941
2017
  return token;
1942
2018
  };
@@ -1968,34 +2044,6 @@ function createSelectorFamily(store, options) {
1968
2044
  return createReadonlyPureSelectorFamily(store, options);
1969
2045
  }
1970
2046
 
1971
- //#endregion
1972
- //#region src/internal/families/init-family-member.ts
1973
- function initFamilyMemberInStore(store, token, key) {
1974
- const family = store.families.get(token.key);
1975
- if (family === void 0) throw new NotFoundError(token, store);
1976
- const state = family(key);
1977
- const target = newest(store);
1978
- if (state.family) {
1979
- if (isRootStore(target)) switch (state.type) {
1980
- case `atom`:
1981
- case `mutable_atom`:
1982
- store.on.atomCreation.next(state);
1983
- break;
1984
- case `writable_pure_selector`:
1985
- case `readonly_pure_selector`:
1986
- case `writable_held_selector`:
1987
- case `readonly_held_selector`:
1988
- store.on.selectorCreation.next(state);
1989
- break;
1990
- }
1991
- else if (isChildStore(target) && target.on.transactionApplying.state === null) target.transactionMeta.update.updates.push({
1992
- type: `state_creation`,
1993
- token: state
1994
- });
1995
- }
1996
- return state;
1997
- }
1998
-
1999
2047
  //#endregion
2000
2048
  //#region src/internal/families/seek-in-store.ts
2001
2049
  function seekInStore(store, token, key) {
@@ -2023,22 +2071,11 @@ function seekInStore(store, token, key) {
2023
2071
 
2024
2072
  //#endregion
2025
2073
  //#region src/internal/families/find-in-store.ts
2026
- function findInStore(store, token, key) {
2027
- let state = seekInStore(store, token, key);
2028
- if (state) return state;
2029
- const stringKey = stringifyJson(key);
2030
- const molecule = store.molecules.get(stringKey);
2031
- if (!molecule && store.config.lifespan === `immortal`) {
2032
- const fakeToken = counterfeit(token, key);
2033
- store.logger.error(`❌`, fakeToken.type, fakeToken.key, `was not found in store "${store.config.name}"; returned a counterfeit token.`);
2034
- return fakeToken;
2035
- }
2036
- state = initFamilyMemberInStore(store, token, key);
2037
- if (molecule) {
2038
- const target = newest(store);
2039
- target.moleculeData.set(stringKey, token.key);
2040
- }
2041
- return state;
2074
+ function findInStore(store, familyToken, key) {
2075
+ const existingStateToken = seekInStore(store, familyToken, key);
2076
+ if (existingStateToken) return existingStateToken;
2077
+ const newStateToken = mintInStore(store, familyToken, key);
2078
+ return newStateToken;
2042
2079
  }
2043
2080
 
2044
2081
  //#endregion
@@ -2090,14 +2127,25 @@ function getFromStore(store, ...params) {
2090
2127
  const disposal = store.disposalTraces.buffer.find((item) => item?.key === subKey);
2091
2128
  store.logger.error(`❌`, token.type, token.key, `could not be retrieved because it was not found in the store "${store.config.name}".`, disposal ? `This state was previously disposed:\n${disposal.trace}` : `No previous disposal trace was found.`);
2092
2129
  switch (family.type) {
2093
- case `atom_family`:
2094
- case `mutable_atom_family`: return store.defaults.get(family.key);
2130
+ case `mutable_atom_family`: {
2131
+ if (store.defaults.has(family.key)) return store.defaults.get(family.key);
2132
+ const mutableFamily = withdraw(store, family);
2133
+ const defaultValue = new mutableFamily.class();
2134
+ store.defaults.set(family.key, defaultValue);
2135
+ return defaultValue;
2136
+ }
2137
+ case `atom_family`: {
2138
+ if (store.defaults.has(family.key)) return store.defaults.get(token.family.key);
2139
+ const defaultValue = withdraw(store, family).default(parseJson(subKey));
2140
+ store.defaults.set(family.key, defaultValue);
2141
+ return defaultValue;
2142
+ }
2095
2143
  case `readonly_pure_selector_family`:
2096
2144
  case `writable_pure_selector_family`:
2097
2145
  case `readonly_held_selector_family`:
2098
2146
  case `writable_held_selector_family`: {
2099
2147
  if (store.defaults.has(family.key)) return store.defaults.get(token.family.key);
2100
- const defaultValue = withdraw(store, family).default(subKey);
2148
+ const defaultValue = withdraw(store, family).default(parseJson(subKey));
2101
2149
  store.defaults.set(family.key, defaultValue);
2102
2150
  return defaultValue;
2103
2151
  }
@@ -2273,7 +2321,7 @@ var Tracker = class {
2273
2321
  captureSignalsFromCore(mutableState, latestSignalState, target) {
2274
2322
  const stateKey = mutableState.key;
2275
2323
  const storeName = target.config.name;
2276
- const storeStatus = isChildStore(target) ? target.transactionMeta.update.key : `main`;
2324
+ const storeStatus = isChildStore(target) ? target.transactionMeta.update.token.key : `main`;
2277
2325
  const subscriptionKey = `tracker:${storeName}:${storeStatus}:${stateKey}`;
2278
2326
  const trackerCapturesOutboundSignal = (update) => {
2279
2327
  setIntoStore(target, latestSignalState, update);
@@ -2288,7 +2336,7 @@ var Tracker = class {
2288
2336
  }.bind(this));
2289
2337
  }
2290
2338
  supplySignalsToCore(mutableState, latestSignalState, target) {
2291
- const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2339
+ const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.token.key : `main`}:${mutableState.key}`;
2292
2340
  subscribeToState(target, latestSignalState, subscriptionKey, function trackerCapturesInboundSignal({ newValue, oldValue }) {
2293
2341
  const timelineId = target.timelineTopics.getRelatedKey(latestSignalState.key);
2294
2342
  if (timelineId && target.timelines.get(timelineId)?.timeTraveling) {
@@ -2452,11 +2500,13 @@ function createMutableAtomFamily(store, options, internalRoles) {
2452
2500
  const token = createMutableAtom(target, individualOptions, family);
2453
2501
  subject.next({
2454
2502
  type: `state_creation`,
2455
- token
2503
+ token,
2504
+ timestamp: Date.now()
2456
2505
  });
2457
2506
  return token;
2458
2507
  };
2459
2508
  const atomFamily$1 = Object.assign(familyFunction, familyToken, {
2509
+ class: options.class,
2460
2510
  subject,
2461
2511
  install: (s) => createMutableAtomFamily(s, options),
2462
2512
  internalRoles
@@ -2531,7 +2581,7 @@ const getUpdateToken = (mutableAtomToken) => {
2531
2581
  //#endregion
2532
2582
  //#region src/internal/mutable/transceiver.ts
2533
2583
  function isTransceiver(value) {
2534
- return typeof value === `object` && value !== null && `do` in value && `undo` in value && `subscribe` in value;
2584
+ return typeof value === `object` && value !== null && `do` in value && `undo` in value && `subscribe` in value && `cacheUpdateNumber` in value && `getUpdateNumber` in value && `READONLY_VIEW` in value && `toJSON` in value;
2535
2585
  }
2536
2586
 
2537
2587
  //#endregion
@@ -2723,17 +2773,17 @@ function disposeAtom(store, atomToken) {
2723
2773
  else {
2724
2774
  atom.cleanup?.();
2725
2775
  const lastValue = store.valueMap.get(atom.key);
2726
- const atomFamily$1 = withdraw(store, {
2727
- key: family.key,
2728
- type: `atom_family`
2729
- });
2776
+ const familyToken = getFamilyOfToken(store, atomToken);
2777
+ const atomFamily$1 = withdraw(store, familyToken);
2778
+ const subject = atomFamily$1.subject;
2730
2779
  const disposal = {
2731
2780
  type: `state_disposal`,
2732
2781
  subType: `atom`,
2733
2782
  token: atomToken,
2734
- value: lastValue
2783
+ value: lastValue,
2784
+ timestamp: Date.now()
2735
2785
  };
2736
- atomFamily$1.subject.next(disposal);
2786
+ subject.next(disposal);
2737
2787
  const isChild = isChildStore(target);
2738
2788
  target.atoms.delete(key);
2739
2789
  target.valueMap.delete(key);
@@ -2748,14 +2798,22 @@ function disposeAtom(store, atomToken) {
2748
2798
  }
2749
2799
  store.logger.info(`🔥`, `atom`, key, `deleted`);
2750
2800
  if (isChild && target.transactionMeta.phase === `building`) {
2751
- const mostRecentUpdate = target.transactionMeta.update.updates.at(-1);
2801
+ const mostRecentUpdate = target.transactionMeta.update.subEvents.at(-1);
2752
2802
  const wasMoleculeDisposal = mostRecentUpdate?.type === `molecule_disposal`;
2753
2803
  const updateAlreadyCaptured = wasMoleculeDisposal && mostRecentUpdate.values.some(([k]) => k === atom.family?.key);
2754
- if (!updateAlreadyCaptured) target.transactionMeta.update.updates.push(disposal);
2804
+ if (!updateAlreadyCaptured) target.transactionMeta.update.subEvents.push(disposal);
2755
2805
  } else store.on.atomDisposal.next(atomToken);
2756
2806
  }
2757
2807
  }
2758
2808
 
2809
+ //#endregion
2810
+ //#region src/internal/atom/has-role.ts
2811
+ const INTERNAL_ROLES = [`tracker:signal`];
2812
+ function hasRole(atom, role) {
2813
+ if (`internalRoles` in atom === false) return false;
2814
+ return atom.internalRoles.includes(role);
2815
+ }
2816
+
2759
2817
  //#endregion
2760
2818
  //#region src/internal/install-into-store.ts
2761
2819
  /**
@@ -2769,12 +2827,12 @@ function disposeAtom(store, atomToken) {
2769
2827
  function installIntoStore(tokens, target, source) {
2770
2828
  const sourceNewest = newest(source);
2771
2829
  if (isChildStore(sourceNewest)) {
2772
- source.logger.error(`❌`, `transaction`, sourceNewest.transactionMeta.update.key, `could not install the following tokens into store "${target.config.name} from "${source.config.name}":`, tokens, `${sourceNewest.config.name} is undergoing a transaction.`);
2830
+ source.logger.error(`❌`, `transaction`, sourceNewest.transactionMeta.update.token.key, `could not install the following tokens into store "${target.config.name} from "${source.config.name}":`, tokens, `${sourceNewest.config.name} is undergoing a transaction.`);
2773
2831
  return;
2774
2832
  }
2775
2833
  const targetNewest = newest(target);
2776
2834
  if (isChildStore(targetNewest)) {
2777
- target.logger.error(`❌`, `transaction`, targetNewest.transactionMeta.update.key, `could not install the following tokens into store "${target.config.name} from "${source.config.name}":`, tokens, `${targetNewest.config.name} is undergoing a transaction.`);
2835
+ target.logger.error(`❌`, `transaction`, targetNewest.transactionMeta.update.token.key, `could not install the following tokens into store "${target.config.name} from "${source.config.name}":`, tokens, `${targetNewest.config.name} is undergoing a transaction.`);
2778
2836
  return;
2779
2837
  }
2780
2838
  for (const token of tokens) {
@@ -3325,37 +3383,39 @@ function addAtomToTimeline(store, atomToken, tl) {
3325
3383
  }, { topicType: `atom` });
3326
3384
  tl.subscriptions.set(atom.key, atom.subject.subscribe(`timeline`, function timelineCapturesAtomUpdate(update) {
3327
3385
  const target = newest(store);
3328
- const currentSelectorKey = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.token.key : null;
3329
- const currentSelectorTime = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.time : null;
3386
+ const currentSelectorToken = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.token : null;
3387
+ const currentSelectorTime = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.timestamp : null;
3330
3388
  const txUpdateInProgress = target.on.transactionApplying.state?.update;
3331
- store.logger.info(`⏳`, `timeline`, tl.key, `atom`, atomToken.key, `went`, update.oldValue, `->`, update.newValue, txUpdateInProgress ? `in transaction "${txUpdateInProgress.key}"` : currentSelectorKey ? `in selector "${currentSelectorKey}"` : ``);
3389
+ store.logger.info(`⏳`, `timeline`, tl.key, `atom`, atomToken.key, `went`, update.oldValue, `->`, update.newValue, txUpdateInProgress ? `in transaction "${txUpdateInProgress.token.key}"` : currentSelectorToken ? `in selector "${currentSelectorToken.key}"` : ``);
3332
3390
  if (tl.timeTraveling === null) if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress);
3333
- else if (currentSelectorKey && currentSelectorTime) {
3391
+ else if (currentSelectorToken && currentSelectorTime) {
3334
3392
  let latestUpdate = tl.history.at(-1);
3335
3393
  if (currentSelectorTime !== tl.selectorTime) {
3336
3394
  latestUpdate = {
3337
3395
  type: `selector_update`,
3338
3396
  timestamp: currentSelectorTime,
3339
- key: currentSelectorKey,
3397
+ token: currentSelectorToken,
3340
3398
  atomUpdates: []
3341
3399
  };
3342
3400
  latestUpdate.atomUpdates.push({
3343
- key: atom.key,
3344
3401
  type: `atom_update`,
3345
- ...update
3402
+ token: atomToken,
3403
+ update,
3404
+ timestamp: Date.now()
3346
3405
  });
3347
3406
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3348
3407
  tl.history.push(latestUpdate);
3349
- store.logger.info(`⌛`, `timeline`, tl.key, `got a selector_update "${currentSelectorKey}" with`, latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key));
3408
+ store.logger.info(`⌛`, `timeline`, tl.key, `got a selector_update "${currentSelectorToken.key}" with`, latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.token.key));
3350
3409
  tl.at = tl.history.length;
3351
3410
  tl.selectorTime = currentSelectorTime;
3352
3411
  } else if (latestUpdate?.type === `selector_update`) {
3353
3412
  latestUpdate.atomUpdates.push({
3354
- key: atom.key,
3355
3413
  type: `atom_update`,
3356
- ...update
3414
+ token: atomToken,
3415
+ update,
3416
+ timestamp: Date.now()
3357
3417
  });
3358
- store.logger.info(`⌛`, `timeline`, tl.key, `set selector_update "${currentSelectorKey}" to`, latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key));
3418
+ store.logger.info(`⌛`, `timeline`, tl.key, `set selector_update "${currentSelectorToken.key}" to`, latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.token.key));
3359
3419
  }
3360
3420
  if (latestUpdate) {
3361
3421
  const willCaptureSelectorUpdate = tl.shouldCapture?.(latestUpdate, tl) ?? true;
@@ -3371,12 +3431,10 @@ function addAtomToTimeline(store, atomToken, tl) {
3371
3431
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3372
3432
  const atomUpdate = {
3373
3433
  type: `atom_update`,
3374
- timestamp,
3375
- key: atom.key,
3376
- oldValue: update.oldValue,
3377
- newValue: update.newValue
3434
+ token: deposit(atom),
3435
+ update,
3436
+ timestamp
3378
3437
  };
3379
- if (atom.family) atomUpdate.family = atom.family;
3380
3438
  const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true;
3381
3439
  store.logger.info(`⌛`, `timeline`, tl.key, `got an atom_update to "${atom.key}"`);
3382
3440
  if (willCapture) {
@@ -3399,7 +3457,7 @@ function addAtomFamilyToTimeline(store, atomFamilyToken, tl) {
3399
3457
  for (const atom of store.atoms.values()) if (atom.family?.key === family.key) addAtomToTimeline(store, atom, tl);
3400
3458
  }
3401
3459
  function joinTransaction(store, tl, txUpdateInProgress) {
3402
- const currentTxKey = txUpdateInProgress.key;
3460
+ const currentTxKey = txUpdateInProgress.token.key;
3403
3461
  const currentTxInstanceId = txUpdateInProgress.id;
3404
3462
  const currentTxToken = {
3405
3463
  key: currentTxKey,
@@ -3414,11 +3472,10 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3414
3472
  if (tl.timeTraveling === null && currentTxInstanceId) {
3415
3473
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3416
3474
  const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key);
3417
- const updates = filterTransactionUpdates(transactionUpdate.updates, timelineTopics);
3475
+ const subEventsFiltered = filterTransactionSubEvents(transactionUpdate.subEvents, timelineTopics);
3418
3476
  const timelineTransactionUpdate = {
3419
- timestamp: Date.now(),
3420
3477
  ...transactionUpdate,
3421
- updates
3478
+ subEvents: subEventsFiltered
3422
3479
  };
3423
3480
  const willCapture = tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true;
3424
3481
  if (willCapture) {
@@ -3430,12 +3487,13 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3430
3487
  });
3431
3488
  }
3432
3489
  }
3433
- function filterTransactionUpdates(updates, timelineTopics) {
3490
+ function filterTransactionSubEvents(updates, timelineTopics) {
3434
3491
  return updates.filter((updateFromTx) => {
3435
- if (updateFromTx.type === `transaction_update`) return true;
3492
+ if (updateFromTx.type === `transaction_outcome`) return true;
3436
3493
  let key;
3437
3494
  let familyKey;
3438
3495
  switch (updateFromTx.type) {
3496
+ case `atom_update`:
3439
3497
  case `state_creation`:
3440
3498
  case `state_disposal`:
3441
3499
  key = updateFromTx.token.key;
@@ -3444,35 +3502,28 @@ function filterTransactionUpdates(updates, timelineTopics) {
3444
3502
  case `molecule_creation`:
3445
3503
  case `molecule_disposal`:
3446
3504
  case `molecule_transfer`: return true;
3447
- case `atom_update`:
3448
- case `selector_update`:
3449
- key = updateFromTx.key;
3450
- familyKey = updateFromTx.family?.key;
3451
- break;
3452
3505
  }
3453
3506
  timelineTopics.has(key);
3454
3507
  if (familyKey && timelineTopics.has(familyKey)) return true;
3455
3508
  return timelineTopics.has(key);
3456
3509
  }).map((updateFromTx) => {
3457
- if (`updates` in updateFromTx) return {
3510
+ if (`subEvents` in updateFromTx) return {
3458
3511
  ...updateFromTx,
3459
- updates: filterTransactionUpdates(updateFromTx.updates, timelineTopics)
3512
+ subEvents: filterTransactionSubEvents(updateFromTx.subEvents, timelineTopics)
3460
3513
  };
3461
3514
  return updateFromTx;
3462
3515
  });
3463
3516
  }
3464
3517
  function handleStateLifecycleEvent(store, event, tl) {
3465
- const timestamp = Date.now();
3466
- const timelineEvent = Object.assign(event, { timestamp });
3467
3518
  if (!tl.timeTraveling) {
3468
3519
  const target = newest(store);
3469
3520
  if (isChildStore(target)) {} else {
3470
3521
  const txUpdateInProgress = target.on.transactionApplying.state;
3471
3522
  if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress.update);
3472
3523
  else {
3473
- tl.history.push(timelineEvent);
3524
+ tl.history.push(event);
3474
3525
  tl.at = tl.history.length;
3475
- tl.subject.next(timelineEvent);
3526
+ tl.subject.next(event);
3476
3527
  }
3477
3528
  }
3478
3529
  }
@@ -3511,7 +3562,7 @@ const timeTravel = (store, action, token) => {
3511
3562
  case `selector_update`:
3512
3563
  ingestSelectorUpdate(applying, update, store);
3513
3564
  break;
3514
- case `transaction_update`:
3565
+ case `transaction_outcome`:
3515
3566
  ingestTransactionUpdate(applying, update, store);
3516
3567
  break;
3517
3568
  case `state_creation`: