atom.io 0.36.3 → 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 +543 -504
  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 +5 -5
  47. package/src/internal/atom/dispose-atom.ts +5 -4
  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 +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 +15 -28
  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.`);
@@ -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}".`);
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;
1009
834
  }
835
+ return protoUpdate;
1010
836
  };
1011
837
 
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
- }
1021
-
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,7 +1883,8 @@ 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
  };
@@ -1853,7 +1925,8 @@ function createReadonlyHeldSelectorFamily(store, options, internalRoles) {
1853
1925
  }, family);
1854
1926
  subject.next({
1855
1927
  type: `state_creation`,
1856
- token
1928
+ token,
1929
+ timestamp: Date.now()
1857
1930
  });
1858
1931
  return token;
1859
1932
  };
@@ -1895,7 +1968,8 @@ function createWritableHeldSelectorFamily(store, options, internalRoles) {
1895
1968
  }, family);
1896
1969
  subject.next({
1897
1970
  type: `state_creation`,
1898
- token
1971
+ token,
1972
+ timestamp: Date.now()
1899
1973
  });
1900
1974
  return token;
1901
1975
  };
@@ -1936,7 +2010,8 @@ function createWritablePureSelectorFamily(store, options, internalRoles) {
1936
2010
  }, family);
1937
2011
  subject.next({
1938
2012
  type: `state_creation`,
1939
- token
2013
+ token,
2014
+ timestamp: Date.now()
1940
2015
  });
1941
2016
  return token;
1942
2017
  };
@@ -1968,34 +2043,6 @@ function createSelectorFamily(store, options) {
1968
2043
  return createReadonlyPureSelectorFamily(store, options);
1969
2044
  }
1970
2045
 
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
2046
  //#endregion
2000
2047
  //#region src/internal/families/seek-in-store.ts
2001
2048
  function seekInStore(store, token, key) {
@@ -2023,22 +2070,11 @@ function seekInStore(store, token, key) {
2023
2070
 
2024
2071
  //#endregion
2025
2072
  //#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;
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;
2042
2078
  }
2043
2079
 
2044
2080
  //#endregion
@@ -2273,7 +2309,7 @@ var Tracker = class {
2273
2309
  captureSignalsFromCore(mutableState, latestSignalState, target) {
2274
2310
  const stateKey = mutableState.key;
2275
2311
  const storeName = target.config.name;
2276
- const storeStatus = isChildStore(target) ? target.transactionMeta.update.key : `main`;
2312
+ const storeStatus = isChildStore(target) ? target.transactionMeta.update.token.key : `main`;
2277
2313
  const subscriptionKey = `tracker:${storeName}:${storeStatus}:${stateKey}`;
2278
2314
  const trackerCapturesOutboundSignal = (update) => {
2279
2315
  setIntoStore(target, latestSignalState, update);
@@ -2288,7 +2324,7 @@ var Tracker = class {
2288
2324
  }.bind(this));
2289
2325
  }
2290
2326
  supplySignalsToCore(mutableState, latestSignalState, target) {
2291
- 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}`;
2292
2328
  subscribeToState(target, latestSignalState, subscriptionKey, function trackerCapturesInboundSignal({ newValue, oldValue }) {
2293
2329
  const timelineId = target.timelineTopics.getRelatedKey(latestSignalState.key);
2294
2330
  if (timelineId && target.timelines.get(timelineId)?.timeTraveling) {
@@ -2452,7 +2488,8 @@ function createMutableAtomFamily(store, options, internalRoles) {
2452
2488
  const token = createMutableAtom(target, individualOptions, family);
2453
2489
  subject.next({
2454
2490
  type: `state_creation`,
2455
- token
2491
+ token,
2492
+ timestamp: Date.now()
2456
2493
  });
2457
2494
  return token;
2458
2495
  };
@@ -2531,7 +2568,7 @@ const getUpdateToken = (mutableAtomToken) => {
2531
2568
  //#endregion
2532
2569
  //#region src/internal/mutable/transceiver.ts
2533
2570
  function isTransceiver(value) {
2534
- 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;
2535
2572
  }
2536
2573
 
2537
2574
  //#endregion
@@ -2731,7 +2768,8 @@ function disposeAtom(store, atomToken) {
2731
2768
  type: `state_disposal`,
2732
2769
  subType: `atom`,
2733
2770
  token: atomToken,
2734
- value: lastValue
2771
+ value: lastValue,
2772
+ timestamp: Date.now()
2735
2773
  };
2736
2774
  atomFamily$1.subject.next(disposal);
2737
2775
  const isChild = isChildStore(target);
@@ -2748,14 +2786,22 @@ function disposeAtom(store, atomToken) {
2748
2786
  }
2749
2787
  store.logger.info(`🔥`, `atom`, key, `deleted`);
2750
2788
  if (isChild && target.transactionMeta.phase === `building`) {
2751
- const mostRecentUpdate = target.transactionMeta.update.updates.at(-1);
2789
+ const mostRecentUpdate = target.transactionMeta.update.subEvents.at(-1);
2752
2790
  const wasMoleculeDisposal = mostRecentUpdate?.type === `molecule_disposal`;
2753
2791
  const updateAlreadyCaptured = wasMoleculeDisposal && mostRecentUpdate.values.some(([k]) => k === atom.family?.key);
2754
- if (!updateAlreadyCaptured) target.transactionMeta.update.updates.push(disposal);
2792
+ if (!updateAlreadyCaptured) target.transactionMeta.update.subEvents.push(disposal);
2755
2793
  } else store.on.atomDisposal.next(atomToken);
2756
2794
  }
2757
2795
  }
2758
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
+
2759
2805
  //#endregion
2760
2806
  //#region src/internal/install-into-store.ts
2761
2807
  /**
@@ -2769,12 +2815,12 @@ function disposeAtom(store, atomToken) {
2769
2815
  function installIntoStore(tokens, target, source) {
2770
2816
  const sourceNewest = newest(source);
2771
2817
  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.`);
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.`);
2773
2819
  return;
2774
2820
  }
2775
2821
  const targetNewest = newest(target);
2776
2822
  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.`);
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.`);
2778
2824
  return;
2779
2825
  }
2780
2826
  for (const token of tokens) {
@@ -3325,37 +3371,39 @@ function addAtomToTimeline(store, atomToken, tl) {
3325
3371
  }, { topicType: `atom` });
3326
3372
  tl.subscriptions.set(atom.key, atom.subject.subscribe(`timeline`, function timelineCapturesAtomUpdate(update) {
3327
3373
  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;
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;
3330
3376
  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}"` : ``);
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}"` : ``);
3332
3378
  if (tl.timeTraveling === null) if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress);
