atom.io 0.27.4 → 0.28.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 (134) hide show
  1. package/data/dist/index.d.ts +31 -29
  2. package/data/dist/index.js +65 -81
  3. package/data/src/dict.ts +9 -12
  4. package/data/src/join.ts +30 -33
  5. package/data/src/struct-family.ts +17 -23
  6. package/data/src/struct.ts +9 -12
  7. package/dist/{chunk-JRENM6KL.js → chunk-BX3MTH2Z.js} +482 -385
  8. package/dist/chunk-D52JNVER.js +721 -0
  9. package/dist/chunk-EUVKUTW3.js +89 -0
  10. package/dist/index.d.ts +4 -3
  11. package/dist/index.js +35 -53
  12. package/ephemeral/dist/index.js +1 -1
  13. package/ephemeral/src/find-state.ts +1 -1
  14. package/immortal/dist/index.js +2 -2
  15. package/immortal/src/seek-state.ts +2 -2
  16. package/internal/dist/index.d.ts +141 -87
  17. package/internal/dist/index.js +1 -1
  18. package/internal/src/atom/create-regular-atom.ts +3 -3
  19. package/internal/src/atom/create-standalone-atom.ts +7 -5
  20. package/internal/src/atom/dispose-atom.ts +2 -9
  21. package/internal/src/families/create-atom-family.ts +5 -5
  22. package/internal/src/families/create-readonly-selector-family.ts +20 -9
  23. package/internal/src/families/create-regular-atom-family.ts +15 -6
  24. package/internal/src/families/create-selector-family.ts +5 -5
  25. package/internal/src/families/create-writable-selector-family.ts +20 -10
  26. package/internal/src/families/dispose-from-store.ts +43 -29
  27. package/internal/src/families/find-in-store.ts +28 -18
  28. package/internal/src/families/init-family-member.ts +9 -9
  29. package/internal/src/families/seek-in-store.ts +10 -10
  30. package/internal/src/get-state/get-from-store.ts +70 -47
  31. package/internal/src/ingest-updates/ingest-atom-update.ts +1 -1
  32. package/internal/src/ingest-updates/ingest-creation-disposal.ts +15 -6
  33. package/internal/src/molecule/create-molecule-family.ts +1 -1
  34. package/internal/src/molecule/dispose-molecule.ts +7 -18
  35. package/internal/src/molecule/grow-molecule-in-store.ts +1 -1
  36. package/internal/src/molecule/make-molecule-in-store.ts +5 -5
  37. package/internal/src/mutable/create-mutable-atom-family.ts +15 -6
  38. package/internal/src/mutable/create-mutable-atom.ts +3 -3
  39. package/internal/src/mutable/get-json-token.ts +2 -2
  40. package/internal/src/mutable/tracker-family.ts +3 -3
  41. package/internal/src/mutable/tracker.ts +14 -18
  42. package/internal/src/pretty-print.ts +1 -16
  43. package/internal/src/selector/create-readonly-selector.ts +2 -2
  44. package/internal/src/selector/create-standalone-selector.ts +5 -5
  45. package/internal/src/selector/create-writable-selector.ts +2 -2
  46. package/internal/src/selector/dispose-selector.ts +2 -9
  47. package/internal/src/selector/register-selector.ts +9 -9
  48. package/internal/src/set-state/set-into-store.ts +23 -33
  49. package/internal/src/store/circular-buffer.ts +34 -0
  50. package/internal/src/store/counterfeit.ts +109 -0
  51. package/internal/src/store/deposit.ts +67 -13
  52. package/internal/src/store/index.ts +1 -0
  53. package/internal/src/store/store.ts +4 -1
  54. package/internal/src/store/withdraw.ts +15 -10
  55. package/internal/src/subscribe/index.ts +2 -0
  56. package/internal/src/subscribe/subscribe-in-store.ts +62 -0
  57. package/internal/src/timeline/time-travel.ts +1 -1
  58. package/internal/src/transaction/build-transaction.ts +7 -6
  59. package/introspection/dist/index.d.ts +84 -4
  60. package/introspection/dist/index.js +1 -413
  61. package/introspection/src/attach-atom-index.ts +5 -8
  62. package/introspection/src/attach-introspection-states.ts +7 -4
  63. package/introspection/src/attach-selector-index.ts +6 -8
  64. package/introspection/src/attach-timeline-family.ts +25 -28
  65. package/introspection/src/attach-timeline-index.ts +5 -8
  66. package/introspection/src/attach-transaction-index.ts +5 -8
  67. package/introspection/src/attach-transaction-logs.ts +21 -27
  68. package/introspection/src/attach-type-selectors.ts +26 -0
  69. package/introspection/src/differ.ts +167 -0
  70. package/introspection/src/index.ts +2 -0
  71. package/introspection/src/refinery.ts +100 -0
  72. package/json/dist/index.d.ts +31 -30
  73. package/json/dist/index.js +2 -80
  74. package/json/src/entries.ts +6 -0
  75. package/json/src/index.ts +47 -6
  76. package/json/src/select-json-family.ts +4 -4
  77. package/json/src/select-json.ts +6 -9
  78. package/package.json +17 -8
  79. package/react/dist/index.js +7 -7
  80. package/react/src/parse-state-overloads.ts +2 -2
  81. package/react/src/use-i.ts +1 -1
  82. package/react/src/use-json.ts +2 -2
  83. package/react/src/use-o.ts +2 -2
  84. package/react-devtools/dist/index.d.ts +1 -91
  85. package/react-devtools/dist/index.js +285 -414
  86. package/react-devtools/src/AtomIODevtools.tsx +2 -2
  87. package/react-devtools/src/StateEditor.tsx +20 -12
  88. package/react-devtools/src/StateIndex.tsx +8 -26
  89. package/react-devtools/src/TimelineIndex.tsx +3 -3
  90. package/react-devtools/src/TransactionIndex.tsx +6 -6
  91. package/react-devtools/src/Updates.tsx +1 -4
  92. package/react-devtools/src/index.ts +0 -71
  93. package/react-devtools/src/store.ts +51 -0
  94. package/realtime/dist/index.d.ts +7 -7
  95. package/realtime/dist/index.js +18 -22
  96. package/realtime/src/realtime-continuity.ts +27 -35
  97. package/realtime-client/dist/index.js +59 -65
  98. package/realtime-client/src/pull-atom-family-member.ts +1 -1
  99. package/realtime-client/src/pull-atom.ts +1 -1
  100. package/realtime-client/src/pull-mutable-atom-family-member.ts +3 -3
  101. package/realtime-client/src/pull-mutable-atom.ts +3 -3
  102. package/realtime-client/src/realtime-client-stores/client-main-store.ts +6 -6
  103. package/realtime-client/src/sync-continuity.ts +55 -53
  104. package/realtime-react/dist/index.js +3 -3
  105. package/realtime-react/src/use-pull-atom-family-member.ts +1 -1
  106. package/realtime-react/src/use-pull-mutable-family-member.ts +1 -1
  107. package/realtime-react/src/use-pull-selector-family-member.ts +1 -1
  108. package/realtime-server/dist/index.js +72 -36
  109. package/realtime-server/src/realtime-continuity-synchronizer.ts +57 -93
  110. package/realtime-server/src/realtime-family-provider.ts +3 -3
  111. package/realtime-server/src/realtime-mutable-family-provider.ts +5 -5
  112. package/realtime-server/src/realtime-mutable-provider.ts +2 -2
  113. package/realtime-server/src/realtime-state-provider.ts +1 -1
  114. package/realtime-server/src/realtime-state-receiver.ts +1 -1
  115. package/realtime-testing/dist/index.d.ts +2 -0
  116. package/realtime-testing/dist/index.js +57 -15
  117. package/realtime-testing/src/setup-realtime-test.tsx +66 -16
  118. package/src/atom.ts +2 -2
  119. package/src/dispose-state.ts +2 -2
  120. package/src/get-state.ts +9 -13
  121. package/src/molecule.ts +1 -1
  122. package/src/selector.ts +2 -2
  123. package/src/set-state.ts +10 -7
  124. package/src/silo.ts +29 -55
  125. package/src/subscribe.ts +3 -23
  126. package/src/timeline.ts +2 -2
  127. package/web/dist/index.d.ts +9 -0
  128. package/{dist/chunk-H6EDLPKH.js → web/dist/index.js} +5 -4
  129. package/web/package.json +13 -0
  130. package/web/src/index.ts +1 -0
  131. package/web/src/persist-sync.ts +25 -0
  132. package/dist/chunk-AK23DRMD.js +0 -21
  133. package/dist/chunk-IW6WYRS7.js +0 -140
  134. package/internal/src/families/throw-in-case-of-conflicting-family.ts +0 -18
@@ -2,6 +2,7 @@ import { Junction } from './chunk-IBTHB2PI.js';
2
2
  import { stringifyJson, parseJson, selectJson, selectJsonFamily } from 'atom.io/json';
