atom.io 0.20.3 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/data/dist/index.cjs +4 -4
  2. package/data/dist/index.js +1 -1
  3. package/data/src/join.ts +3 -8
  4. package/dist/{chunk-SMZRGPN6.js → chunk-HITX3MO4.js} +2 -2
  5. package/dist/chunk-PNIHPILQ.js +8 -0
  6. package/dist/{chunk-2AIFLP2B.js → chunk-RT43TVKP.js} +2 -2
  7. package/dist/index.cjs +4 -4
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +5 -7
  10. package/internal/dist/index.cjs +56 -74
  11. package/internal/dist/index.d.ts +11 -7
  12. package/internal/dist/index.js +55 -73
  13. package/internal/src/atom/create-regular-atom.ts +1 -1
  14. package/internal/src/atom/dispose-atom.ts +42 -0
  15. package/internal/src/atom/index.ts +1 -1
  16. package/internal/src/future.ts +6 -20
  17. package/internal/src/get-state/get-from-store.ts +1 -2
  18. package/internal/src/mutable/tracker.ts +2 -24
  19. package/internal/src/operation.ts +0 -1
  20. package/internal/src/selector/{delete-selector.ts → dispose-selector.ts} +3 -2
  21. package/internal/src/selector/index.ts +1 -1
  22. package/internal/src/store/deposit.ts +5 -0
  23. package/internal/src/store/store.ts +5 -1
  24. package/internal/src/subscribe/recall-state.ts +3 -3
  25. package/internal/src/subscribe/subscribe-to-state.ts +16 -3
  26. package/introspection/dist/index.cjs +251 -119
  27. package/introspection/dist/index.d.ts +43 -6
  28. package/introspection/dist/index.js +226 -96
  29. package/introspection/src/attach-atom-index.ts +68 -47
  30. package/introspection/src/attach-introspection-states.ts +0 -1
  31. package/introspection/src/attach-selector-index.ts +76 -59
  32. package/introspection/src/attach-timeline-family.ts +2 -17
  33. package/introspection/src/auditor.ts +135 -0
  34. package/introspection/src/index.ts +8 -18
  35. package/package.json +12 -12
  36. package/react-devtools/dist/index.cjs +3 -3
  37. package/react-devtools/dist/index.d.ts +5 -5
  38. package/react-devtools/dist/index.js +4 -4
  39. package/react-devtools/src/StateIndex.tsx +8 -27
  40. package/realtime-client/dist/index.cjs +1 -1
  41. package/realtime-client/dist/index.js +1 -1
  42. package/realtime-client/src/sync-continuity.ts +2 -2
  43. package/realtime-react/dist/index.cjs +1 -1
  44. package/realtime-react/dist/index.js +1 -1
  45. package/realtime-server/dist/index.cjs +2 -2
  46. package/realtime-server/dist/index.js +1 -1
  47. package/realtime-testing/dist/index.cjs +4 -4
  48. package/realtime-testing/dist/index.js +1 -1
  49. package/src/dispose.ts +3 -3
  50. package/src/validators.ts +0 -6
  51. package/internal/src/atom/delete-atom.ts +0 -40
@@ -11,44 +11,30 @@ function arbitrary(random = Math.random) {
11
11
  // internal/src/future.ts
12
12
  var Future = class extends Promise {
13
13
  constructor(executor) {
14
- let promise;
15
14
  let superResolve;
16
15
  let superReject;
17
16
  super((resolve, reject) => {
18
17
  superResolve = resolve;
19
18
  superReject = reject;
20
- promise = executor instanceof Promise ? executor : new Promise(executor);
21
- promise.then(
22
- (value) => {
23
- if (promise) {
24
- this.pass(promise, value);
25
- }
26
- },
27
- (reason) => {
28
- if (promise) {
29
- this.fail(promise, reason);
30
- }
31
- }
32
- );
33
19
  });
34
- this.destiny = promise;
35
20
  this.resolve = superResolve;
36
21
  this.reject = superReject;
22
+ this.use(executor instanceof Promise ? executor : new Promise(executor));
37
23
  }
38
24
  pass(promise, value) {
39
- if (promise === this.destiny) {
25
+ if (promise === this.fate) {
40
26
  this.resolve(value);
41
27
  }
42
28
  }
43
29
  fail(promise, reason) {
44
- if (promise === this.destiny) {
30
+ if (promise === this.fate) {
45
31
  this.reject(reason);
46
32
  }
47
33
  }
48
34
  use(value) {
49
35
  if (value instanceof Promise) {
50
36
  const promise = value;
51
- this.destiny = promise;
37
+ this.fate = promise;
52
38
  promise.then(
53
39
  (resolved) => {
54
40
  this.pass(promise, resolved);
@@ -59,7 +45,7 @@ var Future = class extends Promise {
59
45
  );
60
46
  } else {
61
47
  this.resolve(value);
62
- this.destiny = void 0;
48
+ this.fate = void 0;
63
49
  }
64
50
  }
65
51
  };
@@ -158,9 +144,11 @@ var Store = class {
158
144
  );
159
145
  this.on = {
160
146
  atomCreation: new Subject(),
147
+ atomDisposal: new Subject(),
161
148
  selectorCreation: new Subject(),
162
- transactionCreation: new Subject(),
149
+ selectorDisposal: new Subject(),
163
150
  timelineCreation: new Subject(),
151
+ transactionCreation: new Subject(),
164
152
  transactionApplying: new StatefulSubject(
165
153
  null
166
154
  ),
@@ -942,8 +930,8 @@ function createStandaloneSelector(options, store) {
942
930
  return createReadonlySelector(options, void 0, store);
943
931
  }
944
932
 
945
- // internal/src/selector/delete-selector.ts
946
- function deleteSelector(selectorToken, store) {
933
+ // internal/src/selector/dispose-selector.ts
934
+ function disposeSelector(selectorToken, store) {
947
935
  const target = newest(store);
948
936
  const { key } = selectorToken;
949
937
  switch (selectorToken.type) {
@@ -964,20 +952,21 @@ function deleteSelector(selectorToken, store) {
964
952
  );
965
953
  for (const downstreamToken of downstreamTokens) {
966
954
  if (downstreamToken) {
967
- deleteSelector(downstreamToken, store);
955
+ disposeSelector(downstreamToken, store);
968
956
  }
969
957
  }
970
958
  target.selectorGraph.delete(key);
971
959
  store.logger.info(`\u{1F525}`, selectorToken.type, key, `deleted`);
960
+ store.on.selectorDisposal.next(selectorToken);
972
961
  }
973
962
 
974
963
  // internal/src/subscribe/recall-state.ts
975
964
  var recallState = (state, store) => {
976
965
  const target = newest(store);
977
- if (!target.operation.open) {
978
- return target.valueMap.get(state.key);
966
+ if (target.operation.open) {
967
+ return target.operation.prev.get(state.key);
979
968
  }
980
- return target.operation.prev.get(state.key);
969
+ return target.valueMap.get(state.key);
981
970
  };
982
971
 
983
972
  // internal/src/subscribe/subscribe-to-root-atoms.ts
@@ -1026,11 +1015,24 @@ var subscribeToRootAtoms = (selector, store) => {
1026
1015
 
1027
1016
  // internal/src/subscribe/subscribe-to-state.ts
1028
1017
  function subscribeToState(token, handleUpdate, key, store) {
1018
+ function safelyHandleUpdate(update) {
1019
+ if (store.operation.open) {
1020
+ const unsubscribe2 = store.on.operationClose.subscribe(
1021
+ `state subscription ${key}`,
1022
+ () => {
1023
+ unsubscribe2();
1024
+ handleUpdate(update);
1025
+ }
1026
+ );
1027
+ } else {
1028
+ handleUpdate(update);
1029
+ }
1030
+ }
1029
1031
  const state = withdrawOrCreate(token, store);
1030
1032
  store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
1031
1033
  const isSelector = state.type === `selector` || state.type === `readonly_selector`;
1032
1034
  let dependencyUnsubFunctions = null;
1033
- let updateHandler = handleUpdate;
1035
+ let updateHandler = safelyHandleUpdate;
1034
1036
  if (isSelector) {
1035
1037
  dependencyUnsubFunctions = subscribeToRootAtoms(state, store);
1036
1038
  updateHandler = (update) => {
@@ -1038,7 +1040,7 @@ function subscribeToState(token, handleUpdate, key, store) {
1038
1040
  dependencyUnsubFunctions.length = 0;
1039
1041
  dependencyUnsubFunctions.push(...subscribeToRootAtoms(state, store));
1040
1042
  }
1041
- handleUpdate(update);
1043
+ safelyHandleUpdate(update);
1042
1044
  };
1043
1045
  }
1044
1046
  const mainUnsubFunction = state.subject.subscribe(key, updateHandler);
@@ -1127,18 +1129,7 @@ var Tracker = class {
1127
1129
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
1128
1130
  subscriptionKey,
1129
1131
  (update) => {
1130
- if (target.operation.open) {
1131
- const unsubscribe = target.on.operationClose.subscribe(
1132
- subscriptionKey,
1133
- () => {
1134
- unsubscribe();
1135
- setIntoStore(latestUpdateState, update, target);
1136
- }
1137
- );
1138
- } else {
1139
- setIntoStore(mutableState, (current) => current, target);
1140
- setIntoStore(latestUpdateState, update, target);
1141
- }
1132
+ setIntoStore(latestUpdateState, update, target);
1142
1133
  }
1143
1134
  );
1144
1135
  this.unsubscribeFromState = subscribeToState(
@@ -1149,18 +1140,7 @@ var Tracker = class {
1149
1140
  this.unsubscribeFromInnerValue = update.newValue.subscribe(
1150
1141
  subscriptionKey,
1151
1142
  (transceiverUpdate) => {
1152
- if (target.operation.open) {
1153
- const unsubscribe = target.on.operationClose.subscribe(
1154
- subscriptionKey,
1155
- () => {
1156
- unsubscribe();
1157
- setIntoStore(latestUpdateState, transceiverUpdate, target);
1158
- }
1159
- );
1160
- } else {
1161
- setIntoStore(mutableState, (current) => current, target);
1162
- setIntoStore(latestUpdateState, transceiverUpdate, target);
1163
- }
1143
+ setIntoStore(latestUpdateState, transceiverUpdate, target);
1164
1144
  }
1165
1145
  );
1166
1146
  }
@@ -1597,8 +1577,8 @@ function createStandaloneAtom(options, store) {
1597
1577
  return createRegularAtom(options, void 0, store);
1598
1578
  }
1599
1579
 
1600
- // internal/src/atom/delete-atom.ts
1601
- function deleteAtom(atomToken, store) {
1580
+ // internal/src/atom/dispose-atom.ts
1581
+ function disposeAtom(atomToken, store) {
1602
1582
  var _a, _b;
1603
1583
  const target = newest(store);
1604
1584
  const { key } = atomToken;
@@ -1610,27 +1590,29 @@ function deleteAtom(atomToken, store) {
1610
1590
  key,
1611
1591
  `Tried to delete atom, but it does not exist in the store.`
1612
1592
  );
1613
- }
1614
- (_a = atom == null ? void 0 : atom.cleanup) == null ? void 0 : _a.call(atom);
1615
- target.atoms.delete(key);
1616
- target.valueMap.delete(key);
1617
- const selectorKeys = target.selectorAtoms.getRelatedKeys(key);
1618
- if (selectorKeys) {
1619
- for (const selectorKey of selectorKeys) {
1620
- const token = (_b = target.selectors.get(selectorKey)) != null ? _b : target.readonlySelectors.get(selectorKey);
1621
- if (token) {
1622
- deleteSelector(token, store);
1593
+ } else {
1594
+ (_a = atom.cleanup) == null ? void 0 : _a.call(atom);
1595
+ target.atoms.delete(key);
1596
+ target.valueMap.delete(key);
1597
+ const selectorKeys = target.selectorAtoms.getRelatedKeys(key);
1598
+ if (selectorKeys) {
1599
+ for (const selectorKey of selectorKeys) {
1600
+ const token = (_b = target.selectors.get(selectorKey)) != null ? _b : target.readonlySelectors.get(selectorKey);
1601
+ if (token) {
1602
+ disposeSelector(token, store);
1603
+ }
1623
1604
  }
1624
1605
  }
1606
+ target.selectorAtoms.delete(key);
1607
+ target.atomsThatAreDefault.delete(key);
1608
+ target.timelineAtoms.delete(key);
1609
+ if (atomToken.type === `mutable_atom`) {
1610
+ const updateToken = getUpdateToken(atomToken);
1611
+ disposeAtom(updateToken, store);
1612
+ }
1613
+ store.logger.info(`\u{1F525}`, `atom`, key, `deleted`);
1614
+ store.on.atomDisposal.next(atomToken);
1625
1615
  }
1626
- target.selectorAtoms.delete(key);
1627
- target.atomsThatAreDefault.delete(key);
1628
- target.timelineAtoms.delete(key);
1629
- if (atomToken.type === `mutable_atom`) {
1630
- const updateToken = getUpdateToken(atomToken);
1631
- deleteAtom(updateToken, store);
1632
- }
1633
- store.logger.info(`\u{1F525}`, `atom`, key, `deleted`);
1634
1616
  }
1635
1617
 
1636
1618
  // internal/src/get-environment-data.ts
@@ -2285,4 +2267,4 @@ function getEpochNumberOfAction(transactionKey, store) {
2285
2267
  // internal/src/transaction/index.ts
2286
2268
  var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
2287
2269
 
2288
- export { FamilyTracker, Future, IMPLICIT, LazyMap, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, addAtomToTimeline, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtomFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, deleteAtom, deleteSelector, deposit, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateToken, ingestAtomUpdate, ingestSelectorUpdate, ingestTransactionUpdate, isAtomDefault, isAtomKey, isChildStore, isDone, isMutable, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, readCachedValue, readOrComputeValue, registerSelector, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw, withdrawOrCreate };
2270
+ export { FamilyTracker, Future, IMPLICIT, LazyMap, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, addAtomToTimeline, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtomFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, deposit, disposeAtom, disposeSelector, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateToken, ingestAtomUpdate, ingestSelectorUpdate, ingestTransactionUpdate, isAtomDefault, isAtomKey, isChildStore, isDone, isMutable, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, readCachedValue, readOrComputeValue, registerSelector, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw, withdrawOrCreate };
@@ -16,7 +16,7 @@ import { subscribeToState } from "../subscribe"
16
16
  import { markAtomAsDefault } from "./is-default"
17
17
 
18
18
  export function createRegularAtom<T>(
19
- options: MutableAtomOptions<any, any> | RegularAtomOptions<T>,
19
+ options: RegularAtomOptions<T>,
20
20
  family: FamilyMetadata | undefined,
21
21
  store: Store,
22
22
  ): RegularAtomToken<T> {
@@ -0,0 +1,42 @@
1
+ import type { AtomToken } from "atom.io"
2
+
3
+ import type { Store } from ".."
4
+ import { disposeSelector, getUpdateToken, newest } from ".."
5
+
6
+ export function disposeAtom(atomToken: AtomToken<unknown>, store: Store): void {
7
+ const target = newest(store)
8
+ const { key } = atomToken
9
+ const atom = target.atoms.get(key)
10
+ if (!atom) {
11
+ store.logger.error(
12
+ `❌`,
13
+ `atom`,
14
+ key,
15
+ `Tried to delete atom, but it does not exist in the store.`,
16
+ )
17
+ } else {
18
+ atom.cleanup?.()
19
+ target.atoms.delete(key)
20
+ target.valueMap.delete(key)
21
+ const selectorKeys = target.selectorAtoms.getRelatedKeys(key)
22
+ if (selectorKeys) {
23
+ for (const selectorKey of selectorKeys) {
24
+ const token =
25
+ target.selectors.get(selectorKey) ??
26
+ target.readonlySelectors.get(selectorKey)
27
+ if (token) {
28
+ disposeSelector(token, store)
29
+ }
30
+ }
31
+ }
32
+ target.selectorAtoms.delete(key)
33
+ target.atomsThatAreDefault.delete(key)
34
+ target.timelineAtoms.delete(key)
35
+ if (atomToken.type === `mutable_atom`) {
36
+ const updateToken = getUpdateToken(atomToken)
37
+ disposeAtom(updateToken, store)
38
+ }
39
+ store.logger.info(`🔥`, `atom`, key, `deleted`)
40
+ store.on.atomDisposal.next(atomToken)
41
+ }
42
+ }
@@ -1,4 +1,4 @@
1
1
  export * from "./create-regular-atom"
2
2
  export * from "./create-standalone-atom"
3
- export * from "./delete-atom"
3
+ export * from "./dispose-atom"
4
4
  export * from "./is-default"
@@ -8,7 +8,7 @@
8
8
  * Can be constructed like a Promise, or from an existing Promise.
9
9
  */
10
10
  export class Future<T> extends Promise<T> {
11
- private destiny: Promise<T> | undefined
11
+ private fate: Promise<T> | undefined
12
12
  private resolve: (value: T) => void
13
13
  private reject: (reason?: any) => void
14
14
 
@@ -17,38 +17,24 @@ export class Future<T> extends Promise<T> {
17
17
  | Promise<T>
18
18
  | ((resolve: (value: T) => void, reject: (reason?: any) => void) => void),
19
19
  ) {
20
- let promise: Promise<T> | undefined
21
20
  let superResolve: ((value: T) => void) | undefined
22
21
  let superReject: ((reason?: any) => void) | undefined
23
22
  super((resolve, reject) => {
24
23
  superResolve = resolve
25
24
  superReject = reject
26
- promise = executor instanceof Promise ? executor : new Promise(executor)
27
- promise.then(
28
- (value) => {
29
- if (promise) {
30
- this.pass(promise, value)
31
- }
32
- },
33
- (reason) => {
34
- if (promise) {
35
- this.fail(promise, reason)
36
- }
37
- },
38
- )
39
25
  })
40
- this.destiny = promise
41
26
  this.resolve = superResolve as (value: T) => void
42
27
  this.reject = superReject as (reason?: any) => void
28
+ this.use(executor instanceof Promise ? executor : new Promise(executor))
43
29
  }
44
30
 
45
31
  private pass(promise: Promise<T>, value: T) {
46
- if (promise === this.destiny) {
32
+ if (promise === this.fate) {
47
33
  this.resolve(value)
48
34
  }
49
35
  }
50
36
  private fail(promise: Promise<T>, reason: any) {
51
- if (promise === this.destiny) {
37
+ if (promise === this.fate) {
52
38
  this.reject(reason)
53
39
  }
54
40
  }
@@ -56,7 +42,7 @@ export class Future<T> extends Promise<T> {
56
42
  public use(value: Promise<T> | T): void {
57
43
  if (value instanceof Promise) {
58
44
  const promise = value
59
- this.destiny = promise
45
+ this.fate = promise
60
46
  promise.then(
61
47
  (resolved) => {
62
48
  this.pass(promise, resolved)
@@ -67,7 +53,7 @@ export class Future<T> extends Promise<T> {
67
53
  )
68
54
  } else {
69
55
  this.resolve(value)
70
- this.destiny = undefined
56
+ this.fate = undefined
71
57
  }
72
58
  }
73
59
  }
@@ -1,8 +1,7 @@
1
1
  import type { ReadableToken } from "atom.io"
2
2
 
3
- import { NotFoundError } from "../not-found-error"
4
3
  import type { Store } from "../store"
5
- import { withdraw, withdrawOrCreate } from "../store"
4
+ import { withdrawOrCreate } from "../store"
6
5
  import { readOrComputeValue } from "./read-or-compute-value"
7
6
 
8
7
  export function getFromStore<T>(token: ReadableToken<T>, store: Store): T {
@@ -66,18 +66,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
66
66
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
67
67
  subscriptionKey,
68
68
  (update) => {
69
- if (target.operation.open) {
70
- const unsubscribe = target.on.operationClose.subscribe(
71
- subscriptionKey,
72
- () => {
73
- unsubscribe()
74
- setIntoStore(latestUpdateState, update, target)
75
- },
76
- )
77
- } else {
78
- setIntoStore(mutableState, (current) => current, target)
79
- setIntoStore(latestUpdateState, update, target)
80
- }
69
+ setIntoStore(latestUpdateState, update, target)
81
70
  },
82
71
  )
83
72
  this.unsubscribeFromState = subscribeToState(
@@ -88,18 +77,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
88
77
  this.unsubscribeFromInnerValue = update.newValue.subscribe(
89
78
  subscriptionKey,
90
79
  (transceiverUpdate) => {
91
- if (target.operation.open) {
92
- const unsubscribe = target.on.operationClose.subscribe(
93
- subscriptionKey,
94
- () => {
95
- unsubscribe()
96
- setIntoStore(latestUpdateState, transceiverUpdate, target)
97
- },
98
- )
99
- } else {
100
- setIntoStore(mutableState, (current) => current, target)
101
- setIntoStore(latestUpdateState, transceiverUpdate, target)
102
- }
80
+ setIntoStore(latestUpdateState, transceiverUpdate, target)
103
81
  },
104
82
  )
105
83
  }
@@ -1,6 +1,5 @@
1
1
  import type { WritableToken } from "atom.io"
2
2
 
3
- import { newest } from "./lineage"
4
3
  import type { Store } from "./store"
5
4
  import { isChildStore } from "./transaction/is-root-store"
6
5
 
@@ -3,7 +3,7 @@ import type { ReadonlySelectorToken, WritableSelectorToken } from "atom.io"
3
3
  import type { Store } from ".."
4
4
  import { newest } from ".."
5
5
 
6
- export function deleteSelector(
6
+ export function disposeSelector(
7
7
  selectorToken: ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>,
8
8
  store: Store,
9
9
  ): void {
@@ -29,9 +29,10 @@ export function deleteSelector(
29
29
  )
30
30
  for (const downstreamToken of downstreamTokens) {
31
31
  if (downstreamToken) {
32
- deleteSelector(downstreamToken, store)
32
+ disposeSelector(downstreamToken, store)
33
33
  }
34
34
  }
35
35
  target.selectorGraph.delete(key)
36
36
  store.logger.info(`🔥`, selectorToken.type, key, `deleted`)
37
+ store.on.selectorDisposal.next(selectorToken)
37
38
  }
@@ -1,7 +1,7 @@
1
1
  export * from "./create-readonly-selector"
2
2
  export * from "./create-standalone-selector"
3
3
  export * from "./create-writable-selector"
4
- export * from "./delete-selector"
4
+ export * from "./dispose-selector"
5
5
  export * from "./get-selector-dependency-keys"
6
6
  export * from "./register-selector"
7
7
  export * from "./trace-selector-atoms"
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ AtomToken,
2
3
  Func,
3
4
  MutableAtomToken,
4
5
  ReadableToken,
@@ -11,10 +12,12 @@ import type {
11
12
  } from "atom.io"
12
13
 
13
14
  import type {
15
+ Atom,
14
16
  MutableAtom,
15
17
  ReadableState,
16
18
  ReadonlySelector,
17
19
  RegularAtom,
20
+ Selector,
18
21
  Transceiver,
19
22
  WritableSelector,
20
23
  WritableState,
@@ -25,8 +28,10 @@ export function deposit<T>(state: RegularAtom<T>): RegularAtomToken<T>
25
28
  export function deposit<T extends Transceiver<any>>(
26
29
  state: MutableAtom<T, any>,
27
30
  ): MutableAtomToken<T, any>
31
+ export function deposit<T>(state: Atom<T>): AtomToken<T>
28
32
  export function deposit<T>(state: WritableSelector<T>): WritableSelectorToken<T>
29
33
  export function deposit<T>(state: ReadonlySelector<T>): ReadonlySelectorToken<T>
34
+ export function deposit<T>(state: Selector<T>): SelectorToken<T>
30
35
  export function deposit<T>(state: WritableState<T>): WritableToken<T>
31
36
  export function deposit<T extends Func>(
32
37
  state: Transaction<T>,
@@ -82,11 +82,15 @@ export class Store implements Lineage {
82
82
 
83
83
  public on = {
84
84
  atomCreation: new Subject<AtomToken<unknown>>(),
85
+ atomDisposal: new Subject<AtomToken<unknown>>(),
85
86
  selectorCreation: new Subject<
86
87
  ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>
87
88
  >(),
88
- transactionCreation: new Subject<TransactionToken<Func>>(),
89
+ selectorDisposal: new Subject<
90
+ ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>
91
+ >(),
89
92
  timelineCreation: new Subject<TimelineToken<unknown>>(),
93
+ transactionCreation: new Subject<TransactionToken<Func>>(),
90
94
  transactionApplying: new StatefulSubject<TransactionProgress<Func> | null>(
91
95
  null,
92
96
  ),
@@ -4,8 +4,8 @@ import type { Store } from "../store"
4
4
 
5
5
  export const recallState = <T>(state: ReadableState<T>, store: Store): T => {
6
6
  const target = newest(store)
7
- if (!target.operation.open) {
8
- return target.valueMap.get(state.key)
7
+ if (target.operation.open) {
8
+ return target.operation.prev.get(state.key)
9
9
  }
10
- return target.operation.prev.get(state.key)
10
+ return target.valueMap.get(state.key)
11
11
  }
@@ -1,4 +1,4 @@
1
- import type { ReadableToken, UpdateHandler } from "atom.io"
1
+ import type { ReadableToken, StateUpdate, UpdateHandler } from "atom.io"
2
2
 
3
3
  import type { Store } from "../store"
4
4
  import { withdrawOrCreate } from "../store"
@@ -10,12 +10,25 @@ export function subscribeToState<T>(
10
10
  key: string,
11
11
  store: Store,
12
12
  ): () => void {
13
+ function safelyHandleUpdate(update: StateUpdate<any>): void {
14
+ if (store.operation.open) {
15
+ const unsubscribe = store.on.operationClose.subscribe(
16
+ `state subscription ${key}`,
17
+ () => {
18
+ unsubscribe()
19
+ handleUpdate(update)
20
+ },
21
+ )
22
+ } else {
23
+ handleUpdate(update)
24
+ }
25
+ }
13
26
  const state = withdrawOrCreate(token, store)
14
27
  store.logger.info(`👀`, state.type, state.key, `Adding subscription "${key}"`)
15
28
  const isSelector =
16
29
  state.type === `selector` || state.type === `readonly_selector`
17
30
  let dependencyUnsubFunctions: (() => void)[] | null = null
18
- let updateHandler: UpdateHandler<T> = handleUpdate
31
+ let updateHandler: UpdateHandler<T> = safelyHandleUpdate
19
32
  if (isSelector) {
20
33
  dependencyUnsubFunctions = subscribeToRootAtoms(state, store)
21
34
  updateHandler = (update) => {
@@ -23,7 +36,7 @@ export function subscribeToState<T>(
23
36
  dependencyUnsubFunctions.length = 0
24
37
  dependencyUnsubFunctions.push(...subscribeToRootAtoms(state, store))
25
38
  }
26
- handleUpdate(update)
39
+ safelyHandleUpdate(update)
27
40
  }
28
41
  }
29
42
  const mainUnsubFunction = state.subject.subscribe(key, updateHandler)