3333
- else if (currentSelectorKey && currentSelectorTime) {
3379
+ else if (currentSelectorToken && currentSelectorTime) {
3334
3380
  let latestUpdate = tl.history.at(-1);
3335
3381
  if (currentSelectorTime !== tl.selectorTime) {
3336
3382
  latestUpdate = {
3337
3383
  type: `selector_update`,
3338
3384
  timestamp: currentSelectorTime,
3339
- key: currentSelectorKey,
3385
+ token: currentSelectorToken,
3340
3386
  atomUpdates: []
3341
3387
  };
3342
3388
  latestUpdate.atomUpdates.push({
3343
- key: atom.key,
3344
3389
  type: `atom_update`,
3345
- ...update
3390
+ token: atomToken,
3391
+ update,
3392
+ timestamp: Date.now()
3346
3393
  });
3347
3394
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3348
3395
  tl.history.push(latestUpdate);
3349
- 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));
3350
3397
  tl.at = tl.history.length;
3351
3398
  tl.selectorTime = currentSelectorTime;
3352
3399
  } else if (latestUpdate?.type === `selector_update`) {
3353
3400
  latestUpdate.atomUpdates.push({
3354
- key: atom.key,
3355
3401
  type: `atom_update`,
3356
- ...update
3402
+ token: atomToken,
3403
+ update,
3404
+ timestamp: Date.now()
3357
3405
  });
3358
- 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));
3359
3407
  }