3
3
  import { AtomIOLogger } from 'atom.io';
4
4
  import { getJoin, findRelations } from 'atom.io/data';
5
+ import { subscribeToTimeline, subscribeToTransaction, subscribeToState, arbitrary as arbitrary$1 } from 'atom.io/internal';
5
6
 
6
7
  // internal/src/arbitrary.ts
7
8
  function arbitrary(random = Math.random) {
@@ -66,6 +67,37 @@ function eldest(scion) {
66
67
  }
67
68
  return scion;
68
69
  }
70
+ var FAMILY_MEMBER_TOKEN_TYPES = {
71
+ atom_family: `atom`,
72
+ mutable_atom_family: `mutable_atom`,
73
+ selector_family: `selector`,
74
+ readonly_selector_family: `readonly_selector`,
75
+ molecule_family: `molecule`
76
+ };
77
+ function counterfeit(token, key) {
78
+ const subKey = stringifyJson(key);
79
+ const fullKey = `${token.key}(${subKey})`;
80
+ const type = FAMILY_MEMBER_TOKEN_TYPES[token.type];
81
+ const stateToken = {
82
+ key: fullKey,
83
+ type
84
+ };
85
+ if (type === `molecule`) {
86
+ Object.assign(stateToken, {
87
+ key,
88
+ family: token
89
+ });
90
+ } else {
91
+ Object.assign(stateToken, {
92
+ family: {
93
+ key: token.key,
94
+ subKey
95
+ }
96
+ });
97
+ }
98
+ Object.assign(stateToken, { counterfeit: true });
99
+ return stateToken;
100
+ }
69
101
 
70
102
  // internal/src/store/deposit.ts
71
103
  function deposit(state) {
@@ -144,22 +176,7 @@ var abortTransaction = (store) => {
144
176
  // internal/src/pretty-print.ts
145
177
  var capitalize = (str) => str[0].toUpperCase() + str.slice(1);
146
178
  function prettyPrintTokenType(token) {
147
- switch (token.type) {
148
- case `atom_family`:
149
- return `Atom Family`;
150
- case `molecule_family`:
151
- return `Molecule Family`;
152
- case `mutable_atom_family`:
153
- return `Mutable Atom Family`;
154
- case `readonly_selector`:
155
- return `Readonly Selector`;
156
- case `readonly_selector_family`:
157
- return `Readonly Selector Family`;
158
- case `selector_family`:
159
- return `Selector Family`;
160
- default:
161
- return capitalize(token.type);
162
- }
179
+ return token.type.split(`_`).map(capitalize).join(` `);
163
180
  }
164
181
 
165
182
  // internal/src/not-found-error.ts
@@ -437,26 +454,22 @@ var setAtomOrSelector = (state, value, store) => {
437
454
  break;
438
455
  }
439
456
  };
440
-
441
- // internal/src/families/throw-in-case-of-conflicting-family.ts
442
- function throwInCaseOfConflictingFamily(family, store) {
443
- const existingFamily = store.families.get(family.key);
444
- if (existingFamily) {
445
- throw new Error(
446
- `Tried to create ${family.type === `atom_family` ? `an` : `a`} ${prettyPrintTokenType(family)} with key "${family.key}", but "${family.key}" already exists in store "${store.config.name}" as ${existingFamily.type === `atom_family` ? `an` : `a`} ${prettyPrintTokenType(
447
- existingFamily
448
- )}`
449
- );
450
- }
451
- }
452
-
453
- // internal/src/families/create-regular-atom-family.ts
454
- function createRegularAtomFamily(options, store, internalRoles) {
457
+ function createRegularAtomFamily(store, options, internalRoles) {
455
458
  const familyToken = {
456
459
  key: options.key,
457
460
  type: `atom_family`
458
461
  };
459
- throwInCaseOfConflictingFamily(familyToken, store);
462
+ const existing = store.families.get(options.key);
463
+ if (existing) {
464
+ store.logger.error(
465
+ `\u2757`,
466
+ `atom_family`,
467
+ options.key,
468
+ `Overwriting an existing ${prettyPrintTokenType(
469
+ existing
470
+ )} "${existing.key}" in store "${store.config.name}". You can safely ignore this warning if it is due to hot module replacement.`
471
+ );
472
+ }
460
473
  const subject = new Subject();
461
474
  const familyFunction = (key) => {
462
475
  const subKey = stringifyJson(key);
@@ -471,13 +484,13 @@ function createRegularAtomFamily(options, store, internalRoles) {
471
484
  if (options.effects) {
472
485
  individualOptions.effects = options.effects(key);
473
486
  }
474
- const token = createRegularAtom(individualOptions, family, target);
487
+ const token = createRegularAtom(target, individualOptions, family);
475
488
  subject.next({ type: `state_creation`, token });
476
489
  return token;
477
490
  };
478
491
  const atomFamily = Object.assign(familyFunction, familyToken, {
479
492
  subject,
480
- install: (s) => createRegularAtomFamily(options, s),
493
+ install: (s) => createRegularAtomFamily(s, options),
481
494
  internalRoles
482
495
  });
483
496
  store.families.set(options.key, atomFamily);
@@ -486,52 +499,63 @@ function createRegularAtomFamily(options, store, internalRoles) {
486
499
  }
487
500
 
488
501
  // internal/src/families/create-atom-family.ts
489
- function createAtomFamily(options, store) {
502
+ function createAtomFamily(store, options) {
490
503
  const isMutable = `mutable` in options;
491
504
  if (isMutable) {
492
- return createMutableAtomFamily(options, store);
505
+ return createMutableAtomFamily(store, options);
493
506
  }
494
- return createRegularAtomFamily(options, store);
507
+ return createRegularAtomFamily(store, options);
495
508
  }
496
- function getFromStore(...params) {
509
+
510
+ // internal/src/get-state/get-from-store.ts
511
+ function getFromStore(store, ...params) {
497
512
  let token;
498
- let store;
499
- if (params.length === 2) {
513
+ if (params.length === 1) {
500
514
  token = params[0];
501
- store = params[1];
502
515
  } else {
503
516
  const family = params[0];
504
517
  const key = params[1];
505
- store = params[2];
506
- const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
507
- if (!maybeToken) {
508
- store.logger.error(
509
- `\u2757`,
510
- family.type,
511
- family.key,
512
- `tried to get member`,
513
- stringifyJson(key),
514
- `but it was not found in store`,
515
- store.config.name
516
- );
517
- switch (family.type) {
518
- case `atom_family`:
519
- case `mutable_atom_family`:
520
- return store.defaults.get(family.key);
521
- case `selector_family`:
522
- case `readonly_selector_family`: {
523
- if (store.defaults.has(family.key)) {
524
- return store.defaults.get(family.key);
525
- }
526
- const defaultValue = withdraw(family, store).default(key);
527
- store.defaults.set(family.key, defaultValue);
528
- return defaultValue;
518
+ let maybeToken;
519
+ if (family.type === `molecule_family`) {
520
+ maybeToken = seekInStore(store, family, key) ?? counterfeit(family, key);
521
+ } else {
522
+ maybeToken = findInStore(store, family, key);
523
+ }
524
+ token = maybeToken;
525
+ }
526
+ if (`counterfeit` in token && `family` in token) {
527
+ const family = token.type === `molecule` ? withdraw(token.family, store) : (
528
+ // biome-ignore lint/style/noNonNullAssertion: family must be present
529
+ store.families.get(token.family.key)
530
+ );
531
+ const subKey = token.type === `molecule` ? token.key : token.family.subKey;
532
+ const disposal = store.disposalTraces.buffer.find(
533
+ (item) => item?.key === token.key
534
+ );
535
+ store.logger.error(
536
+ `\u274C`,
537
+ token.type,
538
+ token.key,
539
+ `could not be retrieved because it was not found in the store "${store.config.name}".`,
540
+ disposal ? `This state was previously disposed:
541
+ ${disposal.trace}` : `No previous disposal trace was found.`
542
+ );
543
+ switch (family.type) {
544
+ case `atom_family`:
545
+ case `mutable_atom_family`:
546
+ return store.defaults.get(family.key);
547
+ case `selector_family`:
548
+ case `readonly_selector_family`: {
549
+ if (store.defaults.has(family.key)) {
550
+ return store.defaults.get(token.family.key);
529
551
  }
530
- case `molecule_family`:
531
- throw new NotFoundError(family, key, store);
552
+ const defaultValue = withdraw(family, store).default(subKey);
553
+ store.defaults.set(family.key, defaultValue);
554
+ return defaultValue;
532
555
  }
556
+ case `molecule_family`:
557
+ throw new NotFoundError(family, subKey, store);
533
558
  }
534
- token = maybeToken;
535
559
  }
536
560
  switch (token.type) {
537
561
  case `atom`:
@@ -629,12 +653,12 @@ var registerSelector = (selectorKey, covered, store) => ({
629
653
  const [family, key] = params;
630
654
  switch (family.type) {
631
655
  case `molecule_family`:
632
- return getFromStore(family, key, store);
656
+ return getFromStore(store, family, key);
633
657
  default:
634
658
  if (store.config.lifespan === `ephemeral`) {
635
- dependency = findInStore(family, key, store);
659
+ dependency = findInStore(store, family, key);
636
660
  } else {
637
- const maybeDependency = seekInStore(family, key, store);
661
+ const maybeDependency = seekInStore(store, family, key);
638
662
  if (maybeDependency) {
639
663
  dependency = maybeDependency;
640
664
  } else {
@@ -646,7 +670,7 @@ var registerSelector = (selectorKey, covered, store) => ({
646
670
  [dependency] = params;
647
671
  }
648
672
  if (dependency.type === `molecule`) {
649
- return getFromStore(dependency, store);
673
+ return getFromStore(store, dependency);
650
674
  }
651
675
  const dependencyState = withdraw(dependency, store);
652
676
  const dependencyValue = readOrComputeValue(dependencyState, store);
@@ -680,7 +704,7 @@ var registerSelector = (selectorKey, covered, store) => ({
680
704
  const family = params[0];
681
705
  const key = params[1];
682
706
  value = params[2];
683
- const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
707
+ const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(store, family, key) : seekInStore(store, family, key);
684
708
  if (!maybeToken) {
685
709
  throw new NotFoundError(family, key, store);
686
710
  }
@@ -690,13 +714,13 @@ var registerSelector = (selectorKey, covered, store) => ({
690
714
  const state = withdraw(token, target);
691
715
  setAtomOrSelector(state, value, target);
692
716
  },
693
- find: (token, key) => findInStore(token, key, store),
694
- seek: (token, key) => seekInStore(token, key, store),
695
- json: (token) => getJsonToken(token, store)
717
+ find: (token, key) => findInStore(store, token, key),
718
+ seek: (token, key) => seekInStore(store, token, key),
719
+ json: (token) => getJsonToken(store, token)
696
720
  });
697
721
 
698
722
  // internal/src/selector/create-readonly-selector.ts
699
- var createReadonlySelector = (options, family, store) => {
723
+ var createReadonlySelector = (store, options, family) => {
700
724
  const target = newest(store);
701
725
  const subject = new Subject();
702
726
  const covered = /* @__PURE__ */ new Set();
@@ -714,7 +738,7 @@ var createReadonlySelector = (options, family, store) => {
714
738
  const readonlySelector = {
715
739
  ...options,
716
740
  subject,
717
- install: (s) => createReadonlySelector(options, family, s),
741
+ install: (s) => createReadonlySelector(s, options, family),
718
742
  get: getSelf,
719
743
  type: `readonly_selector`,
720
744
  ...family && { family }
@@ -739,7 +763,7 @@ var createReadonlySelector = (options, family, store) => {
739
763
  };
740
764
 
741
765
  // internal/src/selector/create-writable-selector.ts
742
- var createWritableSelector = (options, family, store) => {
766
+ var createWritableSelector = (store, options, family) => {
743
767
  const target = newest(store);
744
768
  const subject = new Subject();
745
769
  const covered = /* @__PURE__ */ new Set();
@@ -776,7 +800,7 @@ var createWritableSelector = (options, family, store) => {
776
800
  const mySelector = {
777
801
  ...options,
778
802
  subject,
779
- install: (s) => createWritableSelector(options, family, s),
803
+ install: (s) => createWritableSelector(s, options, family),
780
804
  get: getSelf,
781
805
  set: setSelf,
782
806
  type: `selector`,
@@ -796,14 +820,14 @@ var createWritableSelector = (options, family, store) => {
796
820
  };
797
821
 
798
822
  // internal/src/selector/create-standalone-selector.ts
799
- function createStandaloneSelector(options, store) {
823
+ function createStandaloneSelector(store, options) {
800
824
  const isWritable = `set` in options;
801
825
  if (isWritable) {
802
- const state2 = createWritableSelector(options, void 0, store);
826
+ const state2 = createWritableSelector(store, options, void 0);
803
827
  store.on.selectorCreation.next(state2);
804
828
  return state2;
805
829
  }
806
- const state = createReadonlySelector(options, void 0, store);
830
+ const state = createReadonlySelector(store, options, void 0);
807
831
  store.on.selectorCreation.next(state);
808
832
  return state;
809
833
  }
@@ -812,15 +836,8 @@ function createStandaloneSelector(options, store) {
812
836
  function disposeSelector(selectorToken, store) {
813
837
  const target = newest(store);
814
838
  const { key } = selectorToken;
815
- const selector = target.selectors.get(key) ?? target.readonlySelectors.get(key);
816
- if (!selector) {
817
- store.logger.info(
818
- `\u274C`,
819
- `selector`,
820
- key,
821
- `Tried to dispose selector, but it does not exist in the store.`
822
- );
823
- } else if (!selector.family) {
839
+ const selector = withdraw(selectorToken, target);
840
+ if (!selector.family) {
824
841
  store.logger.error(
825
842
  `\u274C`,
826
843
  `selector`,
@@ -884,12 +901,22 @@ function disposeSelector(selectorToken, store) {
884
901
  }
885
902
 
886
903
  // internal/src/families/create-readonly-selector-family.ts
887
- function createReadonlySelectorFamily(options, store, internalRoles) {
904
+ function createReadonlySelectorFamily(store, options, internalRoles) {
888
905
  const familyToken = {
889
906
  key: options.key,
890
907
  type: `readonly_selector_family`
891
908
  };
892
- throwInCaseOfConflictingFamily(familyToken, store);
909
+ const existing = store.families.get(options.key);
910
+ if (existing) {
911
+ store.logger.error(
912
+ `\u2757`,
913
+ `readonly_selector_family`,
914
+ options.key,
915
+ `Overwriting an existing ${prettyPrintTokenType(
916
+ existing
917
+ )} "${existing.key}" in store "${store.config.name}". You can safely ignore this warning if it is due to hot module replacement.`
918
+ );
919
+ }
893
920
  const subject = new Subject();
894
921
  const familyFunction = (key) => {
895
922
  const subKey = stringifyJson(key);
@@ -897,12 +924,12 @@ function createReadonlySelectorFamily(options, store, internalRoles) {
897
924
  const fullKey = `${options.key}(${subKey})`;
898
925
  const target = newest(store);
899
926
  const token = createReadonlySelector(
927
+ target,
900
928
  {
901
929
  key: fullKey,
902
930
  get: options.get(key)
903
931
  },
904
- family,
905
- target
932
+ family
906
933
  );
907
934
  subject.next({ type: `state_creation`, token });
908
935
  return token;
@@ -910,26 +937,36 @@ function createReadonlySelectorFamily(options, store, internalRoles) {
910
937
  const readonlySelectorFamily = Object.assign(familyFunction, familyToken, {
911
938
  internalRoles,
912
939
  subject,
913
- install: (s) => createReadonlySelectorFamily(options, s),
940
+ install: (s) => createReadonlySelectorFamily(s, options),
914
941
  default: (key) => {
915
942
  const getFn = options.get(key);
916
943
  return getFn({
917
- get: (token) => getFromStore(token, store),
918
- find: (token, k) => findInStore(token, k, store),
919
- seek: (token, k) => seekInStore(token, k, store),
920
- json: (token) => getJsonToken(token, store)
944
+ get: (...ps) => getFromStore(store, ...ps),
945
+ find: (token, k) => findInStore(store, token, k),
946
+ seek: (token, k) => seekInStore(store, token, k),
947
+ json: (token) => getJsonToken(store, token)
921
948
  });
922
949
  }
923
950
  });
924
951
  store.families.set(options.key, readonlySelectorFamily);
925
952
  return familyToken;
926
953
  }
927
- function createWritableSelectorFamily(options, store, internalRoles) {
954
+ function createWritableSelectorFamily(store, options, internalRoles) {
928
955
  const familyToken = {
929
956
  key: options.key,
930
957
  type: `selector_family`
931
958
  };
932
- throwInCaseOfConflictingFamily(familyToken, store);
959
+ const existing = store.families.get(options.key);
960
+ if (existing) {
961
+ store.logger.error(
962
+ `\u2757`,
963
+ `selector_family`,
964
+ options.key,
965
+ `Overwriting an existing ${prettyPrintTokenType(
966
+ existing
967
+ )} "${existing.key}" in store "${store.config.name}". You can safely ignore this warning if it is due to hot module replacement.`
968
+ );
969
+ }
933
970
  const subject = new Subject();
934
971
  const familyFunction = (key) => {
935
972
  const subKey = stringifyJson(key);
@@ -937,13 +974,13 @@ function createWritableSelectorFamily(options, store, internalRoles) {
937
974
  const fullKey = `${options.key}(${subKey})`;
938
975
  const target = newest(store);
939
976
  const token = createWritableSelector(
977
+ target,
940
978
  {
941
979
  key: fullKey,
942
980
  get: options.get(key),
943
981
  set: options.set(key)
944
982
  },
945
- family,
946
- target
983
+ family
947
984
  );
948
985
  subject.next({ type: `state_creation`, token });
949
986
  return token;
@@ -951,15 +988,14 @@ function createWritableSelectorFamily(options, store, internalRoles) {
951
988
  const selectorFamily = Object.assign(familyFunction, familyToken, {
952
989
  internalRoles,
953
990
  subject,
954
- install: (s) => createWritableSelectorFamily(options, s),
991
+ install: (s) => createWritableSelectorFamily(s, options),
955
992
  default: (key) => {
956
993
  const getFn = options.get(key);
957
994
  return getFn({
958
- get: (...params) => getFromStore(...params, store),
959
- // TODO: make store zero-arg
960
- find: (token, k) => findInStore(token, k, store),
961
- seek: (token, k) => seekInStore(token, k, store),
962
- json: (token) => getJsonToken(token, store)
995
+ get: (...ps) => getFromStore(store, ...ps),
996
+ find: (token, k) => findInStore(store, token, k),
997
+ seek: (token, k) => seekInStore(store, token, k),
998
+ json: (token) => getJsonToken(store, token)
963
999
  });
964
1000
  }
965
1001
  });
@@ -968,32 +1004,23 @@ function createWritableSelectorFamily(options, store, internalRoles) {
968
1004
  }
969
1005
 
970
1006
  // internal/src/families/create-selector-family.ts
971
- function createSelectorFamily(options, store) {
1007
+ function createSelectorFamily(store, options) {
972
1008
  const isWritable = `set` in options;
973
1009
  if (isWritable) {
974
- return createWritableSelectorFamily(options, store);
1010
+ return createWritableSelectorFamily(store, options);
975
1011
  }
976
- return createReadonlySelectorFamily(options, store);
1012
+ return createReadonlySelectorFamily(store, options);
977
1013
  }
978
1014
 
979
1015
  // internal/src/molecule/dispose-molecule.ts
980
1016
  function disposeMolecule(token, store) {
981
1017
  let molecule;
982
- try {
983
- molecule = withdraw(token, store);
984
- } catch (thrown) {
985
- if (thrown instanceof Error) {
986
- store.logger.error(
987
- `\u{1F41E}`,
988
- `molecule`,
989
- JSON.stringify(token.key),
990
- `Failed to dispose molecule, because it was not found in the store.`,
991
- thrown.message
992
- );
993
- }
994
- return;
995
- }
1018
+ molecule = withdraw(token, store);
996
1019
  const { family } = token;
1020
+ for (const join of molecule.joins.values()) {
1021
+ join.relations.delete(molecule.key);
1022
+ join.molecules.delete(molecule.stringKey);
1023
+ }
997
1024
  const context = [];
998
1025
  for (const above of molecule.above.values()) {
999
1026
  context.push(deposit(above));
@@ -1016,7 +1043,7 @@ function disposeMolecule(token, store) {
1016
1043
  disposalEvent.family = token.family;
1017
1044
  }
1018
1045
  for (const state of molecule.tokens.values()) {
1019
- disposeFromStore(state, store);
1046
+ disposeFromStore(store, state);
1020
1047
  }
1021
1048
  for (const child of molecule.below.values()) {
1022
1049
  if (child.family?.dependsOn === `all`) {
@@ -1037,191 +1064,13 @@ function disposeMolecule(token, store) {
1037
1064
  }
1038
1065
  store.molecules.delete(molecule.stringKey);
1039
1066
  }
1040
- for (const join of molecule.joins.values()) {
1041
- join.molecules.delete(molecule.stringKey);
1042
- }
1043
1067
  for (const parent of molecule.above.values()) {
1044
1068
  parent.below.delete(molecule.stringKey);
1045
1069
  }
1046
1070
  }
1047
1071
 
1048
- // internal/src/families/init-family-member.ts
1049
- function initFamilyMemberInStore(token, key, store) {
1050
- const familyKey = token.key;
1051
- const family = store.families.get(familyKey);
1052
- if (family === void 0) {
1053
- throw new NotFoundError(token, store);
1054
- }
1055
- const state = family(key);
1056
- const target = newest(store);
1057
- if (state.family && target.moleculeInProgress === null) {
1058
- if (isRootStore(target)) {
1059
- switch (state.type) {
1060
- case `atom`:
1061
- case `mutable_atom`:
1062
- store.on.atomCreation.next(state);
1063
- break;
1064
- case `selector`:
1065
- case `readonly_selector`:
1066
- store.on.selectorCreation.next(state);
1067
- break;
1068
- }
1069
- } else if (isChildStore(target) && target.on.transactionApplying.state === null) {
1070
- target.transactionMeta.update.updates.push({
1071
- type: `state_creation`,
1072
- token: state
1073
- });
1074
- }
1075
- }
1076
- return state;
1077
- }
1078
- function seekInStore(token, key, store) {
1079
- const subKey = stringifyJson(key);
1080
- const fullKey = `${token.key}(${subKey})`;
1081
- const target = newest(store);
1082
- let state;
1083
- switch (token.type) {
1084
- case `atom_family`:
1085
- case `mutable_atom_family`:
1086
- state = target.atoms.get(fullKey);
1087
- break;
1088
- case `selector_family`:
1089
- state = target.selectors.get(fullKey);
1090
- break;
1091
- case `readonly_selector_family`:
1092
- state = target.readonlySelectors.get(fullKey);
1093
- break;
1094
- case `molecule_family`:
1095
- state = target.molecules.get(stringifyJson(key));
1096
- }
1097
- if (state) {
1098
- return deposit(state);
1099
- }
1100
- return state;
1101
- }
1102
-
1103
- // internal/src/families/find-in-store.ts
1104
- function findInStore(token, key, store) {
1105
- if (store.config.lifespan === `immortal`) {
1106
- throw new Error(
1107
- `Do not use \`find\` or \`findState\` in an immortal store. Prefer \`seek\` or \`seekState\`.`
1108
- );
1109
- }
1110
- let state = seekInStore(token, key, store);
1111
- if (state) {
1112
- return state;
1113
- }
1114
- state = initFamilyMemberInStore(token, key, store);
1115
- return state;
1116
- }
1117
-
1118
- // internal/src/families/dispose-from-store.ts
1119
- function disposeFromStore(...params) {
1120
- let token;
1121
- let store;
1122
- if (params.length === 2) {
1123
- token = params[0];
1124
- store = params[1];
1125
- } else {
1126
- const family = params[0];
1127
- const key = params[1];
1128
- store = params[2];
1129
- const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
1130
- if (!maybeToken) {
1131
- store.logger.error(
1132
- `\u2757`,
1133
- family.type,
1134
- family.key,
1135
- `tried to dispose of member`,
1136
- stringifyJson(key),
1137
- `but it was not found in store`,
1138
- store.config.name
1139
- );
1140
- return;
1141
- }
1142
- token = maybeToken;
1143
- }
1144
- switch (token.type) {
1145
- case `atom`:
1146
- case `mutable_atom`:
1147
- disposeAtom(token, store);
1148
- break;
1149
- case `selector`:
1150
- case `readonly_selector`:
1151
- disposeSelector(token, store);
1152
- break;
1153
- case `molecule`:
1154
- disposeMolecule(token, store);
1155
- break;
1156
- }
1157
- }
1158
-
1159
- // internal/src/set-state/set-into-store.ts
1160
- function setIntoStore(...params) {
1161
- let token;
1162
- let value;
1163
- let store;
1164
- if (params.length === 3) {
1165
- token = params[0];
1166
- value = params[1];
1167
- store = params[2];
1168
- } else {
1169
- const family = params[0];
1170
- const key = params[1];
1171
- value = params[2];
1172
- store = params[3];
1173
- const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
1174
- if (!maybeToken) {
1175
- store.logger.error(
1176
- `\u2757`,
1177
- family.type,
1178
- family.key,
1179
- `tried to set member`,
1180
- stringifyJson(key),
1181
- `to`,
1182
- value,
1183
- `but it was not found in store`,
1184
- store.config.name
1185
- );
1186
- return;
1187
- }
1188
- token = maybeToken;
1189
- }
1190
- const rejectionTime = openOperation(token, store);
1191
- if (rejectionTime) {
1192
- const unsubscribe = store.on.operationClose.subscribe(
1193
- `waiting to set "${token.key}" at T-${rejectionTime}`,
1194
- () => {
1195
- unsubscribe();
1196
- store.logger.info(
1197
- `\u{1F7E2}`,
1198
- token.type,
1199
- token.key,
1200
- `resuming deferred setState from T-${rejectionTime}`
1201
- );
1202
- setIntoStore(token, value, store);
1203
- }
1204
- );
1205
- return;
1206
- }
1207
- const state = withdraw(token, store);
1208
- setAtomOrSelector(state, value, store);
1209
- closeOperation(store);
1210
- }
1211
-
1212
- // internal/src/ingest-updates/ingest-atom-update.ts
1213
- function ingestAtomUpdate(applying, atomUpdate, store) {
1214
- const { key, newValue, oldValue } = atomUpdate;
1215
- const value = applying === `newValue` ? newValue : oldValue;
1216
- const token = { key, type: `atom` };
1217
- if (atomUpdate.family) {
1218
- Object.assign(token, { family: atomUpdate.family });
1219
- }
1220
- setIntoStore(token, value, store);
1221
- }
1222
-
1223
1072
  // internal/src/molecule/create-molecule-family.ts
1224
- function createMoleculeFamily(options, store) {
1073
+ function createMoleculeFamily(store, options) {
1225
1074
  const subject = new Subject();
1226
1075
  const token = {
1227
1076
  type: `molecule_family`,
@@ -1239,7 +1088,7 @@ function createMoleculeFamily(options, store) {
1239
1088
 
1240
1089
  // internal/src/molecule/grow-molecule-in-store.ts
1241
1090
  function growMoleculeInStore(molecule, family, store) {
1242
- const stateToken = initFamilyMemberInStore(family, molecule.key, store);
1091
+ const stateToken = initFamilyMemberInStore(store, family, molecule.key);
1243
1092
  molecule.tokens.set(stateToken.key, stateToken);
1244
1093
  const isTransaction = isChildStore(store) && store.transactionMeta.phase === `building`;
1245
1094
  const moleculeInProgress = store.moleculeInProgress === molecule.key;
@@ -1312,16 +1161,16 @@ function makeMoleculeInStore(store, context, familyToken, key, ...params) {
1312
1161
  owner.below.set(molecule.stringKey, molecule);
1313
1162
  }
1314
1163
  const toolkit = {
1315
- get: (...ps) => getFromStore(...ps, newest(rootStore)),
1164
+ get: (...ps) => getFromStore(newest(rootStore), ...ps),
1316
1165
  set: (...ps) => {
1317
- setIntoStore(...ps, newest(rootStore));
1166
+ setIntoStore(newest(rootStore), ...ps);
1318
1167
  },
1319
- seek: (t, k) => seekInStore(t, k, newest(rootStore)),
1320
- json: (t) => getJsonToken(t, newest(rootStore)),
1168
+ seek: (t, k) => seekInStore(newest(rootStore), t, k),
1169
+ json: (t) => getJsonToken(newest(rootStore), t),
1321
1170
  run: (t, i = arbitrary()) => actUponStore(t, i, newest(store)),
1322
1171
  make: (ctx, f, k, ...args) => makeMoleculeInStore(newest(rootStore), ctx, f, k, ...args),
1323
1172
  dispose: (t) => {
1324
- disposeFromStore(t, newest(rootStore));
1173
+ disposeFromStore(newest(rootStore), t);
1325
1174
  },
1326
1175
  env: () => getEnvironmentData(newest(rootStore)),
1327
1176
  bond: (token2, maybeRole) => {
@@ -1407,7 +1256,202 @@ function makeMoleculeInStore(store, context, familyToken, key, ...params) {
1407
1256
  return token;
1408
1257
  }
1409
1258
 
1410
- // internal/src/ingest-updates/ingest-creation-disposal.ts
1259
+ // internal/src/families/init-family-member.ts
1260
+ function initFamilyMemberInStore(store, token, key) {
1261
+ const familyKey = token.key;
1262
+ const family = store.families.get(familyKey);
1263
+ if (family === void 0) {
1264
+ throw new NotFoundError(token, store);
1265
+ }
1266
+ const state = family(key);
1267
+ const target = newest(store);
1268
+ if (state.family && target.moleculeInProgress === null) {
1269
+ if (isRootStore(target)) {
1270
+ switch (state.type) {
1271
+ case `atom`:
1272
+ case `mutable_atom`:
1273
+ store.on.atomCreation.next(state);
1274
+ break;
1275
+ case `selector`:
1276
+ case `readonly_selector`:
1277
+ store.on.selectorCreation.next(state);
1278
+ break;
1279
+ }
1280
+ } else if (isChildStore(target) && target.on.transactionApplying.state === null) {
1281
+ target.transactionMeta.update.updates.push({
1282
+ type: `state_creation`,
1283
+ token: state
1284
+ });
1285
+ }
1286
+ }
1287
+ return state;
1288
+ }
1289
+ function seekInStore(store, token, key) {
1290
+ const subKey = stringifyJson(key);
1291
+ const fullKey = `${token.key}(${subKey})`;
1292
+ const target = newest(store);
1293
+ let state;
1294
+ switch (token.type) {
1295
+ case `atom_family`:
1296
+ case `mutable_atom_family`:
1297
+ state = target.atoms.get(fullKey);
1298
+ break;
1299
+ case `selector_family`:
1300
+ state = target.selectors.get(fullKey);
1301
+ break;
1302
+ case `readonly_selector_family`:
1303
+ state = target.readonlySelectors.get(fullKey);
1304
+ break;
1305
+ case `molecule_family`:
1306
+ state = target.molecules.get(stringifyJson(key));
1307
+ }
1308
+ if (state) {
1309
+ return deposit(state);
1310
+ }
1311
+ return state;
1312
+ }
1313
+
1314
+ // internal/src/families/find-in-store.ts
1315
+ function findInStore(store, token, key) {
1316
+ let state = seekInStore(store, token, key);
1317
+ if (state) {
1318
+ return state;
1319
+ }
1320
+ const molecule = store.molecules.get(stringifyJson(key));
1321
+ if (molecule) {
1322
+ return growMoleculeInStore(molecule, token, store);
1323
+ }
1324
+ if (store.config.lifespan === `immortal`) {
1325
+ const fakeToken = counterfeit(token, key);
1326
+ store.logger.error(
1327
+ `\u274C`,
1328
+ fakeToken.type,
1329
+ fakeToken.key,
1330
+ `was not found in store "${store.config.name}"; returned a counterfeit token.`
1331
+ );
1332
+ return fakeToken;
1333
+ }
1334
+ state = initFamilyMemberInStore(store, token, key);
1335
+ return state;
1336
+ }
1337
+
1338
+ // internal/src/families/dispose-from-store.ts
1339
+ function disposeFromStore(store, ...params) {
1340
+ let token;
1341
+ if (params.length === 1) {
1342
+ token = params[0];
1343
+ token.key;
1344
+ } else {
1345
+ const family = params[0];
1346
+ const key = params[1];
1347
+ const maybeToken = family.type === `molecule_family` ? seekInStore(store, family, key) ?? counterfeit(family, key) : findInStore(store, family, key);
1348
+ token = maybeToken;
1349
+ }
1350
+ try {
1351
+ withdraw(token, store);
1352
+ } catch (thrown) {
1353
+ const disposal = store.disposalTraces.buffer.find(
1354
+ (item) => item?.key === token.key
1355
+ );
1356
+ console.log(
1357
+ `seeking disposal trace for`,
1358
+ token,
1359
+ store.disposalTraces.buffer.filter(Boolean)
1360
+ );
1361
+ store.logger.error(
1362
+ `\u274C`,
1363
+ token.type,
1364
+ token.key,
1365
+ `could not be disposed because it was not found in the store "${store.config.name}".`,
1366
+ disposal ? `
1367
+ This state was most recently disposed
1368
+ ${disposal.trace}` : `No previous disposal trace was found.`
1369
+ );
1370
+ return;
1371
+ }
1372
+ switch (token.type) {
1373
+ case `atom`:
1374
+ case `mutable_atom`:
1375
+ disposeAtom(token, store);
1376
+ break;
1377
+ case `selector`:
1378
+ case `readonly_selector`:
1379
+ disposeSelector(token, store);
1380
+ break;
1381
+ case `molecule`:
1382
+ disposeMolecule(token, store);
1383
+ break;
1384
+ }
1385
+ const { stack } = new Error();
1386
+ if (stack) {
1387
+ const trace = stack?.split(`
1388
+ `)?.slice(3)?.join(`
1389
+ `);
1390
+ store.disposalTraces.add({ key: token.key, trace });
1391
+ console.log(`added`, token);
1392
+ }
1393
+ }
1394
+
1395
+ // internal/src/set-state/set-into-store.ts
1396
+ function setIntoStore(store, ...params) {
1397
+ let token;
1398
+ let value;
1399
+ if (params.length === 2) {
1400
+ token = params[0];
1401
+ value = params[1];
1402
+ } else {
1403
+ const family = params[0];
1404
+ const key = params[1];
1405
+ value = params[2];
1406
+ const maybeToken = findInStore(store, family, key);
1407
+ token = maybeToken;
1408
+ }
1409
+ if (`counterfeit` in token) {
1410
+ const disposal = store.disposalTraces.buffer.find(
1411
+ (item) => item?.key === token.key
1412
+ );
1413
+ store.logger.error(
1414
+ `\u274C`,
1415
+ token.type,
1416
+ token.key,
1417
+ `could not be set because it was not found in the store "${store.config.name}".`,
1418
+ disposal ? `This state was previously disposed:
1419
+ ${disposal.trace}` : `No previous disposal trace was found.`
1420
+ );
1421
+ return;
1422
+ }
1423
+ const rejectionTime = openOperation(token, store);
1424
+ if (rejectionTime) {
1425
+ const unsubscribe = store.on.operationClose.subscribe(
1426
+ `waiting to set "${token.key}" at T-${rejectionTime}`,
1427
+ () => {
1428
+ unsubscribe();
1429
+ store.logger.info(
1430
+ `\u{1F7E2}`,
1431
+ token.type,
1432
+ token.key,
1433
+ `resuming deferred setState from T-${rejectionTime}`
1434
+ );
1435
+ setIntoStore(store, token, value);
1436
+ }
1437
+ );
1438
+ return;
1439
+ }
1440
+ const state = withdraw(token, store);
1441
+ setAtomOrSelector(state, value, store);
1442
+ closeOperation(store);
1443
+ }
1444
+
1445
+ // internal/src/ingest-updates/ingest-atom-update.ts
1446
+ function ingestAtomUpdate(applying, atomUpdate, store) {
1447
+ const { key, newValue, oldValue } = atomUpdate;
1448
+ const value = applying === `newValue` ? newValue : oldValue;
1449
+ const token = { key, type: `atom` };
1450
+ if (atomUpdate.family) {
1451
+ Object.assign(token, { family: atomUpdate.family });
1452
+ }
1453
+ setIntoStore(store, token, value);
1454
+ }
1411
1455
  function ingestCreationEvent(update, applying, store) {
1412
1456
  switch (applying) {
1413
1457
  case `newValue`: {
@@ -1415,7 +1459,7 @@ function ingestCreationEvent(update, applying, store) {
1415
1459
  break;
1416
1460
  }
1417
1461
  case `oldValue`: {
1418
- disposeFromStore(update.token, store);
1462
+ disposeFromStore(store, update.token);
1419
1463
  break;
1420
1464
  }
1421
1465
  }
@@ -1423,7 +1467,7 @@ function ingestCreationEvent(update, applying, store) {
1423
1467
  function ingestDisposalEvent(update, applying, store) {
1424
1468
  switch (applying) {
1425
1469
  case `newValue`: {
1426
- disposeFromStore(update.token, store);
1470
+ disposeFromStore(store, update.token);
1427
1471
  break;
1428
1472
  }
1429
1473
  case `oldValue`: {
@@ -1443,9 +1487,18 @@ function createInStore(token, store) {
1443
1487
  return;
1444
1488
  }
1445
1489
  if (store.config.lifespan === `immortal`) {
1446
- throw new Error(`No molecule found for key "${token.family.subKey}"`);
1490
+ store.logger.error(
1491
+ `\u{1F41E}`,
1492
+ `atom`,
1493
+ token.family.key,
1494
+ `tried to create member`,
1495
+ `"${token.family.subKey}"`,
1496
+ `but a molecule with that key was not found in store`,
1497
+ `"${store.config.name}"`
1498
+ );
1499
+ return;
1447
1500
  }
1448
- initFamilyMemberInStore(family, parseJson(token.family.subKey), store);
1501
+ initFamilyMemberInStore(store, family, parseJson(token.family.subKey));
1449
1502
  }
1450
1503
  }
1451
1504
  }
@@ -1461,14 +1514,14 @@ function ingestMoleculeCreationEvent(update, applying, store) {
1461
1514
  );
1462
1515
  break;
1463
1516
  case `oldValue`:
1464
- disposeFromStore(update.token, store);
1517
+ disposeFromStore(store, update.token);
1465
1518
  break;
1466
1519
  }
1467
1520
  }
1468
1521
  function ingestMoleculeDisposalEvent(update, applying, store) {
1469
1522
  switch (applying) {
1470
1523
  case `newValue`:
1471
- disposeFromStore(update.token, store);
1524
+ disposeFromStore(store, update.token);
1472
1525
  break;
1473
1526
  case `oldValue`:
1474
1527
  {
@@ -1669,6 +1722,7 @@ var buildTransaction = (key, params, store, id) => {
1669
1722
  selectors: new LazyMap(parent.selectors),
1670
1723
  valueMap: new LazyMap(parent.valueMap),
1671
1724
  defaults: parent.defaults,
1725
+ disposalTraces: store.disposalTraces.copy(),
1672
1726
  molecules: new LazyMap(parent.molecules),
1673
1727
  moleculeFamilies: new LazyMap(parent.moleculeFamilies),
1674
1728
  moleculeInProgress: parent.moleculeInProgress,
@@ -1687,17 +1741,17 @@ var buildTransaction = (key, params, store, id) => {
1687
1741
  output: void 0
1688
1742
  },
1689
1743
  toolkit: {
1690
- get: (...ps) => getFromStore(...ps, child),
1744
+ get: (...ps) => getFromStore(child, ...ps),
1691
1745
  set: (...ps) => {
1692
- setIntoStore(...ps, child);
1746
+ setIntoStore(child, ...ps);
1693
1747
  },
1694
1748
  run: (token, identifier = arbitrary()) => actUponStore(token, identifier, child),
1695
- find: (token, k) => findInStore(token, k, child),
1696
- seek: (token, k) => seekInStore(token, k, child),
1697
- json: (token) => getJsonToken(token, child),
1749
+ find: (token, k) => findInStore(child, token, k),
1750
+ seek: (token, k) => seekInStore(child, token, k),
1751
+ json: (token) => getJsonToken(child, token),
1698
1752
  make: (context, family, k, ...args) => makeMoleculeInStore(child, context, family, k, ...args),
1699
1753
  dispose: (...ps) => {
1700
- disposeFromStore(...ps, child);
1754
+ disposeFromStore(child, ...ps);
1701
1755
  },
1702
1756
  env: () => getEnvironmentData(child)
1703
1757
  }
@@ -1766,6 +1820,36 @@ function getEpochNumberOfAction(transactionKey, store) {
1766
1820
  // internal/src/transaction/index.ts
1767
1821
  var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
1768
1822
 
1823
+ // internal/src/store/circular-buffer.ts
1824
+ var CircularBuffer = class _CircularBuffer {
1825
+ _buffer;
1826
+ _index = 0;
1827
+ constructor(lengthOrArray) {
1828
+ let length;
1829
+ if (typeof lengthOrArray === `number`) {
1830
+ length = lengthOrArray;
1831
+ } else {
1832
+ length = lengthOrArray.length;
1833
+ }
1834
+ this._buffer = Array.from({ length });
1835
+ }
1836
+ get buffer() {
1837
+ return this._buffer;
1838
+ }
1839
+ get index() {
1840
+ return this._index;
1841
+ }
1842
+ add(item) {
1843
+ this._buffer[this._index] = item;
1844
+ this._index = (this._index + 1) % this._buffer.length;
1845
+ }
1846
+ copy() {
1847
+ const copy = new _CircularBuffer([...this._buffer]);
1848
+ copy._index = this._index;
1849
+ return copy;
1850
+ }
1851
+ };
1852
+
1769
1853
  // internal/src/store/store.ts
1770
1854
  var Store = class {
1771
1855
  parent = null;
@@ -1804,6 +1888,7 @@ var Store = class {
1804
1888
  between: [`timelineKey`, `topicKey`],
1805
1889
  cardinality: `1:n`
1806
1890
  });
1891
+ disposalTraces = new CircularBuffer(100);
1807
1892
  molecules = /* @__PURE__ */ new Map();
1808
1893
  moleculeFamilies = /* @__PURE__ */ new Map();
1809
1894
  moleculeInProgress = null;
@@ -1871,7 +1956,7 @@ var Store = class {
1871
1956
  }
1872
1957
  atom.install(this);
1873
1958
  if (atom.type === `mutable_atom`) {
1874
- const originalJsonToken = getJsonToken(atom, store);
1959
+ const originalJsonToken = getJsonToken(store, atom);
1875
1960
  const originalUpdateToken = getUpdateToken(atom);
1876
1961
  mutableHelpers.add(originalJsonToken.key);
1877
1962
  mutableHelpers.add(originalUpdateToken.key);
@@ -1964,6 +2049,19 @@ var recallState = (state, store) => {
1964
2049
  }
1965
2050
  return target.valueMap.get(state.key);
1966
2051
  };
2052
+ function subscribeInStore(store, token, handleUpdate, key = arbitrary$1()) {
2053
+ switch (token.type) {
2054
+ case `atom`:
2055
+ case `mutable_atom`:
2056
+ case `readonly_selector`:
2057
+ case `selector`:
2058
+ return subscribeToState(token, handleUpdate, key, store);
2059
+ case `transaction`:
2060
+ return subscribeToTransaction(token, handleUpdate, key, store);
2061
+ case `timeline`:
2062
+ return subscribeToTimeline(token, handleUpdate, key, store);
2063
+ }
2064
+ }
1967
2065
 
1968
2066
  // internal/src/subscribe/subscribe-to-root-atoms.ts
1969
2067
  var subscribeToRootAtoms = (selector, store) => {
@@ -2010,7 +2108,7 @@ var subscribeToRootAtoms = (selector, store) => {
2010
2108
  };
2011
2109
 
2012
2110
  // internal/src/subscribe/subscribe-to-state.ts
2013
- function subscribeToState(token, handleUpdate, key, store) {
2111
+ function subscribeToState2(token, handleUpdate, key, store) {
2014
2112
  function safelyHandleUpdate(update) {
2015
2113
  if (store.operation.open) {
2016
2114
  const unsubscribe2 = store.on.operationClose.subscribe(
@@ -2058,7 +2156,7 @@ function subscribeToState(token, handleUpdate, key, store) {
2058
2156
  }
2059
2157
 
2060
2158
  // internal/src/subscribe/subscribe-to-timeline.ts
2061
- var subscribeToTimeline = (token, handleUpdate, key, store) => {
2159
+ var subscribeToTimeline2 = (token, handleUpdate, key, store) => {
2062
2160
  const tl = withdraw(token, store);
2063
2161
  store.logger.info(`\u{1F440}`, `timeline`, token.key, `Adding subscription "${key}"`);
2064
2162
  const unsubscribe = tl.subject.subscribe(key, handleUpdate);
@@ -2074,7 +2172,7 @@ var subscribeToTimeline = (token, handleUpdate, key, store) => {
2074
2172
  };
2075
2173
 
2076
2174
  // internal/src/subscribe/subscribe-to-transaction.ts
2077
- var subscribeToTransaction = (token, handleUpdate, key, store) => {
2175
+ var subscribeToTransaction2 = (token, handleUpdate, key, store) => {
2078
2176
  const tx = withdraw(token, store);
2079
2177
  store.logger.info(
2080
2178
  `\u{1F440}`,
@@ -2106,12 +2204,12 @@ var Tracker = class {
2106
2204
  subKey: mutableState.family.subKey
2107
2205
  } : void 0;
2108
2206
  const latestUpdateState = createRegularAtom(
2207
+ store,
2109
2208
  {
2110
2209
  key: latestUpdateStateKey,
2111
2210
  default: null
2112
2211
  },
2113
- familyMetaData,
2114
- store
2212
+ familyMetaData
2115
2213
  );
2116
2214
  if (store.parent?.valueMap.has(latestUpdateStateKey)) {
2117
2215
  const parentValue = store.parent.valueMap.get(latestUpdateStateKey);
@@ -2123,14 +2221,14 @@ var Tracker = class {
2123
2221
  unsubscribeFromState;
2124
2222
  observeCore(mutableState, latestUpdateState, target) {
2125
2223
  const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2126
- const originalInnerValue = getFromStore(mutableState, target);
2224
+ const originalInnerValue = getFromStore(target, mutableState);
2127
2225
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
2128
2226
  subscriptionKey,
2129
2227
  (update) => {
2130
- setIntoStore(latestUpdateState, update, target);
2228
+ setIntoStore(target, latestUpdateState, update);
2131
2229
  }
2132
2230
  );
2133
- this.unsubscribeFromState = subscribeToState(
2231
+ this.unsubscribeFromState = subscribeToState2(
2134
2232
  mutableState,
2135
2233
  (update) => {
2136
2234
  if (update.newValue !== update.oldValue) {
@@ -2138,7 +2236,7 @@ var Tracker = class {
2138
2236
  this.unsubscribeFromInnerValue = update.newValue.subscribe(
2139
2237
  subscriptionKey,
2140
2238
  (transceiverUpdate) => {
2141
- setIntoStore(latestUpdateState, transceiverUpdate, target);
2239
+ setIntoStore(target, latestUpdateState, transceiverUpdate);
2142
2240
  }
2143
2241
  );
2144
2242
  }
@@ -2149,7 +2247,7 @@ var Tracker = class {
2149
2247
  }
2150
2248
  updateCore(mutableState, latestUpdateState, target) {
2151
2249
  const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2152
- subscribeToState(
2250
+ subscribeToState2(
2153
2251
  latestUpdateState,
2154
2252
  ({ newValue, oldValue }) => {
2155
2253
  const timelineId = target.timelineTopics.getRelatedKey(
@@ -2158,22 +2256,18 @@ var Tracker = class {
2158
2256
  if (timelineId) {
2159
2257
  const timelineData = target.timelines.get(timelineId);
2160
2258
  if (timelineData?.timeTraveling) {
2161
- const unsubscribe2 = subscribeToTimeline(
2259
+ const unsubscribe2 = subscribeToTimeline2(
2162
2260
  { key: timelineId, type: `timeline` },
2163
2261
  (update) => {
2164
2262
  unsubscribe2();
2165
- setIntoStore(
2166
- mutableState,
2167
- (transceiver) => {
2168
- if (update === `redo` && newValue) {
2169
- transceiver.do(newValue);
2170
- } else if (update === `undo` && oldValue) {
2171
- transceiver.undo(oldValue);
2172
- }
2173
- return transceiver;
2174
- },
2175
- target
2176
- );
2263
+ setIntoStore(target, mutableState, (transceiver) => {
2264
+ if (update === `redo` && newValue) {
2265
+ transceiver.do(newValue);
2266
+ } else if (update === `undo` && oldValue) {
2267
+ transceiver.undo(oldValue);
2268
+ }
2269
+ return transceiver;
2270
+ });
2177
2271
  },
2178
2272
  subscriptionKey,
2179
2273
  target
@@ -2185,14 +2279,14 @@ var Tracker = class {
2185
2279
  subscriptionKey,
2186
2280
  () => {
2187
2281
  unsubscribe();
2188
- const mutable = getFromStore(mutableState, target);
2282
+ const mutable = getFromStore(target, mutableState);
2189
2283
  const updateNumber = newValue === null ? -1 : mutable.getUpdateNumber(newValue);
2190
2284
  const eventOffset = updateNumber - mutable.cacheUpdateNumber;
2191
2285
  if (newValue && eventOffset === 1) {
2192
2286
  setIntoStore(
2287
+ target,
2193
2288
  mutableState,
2194
- (transceiver) => (transceiver.do(newValue), transceiver),
2195
- target
2289
+ (transceiver) => (transceiver.do(newValue), transceiver)
2196
2290
  );
2197
2291
  } else {
2198
2292
  target.logger.info(
@@ -2228,7 +2322,7 @@ var Tracker = class {
2228
2322
  };
2229
2323
 
2230
2324
  // internal/src/mutable/create-mutable-atom.ts
2231
- function createMutableAtom(options, family, store) {
2325
+ function createMutableAtom(store, options, family) {
2232
2326
  store.logger.info(
2233
2327
  `\u{1F528}`,
2234
2328
  `atom`,
@@ -2257,7 +2351,7 @@ function createMutableAtom(options, family, store) {
2257
2351
  options.key,
2258
2352
  `installing in store "${s.config.name}"`
2259
2353
  );
2260
- return createMutableAtom(options, family, s);
2354
+ return createMutableAtom(s, options, family);
2261
2355
  },
2262
2356
  subject
2263
2357
  };
@@ -2275,9 +2369,9 @@ function createMutableAtom(options, family, store) {
2275
2369
  for (const effect of options.effects) {
2276
2370
  const cleanup = effect({
2277
2371
  setSelf: (next) => {
2278
- setIntoStore(token, next, store);
2372
+ setIntoStore(store, token, next);
2279
2373
  },
2280
- onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
2374
+ onSet: (handle) => subscribeToState2(token, handle, `effect[${effectIndex}]`, store)
2281
2375
  });
2282
2376
  if (cleanup) {
2283
2377
  cleanupFunctions.push(cleanup);
@@ -2302,11 +2396,11 @@ var FamilyTracker = class {
2302
2396
  mutableAtoms;
2303
2397
  constructor(mutableAtoms, store) {
2304
2398
  const updateAtoms = createRegularAtomFamily(
2399
+ store,
2305
2400
  {
2306
2401
  key: `*${mutableAtoms.key}`,
2307
2402
  default: null
2308
2403
  },
2309
- store,
2310
2404
  [`mutable`, `updates`]
2311
2405
  );
2312
2406
  this.latestUpdateAtoms = withdraw(updateAtoms, store);
@@ -2316,7 +2410,7 @@ var FamilyTracker = class {
2316
2410
  (event) => {
2317
2411
  if (event.token.family) {
2318
2412
  const key = parseJson(event.token.family.subKey);
2319
- seekInStore(this.latestUpdateAtoms, key, store);
2413
+ seekInStore(store, this.latestUpdateAtoms, key);
2320
2414
  new Tracker(event.token, store);
2321
2415
  }
2322
2416
  }
@@ -2326,7 +2420,7 @@ var FamilyTracker = class {
2326
2420
  (event) => {
2327
2421
  if (event.token.family) {
2328
2422
  const key = parseJson(event.token.family.subKey);
2329
- const mutableAtomToken = seekInStore(this.mutableAtoms, key, store);
2423
+ const mutableAtomToken = seekInStore(store, this.mutableAtoms, key);
2330
2424
  if (mutableAtomToken) {
2331
2425
  new Tracker(mutableAtomToken, store);
2332
2426
  }
@@ -2337,12 +2431,22 @@ var FamilyTracker = class {
2337
2431
  };
2338
2432
 
2339
2433
  // internal/src/mutable/create-mutable-atom-family.ts
2340
- function createMutableAtomFamily(options, store, internalRoles) {
2434
+ function createMutableAtomFamily(store, options, internalRoles) {
2341
2435
  const familyToken = {
2342
2436
  key: options.key,
2343
2437
  type: `mutable_atom_family`
2344
2438
  };
2345
- throwInCaseOfConflictingFamily(familyToken, store);
2439
+ const existing = store.families.get(options.key);
2440
+ if (existing) {
2441
+ store.logger.error(
2442
+ `\u2757`,
2443
+ `mutable_atom_family`,
2444
+ options.key,
2445
+ `Overwriting an existing ${prettyPrintTokenType(
2446
+ existing
2447
+ )} "${existing.key}" in store "${store.config.name}". You can safely ignore this warning if it is due to hot module replacement.`
2448
+ );
2449
+ }
2346
2450
  const subject = new Subject();
2347
2451
  const familyFunction = (key) => {
2348
2452
  const subKey = stringifyJson(key);
@@ -2359,13 +2463,13 @@ function createMutableAtomFamily(options, store, internalRoles) {
2359
2463
  if (options.effects) {
2360
2464
  individualOptions.effects = options.effects(key);
2361
2465
  }
2362
- const token = createMutableAtom(individualOptions, family, target);
2466
+ const token = createMutableAtom(target, individualOptions, family);
2363
2467
  subject.next({ type: `state_creation`, token });
2364
2468
  return token;
2365
2469
  };
2366
2470
  const atomFamily = Object.assign(familyFunction, familyToken, {
2367
2471
  subject,
2368
- install: (s) => createMutableAtomFamily(options, s),
2472
+ install: (s) => createMutableAtomFamily(s, options),
2369
2473
  toJson: options.toJson,
2370
2474
  fromJson: options.fromJson,
2371
2475
  internalRoles
@@ -2385,7 +2489,7 @@ var getJsonFamily = (mutableAtomFamily, store) => {
2385
2489
  };
2386
2490
 
2387
2491
  // internal/src/mutable/get-json-token.ts
2388
- var getJsonToken = (mutableAtomToken, store) => {
2492
+ var getJsonToken = (store, mutableAtomToken) => {
2389
2493
  if (mutableAtomToken.family) {
2390
2494
  const target = newest(store);
2391
2495
  const jsonFamilyKey = `${mutableAtomToken.family.key}:JSON`;
@@ -2395,7 +2499,7 @@ var getJsonToken = (mutableAtomToken, store) => {
2395
2499
  };
2396
2500
  const family = withdraw(jsonFamilyToken, target);
2397
2501
  const subKey = JSON.parse(mutableAtomToken.family.subKey);
2398
- const jsonToken = findInStore(family, subKey, store);
2502
+ const jsonToken = findInStore(store, family, subKey);
2399
2503
  return jsonToken;
2400
2504
  }
2401
2505
  const token = {
@@ -2514,7 +2618,7 @@ var markAtomAsNotDefault = (key, store) => {
2514
2618
  };
2515
2619
 
2516
2620
  // internal/src/atom/create-regular-atom.ts
2517
- function createRegularAtom(options, family, store) {
2621
+ function createRegularAtom(store, options, family) {
2518
2622
  store.logger.info(
2519
2623
  `\u{1F528}`,
2520
2624
  `atom`,
@@ -2543,7 +2647,7 @@ function createRegularAtom(options, family, store) {
2543
2647
  options.key,
2544
2648
  `installing in store "${s.config.name}"`
2545
2649
  );
2546
- return createRegularAtom(options, family, s);
2650
+ return createRegularAtom(s, options, family);
2547
2651
  },
2548
2652
  subject
2549
2653
  };
@@ -2564,9 +2668,9 @@ function createRegularAtom(options, family, store) {
2564
2668
  for (const effect of options.effects) {
2565
2669
  const cleanup = effect({
2566
2670
  setSelf: (next) => {
2567
- setIntoStore(token, next, store);
2671
+ setIntoStore(store, token, next);
2568
2672
  },
2569
- onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
2673
+ onSet: (handle) => subscribeToState2(token, handle, `effect[${effectIndex}]`, store)
2570
2674
  });
2571
2675
  if (cleanup) {
2572
2676
  cleanupFunctions.push(cleanup);
@@ -2583,14 +2687,14 @@ function createRegularAtom(options, family, store) {
2583
2687
  }
2584
2688
 
2585
2689
  // internal/src/atom/create-standalone-atom.ts
2586
- function createStandaloneAtom(options, store) {
2690
+ function createStandaloneAtom(store, options) {
2587
2691
  const isMutable = `mutable` in options;
2588
2692
  if (isMutable) {
2589
- const state2 = createMutableAtom(options, void 0, store);
2693
+ const state2 = createMutableAtom(store, options, void 0);
2590
2694
  store.on.atomCreation.next(state2);
2591
2695
  return state2;
2592
2696
  }
2593
- const state = createRegularAtom(options, void 0, store);
2697
+ const state = createRegularAtom(store, options, void 0);
2594
2698
  store.on.atomCreation.next(state);
2595
2699
  return state;
2596
2700
  }
@@ -2599,15 +2703,8 @@ function createStandaloneAtom(options, store) {
2599
2703
  function disposeAtom(atomToken, store) {
2600
2704
  const target = newest(store);
2601
2705
  const { key } = atomToken;
2602
- const atom = target.atoms.get(key);
2603
- if (!atom) {
2604
- store.logger.error(
2605
- `\u274C`,
2606
- `atom`,
2607
- key,
2608
- `Tried to dispose atom, but it does not exist in the store.`
2609
- );
2610
- } else if (!atom.family) {
2706
+ const atom = withdraw(atomToken, target);
2707
+ if (!atom.family) {
2611
2708
  store.logger.error(`\u274C`, `atom`, key, `Standalone atoms cannot be disposed.`);
2612
2709
  } else {
2613
2710
  atom.cleanup?.();
@@ -3070,7 +3167,7 @@ function handleStateLifecycleEvent(event, tl, store) {
3070
3167
  }
3071
3168
 
3072
3169
  // internal/src/timeline/time-travel.ts
3073
- var timeTravel = (action, token, store) => {
3170
+ var timeTravel = (store, action, token) => {
3074
3171
  store.logger.info(
3075
3172
  action === `redo` ? `\u23E9` : `\u23EA`,
3076
3173
  `timeline`,
@@ -3145,4 +3242,4 @@ var timeTravel = (action, token, store) => {
3145
3242
  );
3146
3243
  };
3147
3244
 
3148
- export { FamilyTracker, Future, IMPLICIT, LazyMap, Molecule, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtomFamily, createMoleculeFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, createWritableSelectorFamily, deposit, disposeAtom, disposeFromStore, disposeMolecule, disposeSelector, eldest, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateFamily, getUpdateToken, growMoleculeInStore, ingestAtomUpdate, ingestCreationEvent, ingestDisposalEvent, ingestMoleculeCreationEvent, ingestMoleculeDisposalEvent, ingestSelectorUpdate, ingestTransactionUpdate, initFamilyMemberInStore, isAtomDefault, isAtomKey, isChildStore, isDone, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, makeMoleculeInStore, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, prettyPrintTokenType, readCachedValue, readOrComputeValue, registerSelector, seekInStore, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw };
3245
+ export { FAMILY_MEMBER_TOKEN_TYPES, FamilyTracker, Future, IMPLICIT, LazyMap, Molecule, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, counterfeit, createAtomFamily, createMoleculeFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, createWritableSelectorFamily, deposit, disposeAtom, disposeFromStore, disposeMolecule, disposeSelector, eldest, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateFamily, getUpdateToken, growMoleculeInStore, ingestAtomUpdate, ingestCreationEvent, ingestDisposalEvent, ingestMoleculeCreationEvent, ingestMoleculeDisposalEvent, ingestSelectorUpdate, ingestTransactionUpdate, initFamilyMemberInStore, isAtomDefault, isAtomKey, isChildStore, isDone, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, makeMoleculeInStore, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, prettyPrintTokenType, readCachedValue, readOrComputeValue, recallState, registerSelector, seekInStore, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeInStore, subscribeToRootAtoms, subscribeToState2 as subscribeToState, subscribeToTimeline2 as subscribeToTimeline, subscribeToTransaction2 as subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw };