atom.io 0.36.2 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) 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 +66 -98
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +544 -507
  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 +14 -14
  47. package/src/internal/atom/dispose-atom.ts +5 -4
  48. package/src/internal/caching.ts +3 -3
  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 +3 -6
  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/read-or-compute-value.ts +4 -2
  58. package/src/internal/index.ts +19 -18
  59. package/src/internal/ingest-updates/ingest-atom-update.ts +7 -7
  60. package/src/internal/ingest-updates/ingest-creation-disposal.ts +11 -11
  61. package/src/internal/ingest-updates/ingest-selector-update.ts +8 -4
  62. package/src/internal/ingest-updates/ingest-transaction-update.ts +5 -6
  63. package/src/internal/install-into-store.ts +2 -2
  64. package/src/internal/join/join-internal.ts +1 -1
  65. package/src/internal/molecule.ts +12 -9
  66. package/src/internal/mutable/create-mutable-atom-family.ts +3 -6
  67. package/src/internal/mutable/tracker.ts +2 -2
  68. package/src/internal/mutable/transceiver.ts +6 -4
  69. package/src/internal/operation.ts +17 -14
  70. package/src/internal/selector/create-readonly-held-selector.ts +9 -7
  71. package/src/internal/selector/create-readonly-pure-selector.ts +8 -5
  72. package/src/internal/selector/create-writable-held-selector.ts +12 -21
  73. package/src/internal/selector/create-writable-pure-selector.ts +16 -29
  74. package/src/internal/selector/dispose-selector.ts +6 -1
  75. package/src/internal/selector/get-selector-dependency-keys.ts +2 -6
  76. package/src/internal/selector/register-selector.ts +64 -74
  77. package/src/internal/selector/trace-selector-atoms.ts +2 -2
  78. package/src/internal/selector/update-selector-atoms.ts +2 -2
  79. package/src/internal/set-state/dispatch-state-update.ts +101 -0
  80. package/src/internal/set-state/operate-on-store.ts +126 -0
  81. package/src/internal/set-state/reset-atom-or-selector.ts +24 -15
  82. package/src/internal/set-state/set-atom-or-selector.ts +9 -4
  83. package/src/internal/set-state/set-atom.ts +4 -49
  84. package/src/internal/set-state/set-into-store.ts +11 -77
  85. package/src/internal/set-state/set-selector.ts +35 -0
  86. package/src/internal/store/store.ts +4 -4
  87. package/src/internal/subscribe/subscribe-in-store.ts +3 -3
  88. package/src/internal/subscribe/subscribe-to-timeline.ts +2 -2
  89. package/src/internal/timeline/create-timeline.ts +57 -101
  90. package/src/internal/timeline/time-travel.ts +1 -1
  91. package/src/internal/transaction/abort-transaction.ts +1 -1
  92. package/src/internal/transaction/apply-transaction.ts +7 -7
  93. package/src/internal/transaction/build-transaction.ts +10 -9
  94. package/src/internal/transaction/create-transaction.ts +4 -3
  95. package/src/internal/transaction/index.ts +6 -2
  96. package/src/introspection/attach-introspection-states.ts +2 -2
  97. package/src/introspection/attach-transaction-logs.ts +13 -6
  98. package/src/json/index.ts +3 -1
  99. package/src/main/atom.ts +2 -1
  100. package/src/main/events.ts +109 -0
  101. package/src/main/get-state.ts +1 -1
  102. package/src/main/index.ts +3 -0
  103. package/src/main/subscribe.ts +9 -19
  104. package/src/main/timeline.ts +3 -21
  105. package/src/main/transaction.ts +0 -65
  106. package/src/main/validators.ts +8 -2
  107. package/src/react-devtools/TimelineIndex.tsx +1 -1
  108. package/src/react-devtools/TransactionIndex.tsx +5 -3
  109. package/src/react-devtools/Updates.tsx +54 -46
  110. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +20 -10
  111. package/src/realtime-client/realtime-client-stores/client-sync-store.ts +4 -4
  112. package/src/realtime-client/sync-continuity.ts +1 -1
  113. package/src/realtime-server/continuity/prepare-to-serve-transaction-request.ts +14 -8
  114. package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +5 -2
  115. package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
  116. package/src/realtime-server/realtime-action-receiver.ts +6 -3
  117. package/src/realtime-server/realtime-server-stores/server-sync-store.ts +13 -16
  118. package/src/transceivers/set-rtx/set-rtx.ts +1 -3
  119. package/src/web/persist-sync.ts +2 -2
  120. 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.`);
@@ -538,9 +539,7 @@ function writeToCache(target, state, value) {
538
539
  case `mutable_atom`:
539
540
  evictDownstreamFromAtom(target, state);
540
541
  break;
541
- case `readonly_held_selector`:
542
542
  case `readonly_pure_selector`:
543
- case `writable_held_selector`:
544
543
  case `writable_pure_selector`:
545
544
  evictDownstreamFromSelector(target, key);
546
545
  break;
@@ -587,7 +586,7 @@ function evictCachedValue(target, key) {
587
586
  const currentValue = target.valueMap.get(key);
588
587
  if (currentValue instanceof Future) {
589
588
  const selector = target.writableSelectors.get(key) ?? target.readonlySelectors.get(key);
590
- if (selector) selector.get();
589
+ if (selector) selector.getFrom(target);
591
590
  return;
592
591
  }
593
592
  if (target.operation.open) target.operation.prev.set(key, currentValue);
@@ -606,7 +605,7 @@ function readOrComputeValue(target, state, mut) {
606
605
  case `writable_held_selector`:
607
606
  case `writable_pure_selector`:
608
607
  target.logger.info(`🧮`, state.type, key, `computing value`);
609
- return state.get();
608
+ return state.getFrom(target);
610
609
  case `atom`: {
611
610
  let def;
612
611
  if (state.default instanceof Function) def = state.default();
@@ -625,33 +624,104 @@ function readOrComputeValue(target, state, mut) {
625
624
  }
626
625
 
627
626
  //#endregion
628
- //#region src/internal/set-state/become.ts
629
- 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
+ }
630
634
 
631
635
  //#endregion
632
- //#region src/internal/atom/has-role.ts
633
- const INTERNAL_ROLES = [`tracker:signal`];
634
- function hasRole(atom, role) {
635
- if (`internalRoles` in atom === false) return false;
636
- 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);
637
651
  }
638
652
 
639
653
  //#endregion
640
- //#region src/internal/set-state/emit-update.ts
641
- const emitUpdate = (store, state, update) => {
642
- switch (state.type) {
643
- case `mutable_atom`:
644
- store.logger.info(`📢`, state.type, state.key, `is now (`, update.newValue, `) subscribers:`, state.subject.subscribers);
645
- break;
646
- case `atom`:
647
- case `writable_pure_selector`:
648
- case `readonly_pure_selector`:
649
- case `writable_held_selector`:
650
- 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}".`);
651
664
  }
652
- state.subject.next(update);
653
665
  };