3360
3408
  if (latestUpdate) {
3361
3409
  const willCaptureSelectorUpdate = tl.shouldCapture?.(latestUpdate, tl) ?? true;
@@ -3371,12 +3419,10 @@ function addAtomToTimeline(store, atomToken, tl) {
3371
3419
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3372
3420
  const atomUpdate = {
3373
3421
  type: `atom_update`,
3374
- timestamp,
3375
- key: atom.key,
3376
- oldValue: update.oldValue,
3377
- newValue: update.newValue
3422
+ token: deposit(atom),
3423
+ update,
3424
+ timestamp
3378
3425
  };
3379
- if (atom.family) atomUpdate.family = atom.family;
3380
3426
  const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true;
3381
3427
  store.logger.info(`⌛`, `timeline`, tl.key, `got an atom_update to "${atom.key}"`);
3382
3428
  if (willCapture) {
@@ -3399,7 +3445,7 @@ function addAtomFamilyToTimeline(store, atomFamilyToken, tl) {
3399
3445
  for (const atom of store.atoms.values()) if (atom.family?.key === family.key) addAtomToTimeline(store, atom, tl);
3400
3446
  }
3401
3447
  function joinTransaction(store, tl, txUpdateInProgress) {
3402
- const currentTxKey = txUpdateInProgress.key;
3448
+ const currentTxKey = txUpdateInProgress.token.key;
3403
3449
  const currentTxInstanceId = txUpdateInProgress.id;
3404
3450
  const currentTxToken = {
3405
3451
  key: currentTxKey,
@@ -3414,11 +3460,10 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3414
3460
  if (tl.timeTraveling === null && currentTxInstanceId) {
3415
3461
  if (tl.at !== tl.history.length) tl.history.splice(tl.at);
3416
3462
  const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key);
3417
- const updates = filterTransactionUpdates(transactionUpdate.updates, timelineTopics);
3463
+ const subEventsFiltered = filterTransactionSubEvents(transactionUpdate.subEvents, timelineTopics);
3418
3464
  const timelineTransactionUpdate = {
3419
- timestamp: Date.now(),
3420
3465
  ...transactionUpdate,
3421
- updates
3466
+ subEvents: subEventsFiltered
3422
3467
  };
3423
3468
  const willCapture = tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true;
3424
3469
  if (willCapture) {
@@ -3430,12 +3475,13 @@ function joinTransaction(store, tl, txUpdateInProgress) {
3430
3475
  });
3431
3476
  }
3432
3477
  }
3433
- function filterTransactionUpdates(updates, timelineTopics) {
3478
+ function filterTransactionSubEvents(updates, timelineTopics) {
3434
3479
  return updates.filter((updateFromTx) => {
3435
- if (updateFromTx.type === `transaction_update`) return true;
3480
+ if (updateFromTx.type === `transaction_outcome`) return true;
3436
3481
  let key;
3437
3482
  let familyKey;
3438
3483
  switch (updateFromTx.type) {
3484
+ case `atom_update`:
3439
3485
  case `state_creation`:
3440
3486
  case `state_disposal`:
3441
3487
  key = updateFromTx.token.key;
@@ -3444,35 +3490,28 @@ function filterTransactionUpdates(updates, timelineTopics) {
3444
3490
  case `molecule_creation`:
3445
3491
  case `molecule_disposal`:
3446
3492
  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
3493
  }
3453
3494
  timelineTopics.has(key);
3454
3495
  if (familyKey && timelineTopics.has(familyKey)) return true;
3455
3496
  return timelineTopics.has(key);
3456
3497
  }).map((updateFromTx) => {
3457
- if (`updates` in updateFromTx) return {
3498
+ if (`subEvents` in updateFromTx) return {
3458
3499
  ...updateFromTx,
3459
- updates: filterTransactionUpdates(updateFromTx.updates, timelineTopics)
3500
+ subEvents: filterTransactionSubEvents(updateFromTx.subEvents, timelineTopics)
3460
3501
  };
3461
3502
  return updateFromTx;
3462
3503
  });
3463
3504
  }
3464
3505
  function handleStateLifecycleEvent(store, event, tl) {
3465
- const timestamp = Date.now();
3466
- const timelineEvent = Object.assign(event, { timestamp });
3467
3506
  if (!tl.timeTraveling) {
3468
3507
  const target = newest(store);
3469
3508
  if (isChildStore(target)) {} else {
3470
3509
  const txUpdateInProgress = target.on.transactionApplying.state;
3471
3510
  if (txUpdateInProgress) joinTransaction(store, tl, txUpdateInProgress.update);
3472
3511
  else {
3473
- tl.history.push(timelineEvent);
3512
+ tl.history.push(event);
3474
3513
  tl.at = tl.history.length;
3475
- tl.subject.next(timelineEvent);
3514
+ tl.subject.next(event);
3476
3515
  }
3477
3516
  }
3478
3517
  }
@@ -3511,7 +3550,7 @@ const timeTravel = (store, action, token) => {
3511
3550
  case `selector_update`:
3512
3551
  ingestSelectorUpdate(applying, update, store);
3513
3552
  break;
3514
- case `transaction_update`:
3553
+ case `transaction_outcome`:
3515
3554
  ingestTransactionUpdate(applying, update, store);
3516
3555
  break;
3517
3556
  case `state_creation`: