atom.io 0.31.0 → 0.32.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 (171) hide show
  1. package/data/dist/index.d.ts +867 -101
  2. package/data/dist/index.js +10 -558
  3. package/data/src/index.ts +0 -2
  4. package/data/src/struct-family.ts +1 -1
  5. package/data/src/struct.ts +1 -2
  6. package/dist/chunk-354XQWHH.js +153 -0
  7. package/dist/chunk-4LWKCEW3.js +14 -0
  8. package/dist/chunk-5F2V7S3B.js +83 -0
  9. package/dist/chunk-ECOMOMUN.js +631 -0
  10. package/dist/{chunk-42UH5F5Q.js → chunk-GY2XQYZY.js} +2051 -755
  11. package/dist/chunk-NF7FJKJD.js +107 -0
  12. package/dist/chunk-R3ZUK5EH.js +1024 -0
  13. package/dist/chunk-Z2UJW4NQ.js +523 -0
  14. package/dist/index.d.ts +855 -127
  15. package/dist/index.js +1 -143
  16. package/eslint-plugin/dist/index.d.ts +1 -30
  17. package/eslint-plugin/dist/index.js +0 -146
  18. package/eslint-plugin/src/index.ts +0 -1
  19. package/eslint-plugin/src/rules/index.ts +0 -1
  20. package/internal/dist/index.d.ts +794 -70
  21. package/internal/dist/index.js +1 -2
  22. package/internal/src/atom/create-regular-atom.ts +3 -3
  23. package/internal/src/atom/dispose-atom.ts +4 -13
  24. package/internal/src/atom/is-default.ts +3 -3
  25. package/internal/src/caching.ts +5 -5
  26. package/internal/src/capitalize.ts +3 -0
  27. package/internal/src/families/create-readonly-selector-family.ts +5 -6
  28. package/internal/src/families/create-writable-selector-family.ts +1 -4
  29. package/internal/src/families/dispose-from-store.ts +3 -13
  30. package/internal/src/families/find-in-store.ts +1 -6
  31. package/internal/src/get-state/get-from-store.ts +2 -2
  32. package/internal/src/get-state/read-or-compute-value.ts +1 -1
  33. package/internal/src/index.ts +19 -9
  34. package/internal/src/ingest-updates/ingest-creation-disposal.ts +2 -3
  35. package/internal/src/install-into-store.ts +48 -0
  36. package/internal/src/join/edit-relations-in-store.ts +32 -0
  37. package/internal/src/join/find-relations-in-store.ts +124 -0
  38. package/internal/src/join/get-internal-relations-from-store.ts +14 -0
  39. package/internal/src/join/get-join.ts +31 -0
  40. package/internal/src/join/index.ts +5 -0
  41. package/{data/src/join.ts → internal/src/join/join-internal.ts} +20 -429
  42. package/internal/src/keys.ts +7 -7
  43. package/internal/src/molecule.ts +299 -0
  44. package/internal/src/mutable/create-mutable-atom-family.ts +1 -1
  45. package/internal/src/mutable/create-mutable-atom.ts +3 -3
  46. package/internal/src/mutable/get-json-token.ts +1 -1
  47. package/internal/src/mutable/tracker-family.ts +19 -17
  48. package/internal/src/mutable/tracker.ts +8 -8
  49. package/internal/src/not-found-error.ts +8 -30
  50. package/internal/src/pretty-print.ts +2 -13
  51. package/internal/src/selector/create-readonly-selector.ts +3 -7
  52. package/internal/src/selector/create-writable-selector.ts +4 -4
  53. package/internal/src/selector/dispose-selector.ts +20 -11
  54. package/internal/src/selector/get-selector-dependency-keys.ts +1 -1
  55. package/internal/src/selector/register-selector.ts +7 -17
  56. package/internal/src/selector/trace-selector-atoms.ts +2 -2
  57. package/internal/src/set-state/copy-mutable-if-needed.ts +1 -1
  58. package/internal/src/set-state/emit-update.ts +1 -1
  59. package/internal/src/set-state/evict-downstream.ts +1 -1
  60. package/internal/src/set-state/set-atom-or-selector.ts +1 -1
  61. package/internal/src/set-state/set-atom.ts +10 -10
  62. package/internal/src/set-state/set-into-store.ts +2 -2
  63. package/internal/src/set-state/stow-update.ts +1 -1
  64. package/internal/src/store/deposit.ts +10 -8
  65. package/internal/src/store/store.ts +1 -1
  66. package/internal/src/store/withdraw.ts +34 -53
  67. package/internal/src/subscribe/recall-state.ts +1 -1
  68. package/internal/src/subscribe/subscribe-in-store.ts +3 -3
  69. package/internal/src/subscribe/subscribe-to-root-atoms.ts +3 -3
  70. package/internal/src/subscribe/subscribe-to-state.ts +5 -5
  71. package/internal/src/subscribe/subscribe-to-timeline.ts +3 -3
  72. package/internal/src/subscribe/subscribe-to-transaction.ts +3 -3
  73. package/internal/src/timeline/create-timeline.ts +17 -37
  74. package/internal/src/transaction/act-upon-store.ts +2 -2
  75. package/internal/src/transaction/apply-transaction.ts +5 -5
  76. package/internal/src/transaction/assign-transaction-to-continuity.ts +1 -1
  77. package/internal/src/transaction/build-transaction.ts +5 -8
  78. package/internal/src/transaction/create-transaction.ts +3 -3
  79. package/internal/src/transaction/get-epoch-number.ts +3 -3
  80. package/internal/src/transaction/set-epoch-number.ts +2 -2
  81. package/introspection/dist/index.d.ts +922 -6
  82. package/introspection/dist/index.js +2 -620
  83. package/json/dist/index.d.ts +899 -5
  84. package/json/dist/index.js +1 -81
  85. package/json/src/select-json-family.ts +3 -14
  86. package/package.json +27 -45
  87. package/react/dist/index.d.ts +921 -3
  88. package/react/dist/index.js +2 -82
  89. package/react/src/use-o.ts +1 -1
  90. package/react/src/use-tl.ts +2 -2
  91. package/react-devtools/dist/index.css +16 -14
  92. package/react-devtools/dist/index.d.ts +26 -1
  93. package/react-devtools/dist/index.js +6 -6
  94. package/react-devtools/src/devtools.scss +16 -14
  95. package/realtime/dist/index.d.ts +202 -8
  96. package/realtime/dist/index.js +2 -107
  97. package/realtime/src/realtime-continuity.ts +2 -2
  98. package/realtime/src/shared-room-store.ts +1 -2
  99. package/realtime-client/dist/index.d.ts +960 -22
  100. package/realtime-client/dist/index.js +3 -509
  101. package/realtime-client/src/continuity/register-and-attempt-confirmed-update.ts +3 -3
  102. package/realtime-client/src/continuity/use-conceal-state.ts +1 -1
  103. package/realtime-client/src/pull-atom-family-member.ts +2 -2
  104. package/realtime-client/src/pull-atom.ts +2 -2
  105. package/realtime-client/src/pull-mutable-atom-family-member.ts +2 -2
  106. package/realtime-client/src/pull-mutable-atom.ts +2 -2
  107. package/realtime-client/src/pull-selector-family-member.ts +4 -4
  108. package/realtime-client/src/pull-selector.ts +4 -4
  109. package/realtime-client/src/push-state.ts +5 -10
  110. package/realtime-client/src/server-action.ts +4 -4
  111. package/realtime-client/src/sync-continuity.ts +6 -6
  112. package/realtime-react/dist/index.d.ts +166 -12
  113. package/realtime-react/dist/index.js +5 -154
  114. package/realtime-react/src/use-pull-atom-family-member.ts +1 -1
  115. package/realtime-react/src/use-pull-atom.ts +1 -1
  116. package/realtime-react/src/use-pull-mutable-atom.ts +1 -1
  117. package/realtime-react/src/use-pull-mutable-family-member.ts +1 -1
  118. package/realtime-react/src/use-pull-selector-family-member.ts +1 -1
  119. package/realtime-react/src/use-pull-selector.ts +1 -1
  120. package/realtime-react/src/use-push.ts +1 -1
  121. package/realtime-react/src/use-server-action.ts +2 -2
  122. package/realtime-react/src/use-sync-continuity.ts +1 -1
  123. package/realtime-server/dist/index.d.ts +971 -28
  124. package/realtime-server/dist/index.js +3 -1001
  125. package/realtime-server/src/continuity/prepare-to-serve-transaction-request.ts +1 -1
  126. package/realtime-server/src/continuity/prepare-to-sync-realtime-continuity.ts +3 -3
  127. package/realtime-server/src/continuity/subscribe-to-continuity-actions.ts +2 -2
  128. package/realtime-server/src/continuity/subscribe-to-continuity-perpectives.ts +2 -2
  129. package/realtime-server/src/ipc-sockets/child-socket.ts +0 -1
  130. package/realtime-server/src/realtime-action-receiver.ts +1 -1
  131. package/realtime-server/src/realtime-family-provider.ts +2 -2
  132. package/realtime-server/src/realtime-mutable-family-provider.ts +2 -2
  133. package/realtime-server/src/realtime-mutable-provider.ts +2 -2
  134. package/realtime-server/src/realtime-server-stores/server-room-external-actions.ts +2 -1
  135. package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +1 -1
  136. package/realtime-server/src/realtime-server-stores/server-user-store.ts +1 -2
  137. package/realtime-server/src/realtime-state-provider.ts +2 -2
  138. package/realtime-testing/dist/index.d.ts +1091 -3
  139. package/realtime-testing/dist/index.js +23 -26
  140. package/realtime-testing/src/setup-realtime-test.tsx +6 -5
  141. package/src/atom.ts +53 -29
  142. package/src/dispose-state.ts +12 -2
  143. package/{ephemeral/src → src}/find-state.ts +35 -25
  144. package/src/get-state.ts +16 -0
  145. package/src/index.ts +77 -3
  146. package/src/join.ts +218 -0
  147. package/src/realm.ts +169 -0
  148. package/src/selector.ts +20 -0
  149. package/src/set-state.ts +16 -8
  150. package/src/silo.ts +13 -7
  151. package/src/timeline.ts +1 -1
  152. package/src/transaction.ts +4 -8
  153. package/transceivers/set-rtx/dist/index.d.ts +37 -2
  154. package/transceivers/set-rtx/dist/index.js +1 -212
  155. package/transceivers/set-rtx/src/set-rtx.ts +4 -1
  156. package/web/dist/index.d.ts +30 -1
  157. package/web/dist/index.js +1 -15
  158. package/data/src/until.ts +0 -15
  159. package/dist/chunk-ICGFFQ3H.js +0 -272
  160. package/ephemeral/dist/index.d.ts +0 -57
  161. package/ephemeral/dist/index.js +0 -9
  162. package/ephemeral/package.json +0 -13
  163. package/ephemeral/src/index.ts +0 -1
  164. package/eslint-plugin/src/rules/lifespan.ts +0 -203
  165. package/immortal/dist/index.d.ts +0 -12
  166. package/immortal/dist/index.js +0 -9
  167. package/immortal/package.json +0 -13
  168. package/immortal/src/index.ts +0 -1
  169. package/immortal/src/seek-state.ts +0 -60
  170. package/src/allocate.ts +0 -443
  171. package/src/molecule.ts +0 -16
@@ -1,7 +1,306 @@
1
+ import type {
2
+ Above,
3
+ Claim,
4
+ CompoundFrom,
5
+ CompoundTypedKey,
6
+ Hierarchy,
7
+ MoleculeCreation,
8
+ MoleculeDisposal,
9
+ MoleculeTransfer,
10
+ SingularTypedKey,
11
+ Vassal,
12
+ } from "atom.io"
1
13
  import type { Canonical, stringified } from "atom.io/json"
14
+ import { parseJson, stringifyJson } from "atom.io/json"
15
+
16
+ import { disposeFromStore, findInStore } from "./families"
17
+ import { getTrace } from "./get-trace"
18
+ import { newest } from "./lineage"
19
+ import type { Store } from "./store"
20
+ import { IMPLICIT } from "./store"
21
+ import { isChildStore } from "./transaction"
2
22
 
3
23
  export type Molecule<K extends Canonical> = {
4
24
  readonly key: K
5
25
  readonly stringKey: stringified<K>
6
26
  readonly dependsOn: `all` | `any`
7
27
  }
28
+
29
+ export function makeRootMoleculeInStore<S extends string>(
30
+ key: S,
31
+ store: Store = IMPLICIT.STORE,
32
+ ): S {
33
+ const molecule = {
34
+ key,
35
+ stringKey: stringifyJson(key),
36
+ dependsOn: `any`,
37
+ } satisfies Molecule<S>
38
+ store.molecules.set(stringifyJson(key), molecule)
39
+ return key
40
+ }
41
+
42
+ export function allocateIntoStore<
43
+ H extends Hierarchy,
44
+ V extends Vassal<H>,
45
+ A extends Above<V, H>,
46
+ >(
47
+ store: Store,
48
+ provenance: A,
49
+ key: V,
50
+ dependsOn: `all` | `any` = `any`,
51
+ ): Claim<V> {
52
+ const origin = provenance as Canonical | [Canonical, Canonical]
53
+ const stringKey = stringifyJson(key)
54
+ const invalidKeys: stringified<Canonical>[] = []
55
+ const target = newest(store)
56
+
57
+ if (Array.isArray(origin)) {
58
+ for (const formerClaim of origin) {
59
+ const claimString = stringifyJson(formerClaim)
60
+ const claim = target.molecules.get(claimString)
61
+ if (claim) {
62
+ store.moleculeGraph.set(claimString, stringKey, { source: claimString })
63
+ } else {
64
+ invalidKeys.push(claimString)
65
+ }
66
+ }
67
+ } else {
68
+ const claimString = stringifyJson(origin)
69
+ const claim = target.molecules.get(claimString)
70
+ if (claim) {
71
+ store.moleculeGraph.set(claimString, stringKey, { source: claimString })
72
+ } else {
73
+ invalidKeys.push(claimString)
74
+ }
75
+ }
76
+ if (invalidKeys.length === 0) {
77
+ target.molecules.set(stringKey, { key, stringKey, dependsOn })
78
+ }
79
+
80
+ const creationEvent: MoleculeCreation = {
81
+ type: `molecule_creation`,
82
+ key,
83
+ provenance: origin,
84
+ }
85
+ const isTransaction =
86
+ isChildStore(target) && target.transactionMeta.phase === `building`
87
+ if (isTransaction) {
88
+ target.transactionMeta.update.updates.push(creationEvent)
89
+ } else {
90
+ target.on.moleculeCreation.next(creationEvent)
91
+ }
92
+
93
+ for (const claim of invalidKeys) {
94
+ const disposal = store.disposalTraces.buffer.find(
95
+ (item) => item?.key === claim,
96
+ )
97
+ store.logger.error(
98
+ `❌`,
99
+ `molecule`,
100
+ key,
101
+ `allocation failed:`,
102
+ `Could not allocate to ${claim} in store "${store.config.name}".`,
103
+ disposal
104
+ ? `\n ${claim} was most recently disposed\n${disposal.trace}`
105
+ : `No previous disposal trace for ${claim} was found.`,
106
+ )
107
+ }
108
+
109
+ return key as Claim<V>
110
+ }
111
+
112
+ export function fuseWithinStore<
113
+ H extends Hierarchy,
114
+ C extends CompoundFrom<H>,
115
+ T extends C extends CompoundTypedKey<infer t, any, any> ? t : never,
116
+ A extends C extends CompoundTypedKey<any, infer a, any> ? a : never,
117
+ B extends C extends CompoundTypedKey<any, any, infer b> ? b : never,
118
+ >(
119
+ store: Store,
120
+ type: T,
121
+ sideA: SingularTypedKey<A>,
122
+ sideB: SingularTypedKey<B>,
123
+ ): Claim<CompoundTypedKey<T, A, B>> {
124
+ const compoundKey: CompoundTypedKey<T, A, B> =
125
+ `T$--${type}==${sideA}++${sideB}`
126
+ const above = [sideA, sideB] as Above<Vassal<H>, H>
127
+ allocateIntoStore<H, Vassal<H>, Above<Vassal<H>, H>>(
128
+ store,
129
+ above,
130
+ compoundKey as Vassal<H>,
131
+ `all`,
132
+ )
133
+ return compoundKey
134
+ }
135
+
136
+ export function deallocateFromStore<H extends Hierarchy, V extends Vassal<H>>(
137
+ store: Store,
138
+ claim: Claim<V>,
139
+ ): void {
140
+ const stringKey = stringifyJson(claim)
141
+
142
+ const molecule = store.molecules.get(stringKey)
143
+ if (!molecule) {
144
+ const disposal = store.disposalTraces.buffer.find(
145
+ (item) => item?.key === stringKey,
146
+ )
147
+ store.logger.error(
148
+ `❌`,
149
+ `molecule`,
150
+ claim,
151
+ `deallocation failed:`,
152
+ `Could not find allocation for ${stringKey} in store "${store.config.name}".`,
153
+ disposal
154
+ ? `\n This state was most recently deallocated\n${disposal.trace}`
155
+ : `No previous disposal trace for ${stringKey} was found.`,
156
+ )
157
+ return
158
+ }
159
+
160
+ const joinKeys = store.moleculeJoins.getRelatedKeys(
161
+ molecule.key as string /* 💥 RECONCILE */,
162
+ )
163
+ if (joinKeys) {
164
+ for (const joinKey of joinKeys) {
165
+ const join = store.joins.get(joinKey)
166
+ if (join) {
167
+ join.relations.delete(molecule.key)
168
+ join.molecules.delete(molecule.stringKey) // get rid of
169
+ }
170
+ }
171
+ }
172
+ store.moleculeJoins.delete(molecule.stringKey)
173
+
174
+ const provenance: stringified<Canonical>[] = []
175
+
176
+ const values: [string, any][] = []
177
+ const disposalEvent: MoleculeDisposal = {
178
+ type: `molecule_disposal`,
179
+ key: molecule.key,
180
+ values,
181
+ provenance,
182
+ }
183
+ const target = newest(store)
184
+ target.molecules.delete(stringKey)
185
+ const isTransaction =
186
+ isChildStore(target) && target.transactionMeta.phase === `building`
187
+ if (isTransaction) {
188
+ target.transactionMeta.update.updates.push(disposalEvent)
189
+ }
190
+ const relatedMolecules = store.moleculeGraph.getRelationEntries({
191
+ downstreamMoleculeKey: molecule.stringKey,
192
+ })
193
+ if (relatedMolecules) {
194
+ for (const [relatedStringKey, { source }] of relatedMolecules) {
195
+ if (source === molecule.stringKey) {
196
+ const relatedKey = parseJson(relatedStringKey)
197
+ deallocateFromStore<any, any>(store, relatedKey)
198
+ } else {
199
+ provenance.push(source)
200
+ }
201
+ }
202
+ }
203
+ const familyKeys = target.moleculeData.getRelatedKeys(molecule.stringKey)
204
+ if (familyKeys) {
205
+ for (const familyKey of familyKeys) {
206
+ // biome-ignore lint/style/noNonNullAssertion: tokens of molecules must have a family
207
+ const family = target.families.get(familyKey)!
208
+ const token = findInStore(store, family, molecule.key)
209
+ values.push([family.key, token])
210
+ disposeFromStore(store, token)
211
+ }
212
+ }
213
+
214
+ target.moleculeGraph.delete(molecule.stringKey)
215
+ target.moleculeJoins.delete(molecule.stringKey)
216
+ target.moleculeData.delete(molecule.stringKey)
217
+
218
+ if (!isTransaction) {
219
+ target.on.moleculeDisposal.next(disposalEvent)
220
+ }
221
+ target.molecules.delete(molecule.stringKey)
222
+
223
+ const trace = getTrace(new Error())
224
+ store.disposalTraces.add({ key: stringKey, trace })
225
+ }
226
+ export function claimWithinStore<
227
+ H extends Hierarchy,
228
+ V extends Exclude<Vassal<H>, CompoundTypedKey>,
229
+ A extends Above<V, H>,
230
+ >(
231
+ store: Store,
232
+ newProvenance: A,
233
+ claim: Claim<V>,
234
+ exclusive?: `exclusive`,
235
+ ): Claim<V> {
236
+ const stringKey = stringifyJson(claim)
237
+ const target = newest(store)
238
+ const molecule = target.molecules.get(stringKey)
239
+ if (!molecule) {
240
+ const disposal = store.disposalTraces.buffer.find(
241
+ (item) => item?.key === stringKey,
242
+ )
243
+ store.logger.error(
244
+ `❌`,
245
+ `molecule`,
246
+ claim,
247
+ `claim failed:`,
248
+ `Could not allocate to ${stringKey} in store "${store.config.name}".`,
249
+ disposal
250
+ ? `\n ${stringKey} was most recently disposed\n${disposal.trace}`
251
+ : `No previous disposal trace for ${stringKey} was found.`,
252
+ )
253
+ return claim
254
+ }
255
+
256
+ const newProvenanceKey = stringifyJson(newProvenance as Canonical)
257
+ const newProvenanceMolecule = target.molecules.get(newProvenanceKey)
258
+ if (!newProvenanceMolecule) {
259
+ const disposal = store.disposalTraces.buffer.find(
260
+ (item) => item?.key === newProvenanceKey,
261
+ )
262
+ store.logger.error(
263
+ `❌`,
264
+ `molecule`,
265
+ claim,
266
+ `claim failed:`,
267
+ `Could not allocate to ${newProvenanceKey} in store "${store.config.name}".`,
268
+ disposal
269
+ ? `\n ${newProvenanceKey} was most recently disposed\n${disposal.trace}`
270
+ : `No previous disposal trace for ${newProvenanceKey} was found.`,
271
+ )
272
+ return claim
273
+ }
274
+
275
+ const priorProvenance = store.moleculeGraph
276
+ .getRelationEntries({
277
+ downstreamMoleculeKey: molecule.stringKey,
278
+ })
279
+ .filter(([, { source }]) => source !== stringKey)
280
+ .map(([key]) => parseJson(key))
281
+ if (exclusive) {
282
+ target.moleculeGraph.delete(stringKey)
283
+ }
284
+ target.moleculeGraph.set(
285
+ {
286
+ upstreamMoleculeKey: newProvenanceMolecule.stringKey,
287
+ downstreamMoleculeKey: molecule.stringKey,
288
+ },
289
+ {
290
+ source: newProvenanceMolecule.stringKey,
291
+ },
292
+ )
293
+ const transferEvent: MoleculeTransfer = {
294
+ type: `molecule_transfer`,
295
+ key: molecule.key,
296
+ from: priorProvenance,
297
+ to: [newProvenanceMolecule.key],
298
+ }
299
+ const isTransaction =
300
+ isChildStore(target) && target.transactionMeta.phase === `building`
301
+ if (isTransaction) {
302
+ target.transactionMeta.update.updates.push(transferEvent)
303
+ }
304
+
305
+ return claim
306
+ }
@@ -80,7 +80,7 @@ export function createMutableAtomFamily<
80
80
  }) satisfies MutableAtomFamily<T, J, K>
81
81
 
82
82
  store.families.set(options.key, atomFamily)
83
- selectJsonFamily(atomFamily, options, store)
83
+ selectJsonFamily(store, atomFamily, options)
84
84
  new FamilyTracker(atomFamily, store)
85
85
  return familyToken
86
86
  }
@@ -61,8 +61,8 @@ export function createMutableAtom<
61
61
  }
62
62
  const initialValue = options.default()
63
63
  target.atoms.set(newAtom.key, newAtom)
64
- markAtomAsDefault(options.key, store)
65
- cacheValue(options.key, initialValue, subject, target)
64
+ markAtomAsDefault(store, options.key)
65
+ cacheValue(target, options.key, initialValue, subject)
66
66
  const token = deposit(newAtom)
67
67
  if (options.effects) {
68
68
  let effectIndex = 0
@@ -73,7 +73,7 @@ export function createMutableAtom<
73
73
  setIntoStore(store, token, next)
74
74
  },
75
75
  onSet: (handle: UpdateHandler<T>) =>
76
- subscribeToState(token, handle, `effect[${effectIndex}]`, store),
76
+ subscribeToState(store, token, `effect[${effectIndex}]`, handle),
77
77
  })
78
78
  if (cleanup) {
79
79
  cleanupFunctions.push(cleanup)
@@ -27,7 +27,7 @@ export const getJsonToken = <
27
27
  key: jsonFamilyKey,
28
28
  type: `selector_family`,
29
29
  }
30
- const family = withdraw(jsonFamilyToken, target)
30
+ const family = withdraw(target, jsonFamilyToken)
31
31
  const subKey = JSON.parse(mutableAtomToken.family.subKey)
32
32
  const jsonToken = findInStore(store, family, subKey)
33
33
  return jsonToken
@@ -2,7 +2,7 @@ import type { Canonical } from "atom.io/json"
2
2
  import { parseJson } from "atom.io/json"
3
3
 
4
4
  import type { MutableAtomFamily, RegularAtomFamily } from ".."
5
- import { createRegularAtomFamily, seekInStore } from "../families"
5
+ import { createRegularAtomFamily } from "../families"
6
6
  import { type Store, withdraw } from "../store"
7
7
  import { Tracker } from "./tracker"
8
8
  import type { Transceiver } from "./transceiver"
@@ -11,6 +11,7 @@ export class FamilyTracker<
11
11
  Core extends Transceiver<any>,
12
12
  FamilyMemberKey extends Canonical,
13
13
  > {
14
+ private trackers: Map<FamilyMemberKey, Tracker<Core>> = new Map()
14
15
  private readonly Update: Core extends Transceiver<infer Signal>
15
16
  ? Signal
16
17
  : never
@@ -36,26 +37,27 @@ export class FamilyTracker<
36
37
  },
37
38
  [`mutable`, `updates`],
38
39
  )
39
- this.latestUpdateAtoms = withdraw(updateAtoms, store)
40
+ this.latestUpdateAtoms = withdraw(store, updateAtoms)
40
41
  this.mutableAtoms = mutableAtoms
41
42
  this.mutableAtoms.subject.subscribe(
42
43
  `store=${store.config.name}::tracker-atom-family`,
43
44
  (event) => {
44
- if (event.token.family) {
45
- const key = parseJson(event.token.family.subKey) as FamilyMemberKey
46
- seekInStore(store, this.latestUpdateAtoms, key)
47
- new Tracker<Core>(event.token, store)
48
- }
49
- },
50
- )
51
- this.latestUpdateAtoms.subject.subscribe(
52
- `store=${store.config.name}::tracker-atom-family`,
53
- (event) => {
54
- if (event.token.family) {
55
- const key = parseJson(event.token.family.subKey) as FamilyMemberKey
56
- const mutableAtomToken = seekInStore(store, this.mutableAtoms, key)
57
- if (mutableAtomToken) {
58
- new Tracker<Core>(mutableAtomToken, store)
45
+ const { type, token } = event
46
+ if (token.family) {
47
+ const key = parseJson(token.family.subKey)
48
+ switch (type) {
49
+ case `state_creation`:
50
+ this.trackers.set(key, new Tracker<Core>(token, store))
51
+ break
52
+ case `state_disposal`:
53
+ {
54
+ const tracker = this.trackers.get(key)
55
+ if (tracker) {
56
+ tracker[Symbol.dispose]()
57
+ this.trackers.delete(key)
58
+ }
59
+ }
60
+ break
59
61
  }
60
62
  }
61
63
  },
@@ -70,7 +70,9 @@ export class Tracker<Mutable extends Transceiver<any>> {
70
70
  },
71
71
  )
72
72
  this.unsubscribeFromState = subscribeToState(
73
+ target,
73
74
  mutableState,
75
+ subscriptionKey,
74
76
  (update) => {
75
77
  if (update.newValue !== update.oldValue) {
76
78
  this.unsubscribeFromInnerValue()
@@ -82,8 +84,6 @@ export class Tracker<Mutable extends Transceiver<any>> {
82
84
  )
83
85
  }
84
86
  },
85
- subscriptionKey,
86
- target,
87
87
  )
88
88
  }
89
89
 
@@ -96,7 +96,9 @@ export class Tracker<Mutable extends Transceiver<any>> {
96
96
  isChildStore(target) ? target.transactionMeta.update.key : `main`
97
97
  }:${mutableState.key}`
98
98
  subscribeToState(
99
+ target,
99
100
  latestUpdateState,
101
+ subscriptionKey,
100
102
  ({ newValue, oldValue }) => {
101
103
  const timelineId = target.timelineTopics.getRelatedKey(
102
104
  latestUpdateState.key,
@@ -106,7 +108,9 @@ export class Tracker<Mutable extends Transceiver<any>> {
106
108
  const timelineData = target.timelines.get(timelineId)
107
109
  if (timelineData?.timeTraveling) {
108
110
  const unsubscribe = subscribeToTimeline(
111
+ target,
109
112
  { key: timelineId, type: `timeline` },
113
+ subscriptionKey,
110
114
  (update) => {
111
115
  unsubscribe()
112
116
  setIntoStore(target, mutableState, (transceiver) => {
@@ -118,8 +122,6 @@ export class Tracker<Mutable extends Transceiver<any>> {
118
122
  return transceiver
119
123
  })
120
124
  },
121
- subscriptionKey,
122
- target,
123
125
  )
124
126
  return
125
127
  }
@@ -152,15 +154,13 @@ export class Tracker<Mutable extends Transceiver<any>> {
152
154
  },
153
155
  )
154
156
  },
155
- subscriptionKey,
156
- target,
157
157
  )
158
158
  }
159
159
 
160
160
  public mutableState: MutableAtomToken<Mutable, Json.Serializable>
161
161
  public latestUpdateState: RegularAtomToken<typeof this.Update | null>
162
162
 
163
- public dispose: () => void
163
+ public [Symbol.dispose]: () => void
164
164
 
165
165
  public constructor(
166
166
  mutableState: MutableAtomToken<Mutable, Json.Serializable>,
@@ -172,7 +172,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
172
172
  this.observeCore(mutableState, this.latestUpdateState, target)
173
173
  this.updateCore(mutableState, this.latestUpdateState, target)
174
174
  target.trackers.set(mutableState.key, this)
175
- this.dispose = () => {
175
+ this[Symbol.dispose] = () => {
176
176
  this.unsubscribeFromInnerValue()
177
177
  this.unsubscribeFromState()
178
178
  target.trackers.delete(mutableState.key)
@@ -1,37 +1,15 @@
1
- import { type Json, stringifyJson } from "atom.io/json"
1
+ import type { AtomIOToken } from "atom.io"
2
+ import { stringifyJson } from "atom.io/json"
2
3
 
3
- import type { AtomIOToken } from "./pretty-print"
4
4
  import { prettyPrintTokenType } from "./pretty-print"
5
5
  import type { Store } from "./store"
6
6
 
7
7
  export class NotFoundError extends Error {
8
- public constructor(token: AtomIOToken, store: Store)
9
- public constructor(
10
- familyToken: AtomIOToken,
11
- key: Json.Serializable,
12
- store: Store,
13
- )
14
- public constructor(
15
- ...params:
16
- | [token: AtomIOToken, key: Json.Serializable, store: Store]
17
- | [token: AtomIOToken, store: Store]
18
- ) {
19
- const token: AtomIOToken = params[0]
20
- const store: Store = params.length === 2 ? params[1] : params[2]
21
-
22
- if (params.length === 2) {
23
- super(
24
- `${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${
25
- store.config.name
26
- }".`,
27
- )
28
- } else {
29
- const key = params[1]
30
- super(
31
- `${prettyPrintTokenType(token)} "${token.key}" member ${stringifyJson(key)} not found in store "${
32
- store.config.name
33
- }".`,
34
- )
35
- }
8
+ public constructor(token: AtomIOToken, store: Store) {
9
+ super(
10
+ `${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${
11
+ store.config.name
12
+ }".`,
13
+ )
36
14
  }
37
15
  }
@@ -1,17 +1,6 @@
1
- import type {
2
- ReadableFamilyToken,
3
- ReadableToken,
4
- TimelineToken,
5
- TransactionToken,
6
- } from "atom.io"
1
+ import type { AtomIOToken } from "atom.io"
7
2
 
8
- const capitalize = (str: string) => str[0].toUpperCase() + str.slice(1)
9
-
10
- export type AtomIOToken =
11
- | ReadableFamilyToken<any, any>
12
- | ReadableToken<any>
13
- | TimelineToken<any>
14
- | TransactionToken<any>
3
+ import { capitalize } from "./capitalize"
15
4
 
16
5
  export function prettyPrintTokenType(token: AtomIOToken): string {
17
6
  return token.type.split(`_`).map(capitalize).join(` `)
@@ -19,14 +19,10 @@ export const createReadonlySelector = <T>(
19
19
  const target = newest(store)
20
20
  const subject = new Subject<{ newValue: T; oldValue: T }>()
21
21
  const covered = new Set<string>()
22
- const { get, find, seek, json } = registerSelector(
23
- options.key,
24
- covered,
25
- target,
26
- )
22
+ const { get, find, json } = registerSelector(options.key, covered, target)
27
23
  const getSelf = () => {
28
- const value = options.get({ get, find, seek, json })
29
- cacheValue(options.key, value, subject, newest(store))
24
+ const value = options.get({ get, find, json })
25
+ cacheValue(newest(store), options.key, value, subject)
30
26
  covered.clear()
31
27
  return value
32
28
  }
@@ -23,12 +23,12 @@ export const createWritableSelector = <T>(
23
23
  const subject = new Subject<{ newValue: T; oldValue: T }>()
24
24
  const covered = new Set<string>()
25
25
  const setterToolkit = registerSelector(options.key, covered, target)
26
- const { find, get, seek, json } = setterToolkit
27
- const getterToolkit = { find, get, seek, json }
26
+ const { find, get, json } = setterToolkit
27
+ const getterToolkit = { find, get, json }
28
28
 
29
29
  const getSelf = (getFn = options.get, innerTarget = newest(store)): T => {
30
30
  const value = getFn(getterToolkit)
31
- cacheValue(options.key, value, subject, innerTarget)
31
+ cacheValue(innerTarget, options.key, value, subject)
32
32
  covered.clear()
33
33
  return value
34
34
  }
@@ -47,7 +47,7 @@ export const createWritableSelector = <T>(
47
47
  newValue,
48
48
  `)`,
49
49
  )
50
- cacheValue(options.key, newValue, subject, innerTarget)
50
+ cacheValue(innerTarget, options.key, newValue, subject)
51
51
  markDone(innerTarget, options.key)
52
52
  if (isRootStore(innerTarget)) {
53
53
  subject.next({ newValue, oldValue })
@@ -1,15 +1,15 @@
1
- import type { ReadonlySelectorToken, WritableSelectorToken } from "atom.io"
1
+ import type { SelectorFamilyToken, SelectorToken } from "atom.io"
2
2
 
3
3
  import type { Store } from ".."
4
4
  import { isChildStore, newest, withdraw } from ".."
5
5
 
6
6
  export function disposeSelector(
7
- selectorToken: ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>,
8
7
  store: Store,
8
+ selectorToken: SelectorToken<unknown>,
9
9
  ): void {
10
10
  const target = newest(store)
11
11
  const { key } = selectorToken
12
- const selector = withdraw(selectorToken, target)
12
+ const selector = withdraw(target, selectorToken)
13
13
  if (!selector.family) {
14
14
  store.logger.error(
15
15
  `❌`,
@@ -22,23 +22,31 @@ export function disposeSelector(
22
22
  if (molecule) {
23
23
  target.moleculeData.delete(selector.family.subKey, selector.family.key)
24
24
  }
25
+ let familyToken: SelectorFamilyToken<any, any>
25
26
  switch (selectorToken.type) {
26
27
  case `selector`:
27
28
  {
28
29
  target.selectors.delete(key)
29
- const family = withdraw(
30
- { key: selector.family.key, type: `selector_family` },
31
- store,
32
- )
30
+ familyToken = {
31
+ key: selector.family.key,
32
+ type: `selector_family`,
33
+ }
34
+ const family = withdraw(store, familyToken)
35
+ family.subject.next({
36
+ type: `state_disposal`,
37
+ subType: `selector`,
38
+ token: selectorToken,
39
+ })
33
40
  }
34
41
  break
35
42
  case `readonly_selector`:
36
43
  {
37
44
  target.readonlySelectors.delete(key)
38
- const family = withdraw(
39
- { key: selector.family.key, type: `readonly_selector_family` },
40
- store,
41
- )
45
+ familyToken = {
46
+ key: selector.family.key,
47
+ type: `readonly_selector_family`,
48
+ }
49
+ const family = withdraw(store, familyToken)
42
50
  family.subject.next({
43
51
  type: `state_disposal`,
44
52
  subType: `selector`,
@@ -47,6 +55,7 @@ export function disposeSelector(
47
55
  }
48
56
  break
49
57
  }
58
+
50
59
  target.valueMap.delete(key)
51
60
  target.selectorAtoms.delete(key)
52
61
  target.selectorGraph.delete(key)
@@ -15,6 +15,6 @@ export const getSelectorDependencyKeys = (
15
15
  .selectorGraph.getRelationEntries({ downstreamSelectorKey: key })
16
16
  .filter(([_, { source }]) => source !== key)
17
17
  .map(([_, { source }]) => source)
18
- .filter((source) => isStateKey(source, store))
18
+ .filter((source) => isStateKey(store, source))
19
19
  return sources
20
20
  }