654
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
+
655
725
  //#endregion
656
726
  //#region src/internal/set-state/set-atom.ts
657
727
  const setAtom = (target, atom, next) => {
@@ -661,129 +731,49 @@ const setAtom = (target, atom, next) => {
661
731
  newValue = writeToCache(target, atom, newValue);
662
732
  markDone(target, atom.key);
663
733
  evictDownstreamFromAtom(target, atom);
664
- const update = {
665
- oldValue,
666
- newValue
667
- };
668
- if (!isChildStore(target)) {
669
- emitUpdate(target, atom, update);
670
- return;
671
- }
672
- if (target.on.transactionApplying.state === null) {
673
- const { key } = atom;
674
- if (isTransceiver(update.newValue)) return;
675
- const atomUpdate = {
676
- type: `atom_update`,
677
- key,
678
- ...update
679
- };
680
- if (atom.family) atomUpdate.family = atom.family;
681
- target.transactionMeta.update.updates.push(atomUpdate);
682
- target.logger.info(`📁`, `atom`, key, `stowed (`, update.oldValue, `->`, update.newValue, `)`);
683
- } else if (hasRole(atom, `tracker:signal`)) {
684
- const key = atom.key.slice(1);
685
- const mutable = target.atoms.get(key);
686
- const transceiver = readOrComputeValue(target, mutable, `mut`);
687
- const accepted = transceiver.do(update.newValue) === null;
688
- if (accepted === true) evictDownstreamFromAtom(target, mutable);
689
- }
734
+ return [oldValue, newValue];
690
735
  };
691
736
 
692
737
  //#endregion
693
738
  //#region src/internal/set-state/reset-atom-or-selector.ts
694
- function resetAtom(store, state) {
695
- switch (state.type) {
696
- case `mutable_atom`:
697
- setAtom(store, state, new state.class());
698
- return;
739
+ function resetAtom(target, atom) {
740
+ switch (atom.type) {
741
+ case `mutable_atom`: return setAtom(target, atom, new atom.class());
699
742
  case `atom`: {
700
- let def = state.default;
743
+ let def = atom.default;
701
744
  if (def instanceof Function) def = def();
702
- setAtom(store, state, def);
745
+ return setAtom(target, atom, def);
703
746
  }
704
747
  }
705
748
  }
706
- function resetAtomOrSelector(store, state) {
749
+ function resetAtomOrSelector(target, state) {
750
+ let protoUpdate;
707
751
  switch (state.type) {
708
752
  case `atom`:
709
753
  case `mutable_atom`:
710
- resetAtom(store, state);
754
+ protoUpdate = resetAtom(target, state);
711
755
  break;
712
756
  case `writable_pure_selector`:
713
757
  case `writable_held_selector`:
714
758
  {
715
- const atoms = traceRootSelectorAtoms(store, state.key);
716
- 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];
717
767
  }
718
768
  break;
719
769
  }
770
+ return protoUpdate;
720
771
  }
721
772
 
722
- //#endregion
723
- //#region src/internal/families/get-family-of-token.ts
724
- function getFamilyOfToken(store, token) {
725
- if (token.family) {
726
- const family = store.families.get(token.family.key);
727
- if (family) return family;
728
- }
729
- }
730
-
731
- //#endregion
732
- //#region src/internal/set-state/set-atom-or-selector.ts
733
- const setAtomOrSelector = (store, state, value) => {
734
- switch (state.type) {
735
- case `atom`:
736
- case `mutable_atom`:
737
- setAtom(store, state, value);
738
- break;
739
- case `writable_pure_selector`:
740
- case `writable_held_selector`:
741
- state.set(value);
742
- break;
743
- }
744
- };
745
-
746
773
  //#endregion
747
774
  //#region src/internal/set-state/set-into-store.ts
748
775
  function setIntoStore(store, ...params) {
749
- let token;
750
- let family;
751
- let key;
752
- let value;
753
- if (params.length === 2) {
754
- token = params[0];
755
- value = params[1];
756
- if (token.family) {
757
- family = getFamilyOfToken(store, token);
758
- key = parseJson(token.family.subKey);
759
- token = findInStore(store, family, key);
760
- }
761
- } else {
762
- family = params[0];
763
- key = params[1];
764
- value = params[2];
765
- token = findInStore(store, family, key);
766
- }
767
- const action = value === RESET_STATE ? `reset` : `set`;
768
- if (`counterfeit` in token && `family` in token) {
769
- const subKey = token.family.subKey;
770
- const disposal = store.disposalTraces.buffer.find((item) => item?.key === subKey);
771
- 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.`);
772
- return;
773
- }
774
- const rejectionTime = openOperation(store, token);
775
- if (rejectionTime) {
776
- const unsubscribe = store.on.operationClose.subscribe(`waiting to ${action} "${token.key}" at T-${rejectionTime}`, function waitUntilOperationCloseToSetState() {
777
- unsubscribe();
778
- store.logger.info(`🟢`, token.type, token.key, `resuming deferred`, action, `from T-${rejectionTime}`);
779
- setIntoStore(store, token, value);
780
- });
781
- return;
782
- }
783
- const state = withdraw(store, token);
784
- if (value === RESET_STATE) resetAtomOrSelector(store, state);
785
- else setAtomOrSelector(store, state, value);
786
- closeOperation(store);
776
+ operateOnStore(store, true, ...params);
787
777
  }
788
778
 
789
779
  //#endregion
@@ -804,233 +794,52 @@ function resetInStore(store, ...params) {
804
794
  }
805
795
 
806
796
  //#endregion
807
- //#region src/internal/keys.ts
808
- const isAtomKey = (store, key) => newest(store).atoms.has(key);
809
- const isSelectorKey = (store, key) => newest(store).writableSelectors.has(key);
810
- const isReadonlySelectorKey = (store, key) => newest(store).readonlySelectors.has(key);
811
- const isStateKey = (store, key) => isAtomKey(store, key) || isSelectorKey(store, key) || isReadonlySelectorKey(store, key);
812
-
813
- //#endregion
814
- //#region src/internal/selector/get-selector-dependency-keys.ts
815
- const getSelectorDependencyKeys = (store, key) => {
816
- const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(store, source));
817
- return sources;
818
- };
819
-
820
- //#endregion
821
- //#region src/internal/selector/trace-selector-atoms.ts
822
- const traceRootSelectorAtoms = (store, selectorKey, covered = /* @__PURE__ */ new Set()) => {
823
- const dependencies = getSelectorDependencyKeys(store, selectorKey);
824
- const roots = /* @__PURE__ */ new Map();
825
- while (dependencies.length > 0) {
826
- const dependencyKey = dependencies.pop();
827
- if (covered.has(dependencyKey)) continue;
828
- covered.add(dependencyKey);
829
- if (isAtomKey(store, dependencyKey)) {
830
- const atom = store.atoms.get(dependencyKey);
831
- roots.set(atom.key, atom);
832
- } else dependencies.push(...getSelectorDependencyKeys(store, dependencyKey));
833
- }
834
- return roots;
835
- };
836
-
837
- //#endregion
838
- //#region src/internal/selector/update-selector-atoms.ts
839
- const updateSelectorAtoms = (store, selectorType, selectorKey, dependency, covered) => {
840
- const target = newest(store);
841
- const { type: dependencyType, key: dependencyKey } = dependency;
842
- if (dependencyType === `atom` || dependencyType === `mutable_atom`) {
843
- target.selectorAtoms.set({
844
- selectorKey,
845
- atomKey: dependencyKey
846
- });
847
- store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atom "${dependencyKey}"`);
848
- } else {
849
- const rootKeys = traceRootSelectorAtoms(store, dependencyKey, covered);
850
- store.logger.info(`🔍`, selectorType, selectorKey, `discovers root atoms: [ ${[...rootKeys.values()].map((root) => `"${root.key}"`).join(`, `)} ]`);
851
- for (const { key: atomKey } of rootKeys.values()) target.selectorAtoms = target.selectorAtoms.set({
852
- selectorKey,
853
- atomKey
854
- });
855
- }
856
- covered.add(dependencyKey);
857
- };
858
-
859
- //#endregion
860
- //#region src/internal/selector/register-selector.ts
861
- const registerSelector = (store, selectorType, selectorKey, covered) => ({
862
- get: (...params) => {
863
- const target = newest(store);
864
- let dependency;
865
- if (params.length === 2) {
866
- const [family, key] = params;
867
- dependency = findInStore(store, family, key);
868
- } else [dependency] = params;
869
- const dependencyState = withdraw(store, dependency);
870
- const dependencyValue = readOrComputeValue(store, dependencyState);
871
- const dependencyKey = dependency.key;
872
- store.logger.info(`🔌`, selectorType, selectorKey, `registers dependency ( "${dependencyKey}" =`, dependencyValue, `)`);
873
- target.selectorGraph.set({
874
- upstreamSelectorKey: dependencyKey,
875
- downstreamSelectorKey: selectorKey
876
- }, { source: dependency.key });
877
- updateSelectorAtoms(store, selectorType, selectorKey, dependency, covered);
878
- return dependencyValue;
879
- },
880
- set: ((...params) => {
881
- let token;
882
- let value;
883
- if (params.length === 2) {
884
- token = params[0];
885
- value = params[1];
886
- } else {
887
- const family = params[0];
888
- const key = params[1];
889
- value = params[2];
890
- token = findInStore(store, family, key);
891
- }
892
- const target = newest(store);
893
- const state = withdraw(target, token);
894
- setAtomOrSelector(target, state, value);
895
- }),
896
- find: ((...args) => findInStore(store, ...args)),
897
- json: (token) => getJsonToken(store, token)
898
- });
899
-
900
- //#endregion
901
- //#region src/internal/selector/create-readonly-held-selector.ts
902
- const createReadonlyHeldSelector = (store, options, family) => {
903
- const target = newest(store);
904
- const subject = new Subject();
905
- const covered = /* @__PURE__ */ new Set();
906
- const { key, const: constant } = options;
907
- const type = `readonly_held_selector`;
908
- const { get, find, json } = registerSelector(target, type, key, covered);
909
- const getSelf = () => {
910
- const innerTarget = newest(store);
911
- const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
912
- for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
913
- innerTarget.selectorAtoms.delete(key);
914
- options.get({
915
- get,
916
- find,
917
- json
918
- }, constant);
919
- writeToCache(newest(store), readonlySelector, constant);
920
- covered.clear();
921
- return constant;
922
- };
923
- const readonlySelector = {
924
- ...options,
925
- type,
926
- subject,
927
- install: (s) => createReadonlyHeldSelector(s, options, family),
928
- get: getSelf,
929
- ...family && { family }
930
- };
931
- target.readonlySelectors.set(key, readonlySelector);
932
- store.logger.info(`✨`, type, key, `=`, constant);
933
- const token = {
934
- key,
935
- type
936
- };
937
- if (family) token.family = family;
938
- return token;
939
- };
940
-
941
- //#endregion
942
- //#region src/internal/selector/create-readonly-pure-selector.ts
943
- const createReadonlyPureSelector = (store, options, family) => {
944
- const target = newest(store);
945
- const subject = new Subject();
946
- const covered = /* @__PURE__ */ new Set();
947
- const key = options.key;
948
- const type = `readonly_pure_selector`;
949
- const { get, find, json } = registerSelector(target, type, key, covered);
950
- const getSelf = () => {
951
- const innerTarget = newest(store);
952
- const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
953
- for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
954
- innerTarget.selectorAtoms.delete(key);
955
- const value = options.get({
956
- get,
957
- find,
958
- json
959
- });
960
- const cached = writeToCache(innerTarget, readonlySelector, value);
961
- store.logger.info(`✨`, type, key, `=`, cached);
962
- covered.clear();
963
- return cached;
964
- };
965
- const readonlySelector = {
966
- ...options,
967
- type,
968
- subject,
969
- install: (s) => createReadonlyPureSelector(s, options, family),
970
- get: getSelf,
971
- ...family && { family }
972
- };
973
- target.readonlySelectors.set(key, readonlySelector);
974
- const token = {
975
- key,
976
- type
977
- };
978
- if (family) token.family = family;
979
- return token;
980
- };
981
-
982
- //#endregion
983
- //#region src/internal/transaction/abort-transaction.ts
984
- const abortTransaction = (store) => {
985
- const target = newest(store);
986
- if (!isChildStore(target)) {
987
- store.logger.warn(`🐞`, `transaction`, `???`, `abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`);
988
- 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;
989
814
  }
990
- store.logger.info(`🪂`, `transaction`, target.transactionMeta.update.key, `Aborting transaction`);
991
- target.parent.child = null;
992
- };
993
-
994
- //#endregion
995
- //#region src/internal/capitalize.ts
996
- function capitalize(string) {
997
- return string[0].toUpperCase() + string.slice(1);
998
- }
999
-
1000
- //#endregion
1001
- //#region src/internal/pretty-print.ts
1002
- function prettyPrintTokenType(token) {
1003
- 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];
1004
819
  }
1005
820
 
1006
821
  //#endregion
1007
- //#region src/internal/not-found-error.ts
1008
- var NotFoundError = class extends Error {
1009
- constructor(token, store) {
1010
- super(`${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${store.config.name}".`);
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;
1011
834
  }
835
+ return protoUpdate;
1012
836
  };
1013
837
 
1014
- //#endregion
1015
- //#region src/internal/transaction/act-upon-store.ts
1016
- function actUponStore(store, token, id) {
1017
- return (...parameters) => {
1018
- const tx = withdraw(store, token);
1019
- if (tx) return tx.run(parameters, id);
1020
- throw new NotFoundError(token, store);
1021
- };
1022
- }
1023
-
1024
838
  //#endregion
1025
839
  //#region src/internal/ingest-updates/ingest-atom-update.ts
1026
840
  function ingestAtomUpdate(applying, atomUpdate, store) {
1027
- const { key, newValue, oldValue } = atomUpdate;
841
+ const { token, update: { newValue, oldValue } } = atomUpdate;
1028
842
  const value = applying === `newValue` ? newValue : oldValue;
1029
- const token = {
1030
- key,
1031
- type: `atom`
1032
- };
1033
- if (atomUpdate.family) Object.assign(token, { family: atomUpdate.family });
1034
843
  setIntoStore(store, token, value);
1035
844
  }
1036
845
 
@@ -1078,10 +887,11 @@ function allocateIntoStore(store, provenance, key, dependsOn = `any`) {
1078
887
  const creationEvent = {
1079
888
  type: `molecule_creation`,
1080
889
  key,
1081
- provenance: origin
890
+ provenance: origin,
891
+ timestamp: Date.now()
1082
892
  };
1083
893
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1084
- if (isTransaction) target.transactionMeta.update.updates.push(creationEvent);
894
+ if (isTransaction) target.transactionMeta.update.subEvents.push(creationEvent);
1085
895
  else target.on.moleculeCreation.next(creationEvent);
1086
896
  for (const claim of invalidKeys) {
1087
897
  const disposal = store.disposalTraces.buffer.find((item) => item?.key === claim);
@@ -1118,12 +928,13 @@ function deallocateFromStore(store, claim) {
1118
928
  type: `molecule_disposal`,
1119
929
  key: molecule.key,
1120
930
  values,
1121
- provenance
931
+ provenance,
932
+ timestamp: Date.now()
1122
933
  };
1123
934
  const target = newest(store);
1124
935
  target.molecules.delete(stringKey);
1125
936
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1126
- if (isTransaction) target.transactionMeta.update.updates.push(disposalEvent);
937
+ if (isTransaction) target.transactionMeta.update.subEvents.push(disposalEvent);
1127
938
  const relatedMolecules = store.moleculeGraph.getRelationEntries({ downstreamMoleculeKey: molecule.stringKey });
1128
939
  if (relatedMolecules) for (const [relatedStringKey, { source }] of relatedMolecules) if (source === molecule.stringKey) {
1129
940
  const relatedKey = parseJson(relatedStringKey);
@@ -1174,10 +985,11 @@ function claimWithinStore(store, newProvenance, claim, exclusive) {
1174
985
  key: molecule.key,
1175
986
  exclusive: Boolean(exclusive),
1176
987
  from: priorProvenance,
1177
- to: [newProvenanceMolecule.key]
988
+ to: [newProvenanceMolecule.key],
989
+ timestamp: Date.now()
1178
990
  };
1179
991
  const isTransaction = isChildStore(target) && target.transactionMeta.phase === `building`;
1180
- if (isTransaction) target.transactionMeta.update.updates.push(transferEvent);
992
+ if (isTransaction) target.transactionMeta.update.subEvents.push(transferEvent);
1181
993
  return claim;
1182
994
  }
1183
995
 
@@ -1271,10 +1083,9 @@ function ingestSelectorUpdate(applying, selectorUpdate, store) {
1271
1083
  //#endregion
1272
1084
  //#region src/internal/ingest-updates/ingest-transaction-update.ts
1273
1085
  function ingestTransactionUpdate(applying, transactionUpdate, store) {
1274
- const updates = applying === `newValue` ? transactionUpdate.updates : [...transactionUpdate.updates].reverse();
1086
+ const updates = applying === `newValue` ? transactionUpdate.subEvents : [...transactionUpdate.subEvents].reverse();
1275
1087
  for (const updateFromTransaction of updates) switch (updateFromTransaction.type) {
1276
1088
  case `atom_update`:
1277
- case `selector_update`:
1278
1089
  ingestAtomUpdate(applying, updateFromTransaction, store);
1279
1090
  break;
1280
1091
  case `state_creation`:
@@ -1292,7 +1103,7 @@ function ingestTransactionUpdate(applying, transactionUpdate, store) {
1292
1103
  case `molecule_transfer`:
1293
1104
  ingestMoleculeTransferEvent(updateFromTransaction, applying, store);
1294
1105
  break;
1295
- case `transaction_update`:
1106
+ case `transaction_outcome`:
1296
1107
  ingestTransactionUpdate(applying, updateFromTransaction, store);
1297
1108
  break;
1298
1109
  }
@@ -1342,18 +1153,18 @@ const applyTransaction = (output, store) => {
1342
1153
  child.transactionMeta.update.output = output;
1343
1154
  parent.child = null;
1344
1155
  parent.on.transactionApplying.next(child.transactionMeta);
1345
- const { updates } = child.transactionMeta.update;
1346
- 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);
1347
1158
  ingestTransactionUpdate(`newValue`, child.transactionMeta.update, parent);
1348
1159
  if (isRootStore(parent)) {
1349
- setEpochNumberOfAction(parent, child.transactionMeta.update.key, child.transactionMeta.update.epoch);
1160
+ setEpochNumberOfAction(parent, child.transactionMeta.update.token.key, child.transactionMeta.update.epoch);
1350
1161
  const myTransaction = withdraw(store, {
1351
- key: child.transactionMeta.update.key,
1162
+ key: child.transactionMeta.update.token.key,
1352
1163
  type: `transaction`
1353
1164
  });
1354
1165
  myTransaction?.subject.next(child.transactionMeta.update);
1355
- store.logger.info(`🛬`, `transaction`, child.transactionMeta.update.key, `Finished applying transaction.`);
1356
- } 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);
1357
1168
  parent.on.transactionApplying.next(null);
1358
1169
  };
1359
1170
 
@@ -1409,7 +1220,7 @@ var LazyMap = class extends Map {
1409
1220
 
1410
1221
  //#endregion
1411
1222
  //#region src/internal/transaction/build-transaction.ts
1412
- const buildTransaction = (store, key, params, id) => {
1223
+ const buildTransaction = (store, token, params, id) => {
1413
1224
  const parent = newest(store);
1414
1225
  const childBase = {
1415
1226
  parent,
@@ -1440,15 +1251,16 @@ const buildTransaction = (store, key, params, id) => {
1440
1251
  moleculeJoins: new Junction(parent.moleculeJoins.toJSON(), { makeContentKey: parent.moleculeJoins.makeContentKey }),
1441
1252
  miscResources: new LazyMap(parent.miscResources)
1442
1253
  };
1443
- const epoch = getEpochNumberOfAction(store, key);
1254
+ const epoch = getEpochNumberOfAction(store, token.key);
1444
1255
  const transactionMeta = {
1445
1256
  phase: `building`,
1446
1257
  update: {
1447
- type: `transaction_update`,
1448
- key,
1258
+ type: `transaction_outcome`,
1259
+ token,
1449
1260
  id,
1450
1261
  epoch: epoch === void 0 ? NaN : epoch + 1,
1451
- updates: [],
1262
+ timestamp: Date.now(),
1263
+ subEvents: [],
1452
1264
  params,
1453
1265
  output: void 0
1454
1266
  },
@@ -1460,9 +1272,9 @@ const buildTransaction = (store, key, params, id) => {
1460
1272
  reset: ((...ps) => {
1461
1273
  resetInStore(child, ...ps);
1462
1274
  }),
1463
- run: (token, identifier = arbitrary()) => actUponStore(child, token, identifier),
1275
+ run: (t, identifier = arbitrary()) => actUponStore(child, t, identifier),
1464
1276
  find: ((...ps) => findInStore(store, ...ps)),
1465
- json: (token) => getJsonToken(child, token),
1277
+ json: (t) => getJsonToken(child, t),
1466
1278
  dispose: ((...ps) => {
1467
1279
  disposeFromStore(child, ...ps);
1468
1280
  }),
@@ -1471,7 +1283,7 @@ const buildTransaction = (store, key, params, id) => {
1471
1283
  };
1472
1284
  const child = Object.assign(childBase, { transactionMeta });
1473
1285
  parent.child = child;
1474
- store.logger.info(`🛫`, `transaction`, key, `Building transaction with params:`, params);
1286
+ store.logger.info(`🛫`, `transaction`, token.key, `Building transaction with params:`, params);
1475
1287
  return child;
1476
1288
  };
1477
1289
 
@@ -1484,7 +1296,8 @@ function createTransaction(store, options) {
1484
1296
  key,
1485
1297
  type: `transaction`,
1486
1298
  run: (params, id) => {
1487
- const childStore = buildTransaction(store, key, params, id);
1299
+ const token$1 = deposit(newTransaction);
1300
+ const childStore = buildTransaction(store, token$1, params, id);
1488
1301
  try {
1489
1302
  const target$1 = newest(store);
1490
1303
  const { toolkit } = childStore.transactionMeta;
@@ -1515,9 +1328,279 @@ const TRANSACTION_PHASES = [
1515
1328
  `applying`
1516
1329
  ];
1517
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
+
1518
1601
  //#endregion
1519
1602
  //#region src/internal/selector/create-writable-held-selector.ts
1520
- const createWritableHeldSelector = (store, options, family) => {
1603
+ function createWritableHeldSelector(store, options, family) {
1521
1604
  const target = newest(store);
1522
1605
  const subject = new Subject();
1523
1606
  const covered = /* @__PURE__ */ new Set();
@@ -1530,38 +1613,28 @@ const createWritableHeldSelector = (store, options, family) => {
1530
1613
  get,
1531
1614
  json
1532
1615
  };
1533
- const getSelf = (getFn = options.get, innerTarget = newest(store)) => {
1616
+ const getFrom = (innerTarget) => {
1534
1617
  const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1535
1618
  for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1536
1619
  innerTarget.selectorAtoms.delete(key);
1537
- getFn(getterToolkit, constant);
1620
+ options.get(getterToolkit, constant);
1538
1621
  writeToCache(innerTarget, mySelector, constant);
1539
1622
  store.logger.info(`✨`, type, key, `=`, constant);
1540
1623
  covered.clear();
1541
1624
  return constant;
1542
1625
  };
1543
- const setSelf = (next) => {
1544
- const innerTarget = newest(store);
1545
- const oldValue = getSelf(options.get, innerTarget);
1546
- const newValue = become(next)(oldValue);
1547
- store.logger.info(`📝`, type, key, `set (`, oldValue, `->`, newValue, `)`);
1548
- writeToCache(innerTarget, mySelector, newValue);
1549
- markDone(innerTarget, key);
1550
- if (isRootStore(innerTarget)) subject.next({
1551
- newValue,
1552
- oldValue
1553
- });
1554
- options.set(setterToolkit, newValue);
1626
+ const setSelf = () => {
1627
+ options.set(setterToolkit, constant);
1555
1628
  };
1556
1629
  const mySelector = {
1557
1630
  ...options,
1558
1631
  type,
1559
1632
  subject,
1560
- install: (s) => createWritableHeldSelector(s, options, family),
1561
- get: getSelf,
1562
- set: setSelf,
1563
- ...family && { family }
1633
+ getFrom,
1634
+ setSelf,
1635
+ install: (s) => createWritableHeldSelector(s, options, family)
1564
1636
  };
1637
+ if (family) mySelector.family = family;
1565
1638
  target.writableSelectors.set(key, mySelector);
1566
1639
  const token = {
1567
1640
  key,
@@ -1569,11 +1642,11 @@ const createWritableHeldSelector = (store, options, family) => {
1569
1642
  };
1570
1643
  if (family) token.family = family;
1571
1644
  return token;
1572
- };
1645
+ }
1573
1646
 
1574
1647
  //#endregion
1575
1648
  //#region src/internal/selector/create-writable-pure-selector.ts
1576
- const createWritablePureSelector = (store, options, family) => {
1649
+ function createWritablePureSelector(store, options, family) {
1577
1650
  const target = newest(store);
1578
1651
  const subject = new Subject();
1579
1652
  const covered = /* @__PURE__ */ new Set();
@@ -1586,40 +1659,30 @@ const createWritablePureSelector = (store, options, family) => {
1586
1659
  get,
1587
1660
  json
1588
1661
  };
1589
- const getSelf = (getFn = options.get, innerTarget = newest(store)) => {
1662
+ const getFrom = (innerTarget) => {
1590
1663
  const upstreamStates = innerTarget.selectorGraph.getRelationEntries({ downstreamSelectorKey: key });
1591
1664
  for (const [downstreamSelectorKey, { source }] of upstreamStates) if (source !== key) innerTarget.selectorGraph.delete(downstreamSelectorKey, key);
1592
1665
  innerTarget.selectorAtoms.delete(key);
1593
- const value = getFn(getterToolkit);
1666
+ const value = options.get(getterToolkit);
1594
1667
  const cached = writeToCache(innerTarget, mySelector, value);
1595
1668
  store.logger.info(`✨`, type, key, `=`, cached);
1596
1669
  covered.clear();
1597
- return value;
1670
+ return cached;
1598
1671
  };
1599
- const setSelf = (next) => {
1600
- const innerTarget = newest(store);
1601
- const oldValue = getSelf(options.get, innerTarget);
1602
- const newValue = become(next)(oldValue);
1603
- store.logger.info(`📝`, type, key, `set (`, oldValue, `->`, newValue, `)`);
1604
- writeToCache(innerTarget, mySelector, newValue);
1605
- markDone(innerTarget, options.key);
1606
- if (isRootStore(innerTarget)) subject.next({
1607
- newValue,
1608
- oldValue
1609
- });
1672
+ const setSelf = (newValue) => {
1610
1673
  options.set(setterToolkit, newValue);
1611
1674
  };
1612
1675
  const mySelector = {
1613
1676
  ...options,
1614
1677
  type,
1615
1678
  subject,
1616
- install: (s) => createWritablePureSelector(s, options, family),
1617
- get: getSelf,
1618
- set: setSelf,
1619
- ...family && { family }
1679
+ getFrom,
1680
+ setSelf,
1681
+ install: (s) => createWritablePureSelector(s, options, family)
1620
1682
  };
1683
+ if (family) mySelector.family = family;
1621
1684
  target.writableSelectors.set(key, mySelector);
1622
- const initialValue = getSelf();
1685
+ const initialValue = getFrom(target);
1623
1686
  store.logger.info(`✨`, mySelector.type, mySelector.key, `=`, initialValue);
1624
1687
  const token = {
1625
1688
  key,
@@ -1627,7 +1690,7 @@ const createWritablePureSelector = (store, options, family) => {
1627
1690
  };
1628
1691
  if (family) token.family = family;
1629
1692
  return token;
1630
- };
1693
+ }
1631
1694
 
1632
1695
  //#endregion
1633
1696
  //#region src/internal/selector/create-standalone-selector.ts
@@ -1676,7 +1739,8 @@ function disposeSelector(store, selectorToken) {
1676
1739
  family.subject.next({
1677
1740
  type: `state_disposal`,
1678
1741
  subType: `selector`,
1679
- token: selectorToken
1742
+ token: selectorToken,
1743
+ timestamp: Date.now()
1680
1744
  });
1681
1745
  }
1682
1746
  break;
@@ -1691,7 +1755,8 @@ function disposeSelector(store, selectorToken) {
1691
1755
  family.subject.next({
1692
1756
  type: `state_disposal`,
1693
1757
  subType: `selector`,
1694
- token: selectorToken
1758
+ token: selectorToken,
1759
+ timestamp: Date.now()
1695
1760
  });
1696
1761
  }
1697
1762
  break;
@@ -1706,7 +1771,8 @@ function disposeSelector(store, selectorToken) {
1706
1771
  family.subject.next({
1707
1772
  type: `state_disposal`,
1708
1773
  subType: `selector`,
1709
- token: selectorToken
1774
+ token: selectorToken,
1775
+ timestamp: Date.now()
1710
1776
  });
1711
1777
  }
1712
1778
  break;
@@ -1721,7 +1787,8 @@ function disposeSelector(store, selectorToken) {
1721
1787
  family.subject.next({
1722
1788
  type: `state_disposal`,
1723
1789
  subType: `selector`,
1724
- token: selectorToken
1790
+ token: selectorToken,
1791
+ timestamp: Date.now()
1725
1792
  });
1726
1793
  }
1727
1794
  break;
@@ -1731,10 +1798,11 @@ function disposeSelector(store, selectorToken) {
1731
1798
  target.selectorGraph.delete(key);
1732
1799
  target.moleculeData.delete(familyMeta.key, familyMeta.subKey);
1733
1800
  store.logger.info(`🔥`, selectorToken.type, key, `deleted`);
1734
- 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({
1735
1802
  type: `state_disposal`,
1736
1803
  subType: `selector`,
1737
- token: selectorToken
1804
+ token: selectorToken,
1805
+ timestamp: Date.now()
1738
1806
  });
1739
1807
  else store.on.selectorDisposal.next(selectorToken);
1740
1808
  }
@@ -1766,7 +1834,8 @@ function createReadonlyPureSelectorFamily(store, options, internalRoles) {
1766
1834
  }, family);
1767
1835
  subject.next({
1768
1836
  type: `state_creation`,
1769
- token
1837
+ token,
1838
+ timestamp: Date.now()
1770
1839
  });
1771
1840
  return token;
1772
1841
  };
@@ -1814,7 +1883,8 @@ function createRegularAtomFamily(store, options, internalRoles) {
1814
1883
  const token = createRegularAtom(target, individualOptions, family);
1815
1884
  subject.next({
1816
1885
  type: `state_creation`,
1817
- token
1886
+ token,
1887
+ timestamp: Date.now()
1818
1888
  });
1819
1889
  return token;
1820
1890
  };
@@ -1855,7 +1925,8 @@ function createReadonlyHeldSelectorFamily(store, options, internalRoles) {
1855
1925
  }, family);
1856
1926
  subject.next({
1857
1927
  type: `state_creation`,
1858
- token
1928
+ token,
1929
+ timestamp: Date.now()
1859
1930
  });
1860
1931
  return token;
1861
1932
  };
@@ -1897,7 +1968,8 @@ function createWritableHeldSelectorFamily(store, options, internalRoles) {
1897
1968
  }, family);
1898
1969
  subject.next({
1899
1970
  type: `state_creation`,
1900
- token
1971
+ token,
1972
+ timestamp: Date.now()
1901
1973
  });
1902
1974
  return token;
1903
1975
  };
@@ -1938,7 +2010,8 @@ function createWritablePureSelectorFamily(store, options, internalRoles) {
1938
2010
  }, family);
1939
2011
  subject.next({
1940
2012
  type: `state_creation`,
1941
- token
2013
+ token,
2014
+ timestamp: Date.now()
1942
2015
  });
1943
2016
  return token;
1944
2017
  };
@@ -1970,34 +2043,6 @@ function createSelectorFamily(store, options) {
1970
2043
  return createReadonlyPureSelectorFamily(store, options);
1971
2044
  }
1972
2045
 
1973
- //#endregion
1974
- //#region src/internal/families/init-family-member.ts
1975
- function initFamilyMemberInStore(store, token, key) {
1976
- const family = store.families.get(token.key);
1977
- if (family === void 0) throw new NotFoundError(token, store);
1978
- const state = family(key);
1979
- const target = newest(store);
1980
- if (state.family) {
1981
- if (isRootStore(target)) switch (state.type) {
1982
- case `atom`:
1983
- case `mutable_atom`:
1984
- store.on.atomCreation.next(state);
1985
- break;
1986
- case `writable_pure_selector`:
1987
- case `readonly_pure_selector`:
1988
- case `writable_held_selector`:
1989
- case `readonly_held_selector`:
1990
- store.on.selectorCreation.next(state);
1991
- break;
1992
- }
1993
- else if (isChildStore(target) && target.on.transactionApplying.state === null) target.transactionMeta.update.updates.push({
1994
- type: `state_creation`,
1995
- token: state
1996
- });
1997
- }
1998
- return state;
1999
- }
2000
-
2001
2046
  //#endregion
2002
2047
  //#region src/internal/families/seek-in-store.ts
2003
2048
  function seekInStore(store, token, key) {
@@ -2025,22 +2070,11 @@ function seekInStore(store, token, key) {
2025
2070
 
2026
2071
  //#endregion
2027
2072
  //#region src/internal/families/find-in-store.ts
2028
- function findInStore(store, token, key) {
2029
- let state = seekInStore(store, token, key);
2030
- if (state) return state;
2031
- const stringKey = stringifyJson(key);
2032
- const molecule = store.molecules.get(stringKey);
2033
- if (!molecule && store.config.lifespan === `immortal`) {
2034
- const fakeToken = counterfeit(token, key);
2035
- store.logger.error(`❌`, fakeToken.type, fakeToken.key, `was not found in store "${store.config.name}"; returned a counterfeit token.`);
2036
- return fakeToken;
2037
- }
2038
- state = initFamilyMemberInStore(store, token, key);
2039
- if (molecule) {
2040
- const target = newest(store);
2041
- target.moleculeData.set(stringKey, token.key);
2042
- }
2043
- return state;
2073
+ function findInStore(store, familyToken, key) {
2074
+ const existingStateToken = seekInStore(store, familyToken, key);
2075
+ if (existingStateToken) return existingStateToken;
2076
+ const newStateToken = mintInStore(store, familyToken, key);
2077
+ return newStateToken;
2044
2078
  }
2045
2079
 
2046
2080
  //#endregion
@@ -2275,7 +2309,7 @@ var Tracker = class {
2275
2309
  captureSignalsFromCore(mutableState, latestSignalState, target) {
2276
2310
  const stateKey = mutableState.key;
2277
2311
  const storeName = target.config.name;
2278
- const storeStatus = isChildStore(target) ? target.transactionMeta.update.key : `main`;
2312
+ const storeStatus = isChildStore(target) ? target.transactionMeta.update.token.key : `main`;
2279
2313
  const subscriptionKey = `tracker:${storeName}:${storeStatus}:${stateKey}`;
2280
2314
  const trackerCapturesOutboundSignal = (update) => {
2281
2315
  setIntoStore(target, latestSignalState, update);
@@ -2290,7 +2324,7 @@ var Tracker = class {
2290
2324
  }.bind(this));
2291
2325
  }
2292
2326
  supplySignalsToCore(mutableState, latestSignalState, target) {
2293
- const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2327
+ const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.token.key : `main`}:${mutableState.key}`;
2294
2328
  subscribeToState(target, latestSignalState, subscriptionKey, function trackerCapturesInboundSignal({ newValue, oldValue }) {
2295
2329
  const timelineId = target.timelineTopics.getRelatedKey(latestSignalState.key);
2296
2330
  if (timelineId && target.timelines.get(timelineId)?.timeTraveling) {
@@ -2454,7 +2488,8 @@ function createMutableAtomFamily(store, options, internalRoles) {
2454
2488
  const token = createMutableAtom(target, individualOptions, family);
2455
2489
  subject.next({
2456
2490
  type: `state_creation`,
2457
- token
2491
+ token,
2492
+ timestamp: Date.now()
2458
2493
  });
2459
2494
  return token;
2460
2495
  };
@@ -2533,7 +2568,7 @@ const getUpdateToken = (mutableAtomToken) => {
2533
2568
  //#endregion
2534
2569
  //#region src/internal/mutable/transceiver.ts
2535
2570
  function isTransceiver(value) {
2536
- return typeof value === `object` && value !== null && `do` in value && `undo` in value && `subscribe` in value;
2571
+ 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;
2537
2572
  }
2538
2573
 
2539
2574
  //#endregion
@@ -2733,7 +2768,8 @@ function disposeAtom(store, atomToken) {
2733
2768
  type: `state_disposal`,
2734
2769
  subType: `atom`,
2735
2770
  token: atomToken,
2736
- value: lastValue
2771
+ value: lastValue,
2772
+ timestamp: Date.now()
2737
2773
  };
2738
2774
  atomFamily$1.subject.next(disposal);
2739
2775
  const isChild = isChildStore(target);
@@ -2750,14 +2786,22 @@ function disposeAtom(store, atomToken) {
2750
2786
  }
2751
2787
  store.logger.info(`🔥`, `atom`, key, `deleted`);
2752
2788
  if (isChild && target.transactionMeta.phase === `building`) {
2753
- const mostRecentUpdate = target.transactionMeta.update.updates.at(-1);
2789
+ const mostRecentUpdate = target.transactionMeta.update.subEvents.at(-1);
2754
2790
  const wasMoleculeDisposal = mostRecentUpdate?.type === `molecule_disposal`;
2755
2791
  const updateAlreadyCaptured = wasMoleculeDisposal && mostRecentUpdate.values.some(([k]) => k === atom.family?.key);
2756
- if (!updateAlreadyCaptured) target.transactionMeta.update.updates.push(disposal);
2792
+ if (!updateAlreadyCaptured) target.transactionMeta.update.subEvents.push(disposal);
2757
2793
  } else store.on.atomDisposal.next(atomToken);
2758
2794
  }
2759
2795
  }
2760
2796
 
2797
+ //#endregion
2798
+ //#region src/internal/atom/has-role.ts
2799
+ const INTERNAL_ROLES = [`tracker:signal`];
2800
+ function hasRole(atom, role) {
2801
+ if (`internalRoles` in atom === false) return false;
2802
+ return atom.internalRoles.includes(role);
2803
+ }
2804
+
2761
2805
  //#endregion
2762
2806
  //#region src/internal/install-into-store.ts
2763
2807
  /**
@@ -2771,12 +2815,12 @@ function disposeAtom(store, atomToken) {
2771
2815
  function installIntoStore(tokens, target, source) {
2772
2816
  const sourceNewest = newest(source);
2773
2817
  if (isChildStore(sourceNewest)) {
2774
- 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.`);
2818
+ 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.`);
2775
2819
  return;
2776
2820
  }
2777
2821
  const targetNewest = newest(target);
2778
2822
  if (isChildStore(targetNewest)) {
2779
- 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.`);
2823
+ 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.`);
2780
2824
  return;
2781
2825
  }
2782
2826
  for (const token of tokens) {
@@ -3327,37 +3371,39 @@ function addAtomToTimeline(store, atomToken, tl) {
3327
3371
  }, { topicType: `atom` });
3328
3372
  tl.subscriptions.set(atom.key, atom.subject.subscribe(`timeline`, function timelineCapturesAtomUpdate(update) {
3329
3373
  const target = newest(store);
3330
- const currentSelectorKey = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.token.key : null;
3331
- const currentSelectorTime = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.time : null;
3374
+ const currentSelectorToken = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.token : null;
3375
+ const currentSelectorTime = store.operation.open && store.operation.token.type === `writable_pure_selector` ? store.operation.timestamp : null;
3332
3376
  const txUpdateInProgress = target.on.transactionApplying.state?.update;
3333
- store.logger.info(`⏳`, `timeline`, tl.key, `atom`, atomToken.key, `went`, update.oldValue, `->`, update.newValue, txUpdateInProgress ? `in transaction "${txUpdateInProgress.key}"` : currentSelectorKey ? `in selector "${currentSelectorKey}"` : ``);
3377
+ 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}"` : ``);
3334
3378
  if (tl.timeTraveling === null) if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress);
3335
- else if (currentSelectorKey && currentSelectorTime) {
3379
+ else if (currentSelectorToken && currentSelectorTime) {
3336
3380
  let latestUpdate = tl.history.at(-1);
3337
3381
  if (currentSelectorTime !== tl.selectorTime) {
3338
3382
  latestUpdate = {
3339
3383
  type: `selector_update`,
3340
3384
  timestamp: currentSelectorTime,
3341
- key: currentSelectorKey,
3385
+ token: currentSelectorToken,
3342
3386
  atomUpdates: []
3343
3387
  };
3344
3388
  latestUpdate.atomUpdates.push({
3345
- key: atom.key,
3346
3389
  type: `atom_update`,
3347
- ...update
3390
+ token: atomToken,
3391
+ update,
3392
+ timestamp: Date.now()
3348
3393
  });
3349
3394
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3350
3395
  tl.history.push(latestUpdate);
3351
- store.logger.info(`⌛`, `timeline`, tl.key, `got a selector_update "${currentSelectorKey}" with`, latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key));
3396
+ store.logger.info(`⌛`, `timeline`, tl.key, `got a selector_update "${currentSelectorToken.key}" with`, latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.token.key));
3352
3397
  tl.at = tl.history.length;
3353
3398
  tl.selectorTime = currentSelectorTime;
3354
3399
  } else if (latestUpdate?.type === `selector_update`) {
3355
3400
  latestUpdate.atomUpdates.push({
3356
- key: atom.key,
3357
3401
  type: `atom_update`,
3358
- ...update
3402
+ token: atomToken,
3403
+ update,
3404
+ timestamp: Date.now()
3359
3405
  });
3360
- store.logger.info(`⌛`, `timeline`, tl.key, `set selector_update "${currentSelectorKey}" to`, latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key));
3406
+ store.logger.info(`⌛`, `timeline`, tl.key, `set selector_update "${currentSelectorToken.key}" to`, latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.token.key));
3361
3407
  }
3362
3408
  if (latestUpdate) {
3363
3409
  const willCaptureSelectorUpdate = tl.shouldCapture?.(latestUpdate, tl) ?? true;
@@ -3373,12 +3419,10 @@ function addAtomToTimeline(store, atomToken, tl) {
3373
3419
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3374
3420
  const atomUpdate = {
3375
3421
  type: `atom_update`,
3376
- timestamp,
3377
- key: atom.key,
3378
- oldValue: update.oldValue,
3379
- newValue: update.newValue
3422
+ token: deposit(atom),
3423
+ update,
3424
+ timestamp
3380
3425
  };
3381
- if (atom.family) atomUpdate.family = atom.family;
3382
3426
  const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true;
3383
3427
  store.logger.info(`⌛`, `timeline`, tl.key, `got an atom_update to "${atom.key}"`);
3384
3428
  if (willCapture) {
@@ -3401,7 +3445,7 @@ function addAtomFamilyToTimeline(store, atomFamilyToken, tl) {
3401
3445
  for (const atom of store.atoms.values()) if (atom.family?.key === family.key) addAtomToTimeline(store, atom, tl);
3402
3446
  }
3403
3447
  function joinTransaction(store, tl, txUpdateInProgress) {
3404
- const currentTxKey = txUpdateInProgress.key;
3448
+ const currentTxKey = txUpdateInProgress.token.key;
3405
3449
  const currentTxInstanceId = txUpdateInProgress.id;
3406
3450
  const currentTxToken = {
3407
3451
  key: currentTxKey,
@@ -3416,11 +3460,10 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3416
3460
  if (tl.timeTraveling === null && currentTxInstanceId) {
3417
3461
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3418
3462
  const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key);
3419
- const updates = filterTransactionUpdates(transactionUpdate.updates, timelineTopics);
3463
+ const subEventsFiltered = filterTransactionSubEvents(transactionUpdate.subEvents, timelineTopics);
3420
3464
  const timelineTransactionUpdate = {
3421
- timestamp: Date.now(),
3422
3465
  ...transactionUpdate,
3423
- updates
3466
+ subEvents: subEventsFiltered
3424
3467
  };
3425
3468
  const willCapture = tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true;
3426
3469
  if (willCapture) {
@@ -3432,12 +3475,13 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3432
3475
  });
3433
3476
  }
3434
3477
  }
3435
- function filterTransactionUpdates(updates, timelineTopics) {
3478
+ function filterTransactionSubEvents(updates, timelineTopics) {
3436
3479
  return updates.filter((updateFromTx) => {
3437
- if (updateFromTx.type === `transaction_update`) return true;
3480
+ if (updateFromTx.type === `transaction_outcome`) return true;
3438
3481
  let key;
3439
3482
  let familyKey;
3440
3483
  switch (updateFromTx.type) {
3484
+ case `atom_update`:
3441
3485
  case `state_creation`:
3442
3486
  case `state_disposal`:
3443
3487
  key = updateFromTx.token.key;
@@ -3446,35 +3490,28 @@ function filterTransactionUpdates(updates, timelineTopics) {
3446
3490
  case `molecule_creation`:
3447
3491
  case `molecule_disposal`:
3448
3492
  case `molecule_transfer`: return true;
3449
- case `atom_update`:
3450
- case `selector_update`:
3451
- key = updateFromTx.key;
3452
- familyKey = updateFromTx.family?.key;
3453
- break;
3454
3493
  }
3455
3494
  timelineTopics.has(key);
3456
3495
  if (familyKey && timelineTopics.has(familyKey)) return true;
3457
3496
  return timelineTopics.has(key);
3458
3497
  }).map((updateFromTx) => {
3459
- if (`updates` in updateFromTx) return {
3498
+ if (`subEvents` in updateFromTx) return {
3460
3499
  ...updateFromTx,
3461
- updates: filterTransactionUpdates(updateFromTx.updates, timelineTopics)
3500
+ subEvents: filterTransactionSubEvents(updateFromTx.subEvents, timelineTopics)
3462
3501
  };
3463
3502
  return updateFromTx;
3464
3503
  });
3465
3504
  }
3466
3505
  function handleStateLifecycleEvent(store, event, tl) {
3467
- const timestamp = Date.now();
3468
- const timelineEvent = Object.assign(event, { timestamp });
3469
3506
  if (!tl.timeTraveling) {
3470
3507
  const target = newest(store);
3471
3508
  if (isChildStore(target)) {} else {
3472
3509
  const txUpdateInProgress = target.on.transactionApplying.state;
3473
3510
  if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress.update);
3474
3511
  else {
3475
- tl.history.push(timelineEvent);
3512
+ tl.history.push(event);
3476
3513
  tl.at = tl.history.length;
3477
- tl.subject.next(timelineEvent);
3514
+ tl.subject.next(event);
3478
3515
  }
3479
3516
  }
3480
3517
  }
@@ -3513,7 +3550,7 @@ const timeTravel = (store, action, token) => {
3513
3550
  case `selector_update`:
3514
3551
  ingestSelectorUpdate(applying, update, store);
3515
3552
  break;
3516
- case `transaction_update`:
3553
+ case `transaction_outcome`:
3517
3554
  ingestTransactionUpdate(applying, update, store);
3518
3555
  break;
3519
3556
  case `state_creation`: