atom.io 0.27.1 → 0.27.3

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 (45) hide show
  1. package/data/dist/index.d.ts +12 -12
  2. package/data/dist/index.js +20 -14
  3. package/data/src/dict.ts +4 -4
  4. package/data/src/join.ts +23 -18
  5. package/data/src/struct-family.ts +2 -2
  6. package/dist/chunk-ETCFHO7J.js +3087 -0
  7. package/dist/index.d.ts +4 -31
  8. package/eslint-plugin/dist/index.js +8 -0
  9. package/eslint-plugin/src/walk.ts +8 -0
  10. package/internal/dist/index.d.ts +52 -19
  11. package/internal/dist/index.js +2 -3044
  12. package/internal/src/families/create-atom-family.ts +6 -5
  13. package/internal/src/families/create-readonly-selector-family.ts +38 -29
  14. package/internal/src/families/create-regular-atom-family.ts +40 -31
  15. package/internal/src/families/create-selector-family.ts +6 -5
  16. package/internal/src/families/create-writable-selector-family.ts +39 -30
  17. package/internal/src/families/throw-in-case-of-conflicting-family.ts +18 -0
  18. package/internal/src/index.ts +76 -2
  19. package/internal/src/ingest-updates/ingest-creation-disposal.ts +0 -1
  20. package/internal/src/ingest-updates/ingest-selector-update.ts +1 -1
  21. package/internal/src/molecule/dispose-molecule.ts +0 -1
  22. package/internal/src/molecule/grow-molecule-in-store.ts +27 -17
  23. package/internal/src/mutable/create-mutable-atom-family.ts +41 -32
  24. package/internal/src/mutable/get-json-family.ts +2 -1
  25. package/internal/src/mutable/get-update-family.ts +23 -0
  26. package/internal/src/mutable/index.ts +1 -0
  27. package/internal/src/mutable/tracker-family.ts +5 -3
  28. package/internal/src/not-found-error.ts +2 -35
  29. package/internal/src/pretty-print.ts +37 -0
  30. package/internal/src/store/store.ts +10 -4
  31. package/internal/src/store/withdraw.ts +8 -8
  32. package/introspection/dist/index.js +3 -3
  33. package/introspection/src/attach-timeline-family.ts +1 -1
  34. package/introspection/src/attach-transaction-logs.ts +2 -2
  35. package/json/dist/index.d.ts +2 -2
  36. package/json/dist/index.js +16 -12
  37. package/json/src/select-json-family.ts +21 -18
  38. package/package.json +4 -4
  39. package/realtime-server/dist/index.d.ts +1 -1
  40. package/src/atom.ts +2 -32
  41. package/src/get-state.ts +2 -2
  42. package/src/index.ts +1 -10
  43. package/src/selector.ts +1 -26
  44. package/src/set-state.ts +2 -2
  45. package/src/silo.ts +7 -5
@@ -0,0 +1,3087 @@
1
+ import { Junction } from './chunk-IBTHB2PI.js';
2
+ import { stringifyJson, parseJson, selectJson, selectJsonFamily } from 'atom.io/json';
3
+ import { AtomIOLogger } from 'atom.io';
4
+ import { getJoin, findRelations } from 'atom.io/data';
5
+
6
+ // internal/src/arbitrary.ts
7
+ function arbitrary(random = Math.random) {
8
+ return random().toString(36).slice(2);
9
+ }
10
+
11
+ // internal/src/future.ts
12
+ var Future = class extends Promise {
13
+ fate;
14
+ resolve;
15
+ reject;
16
+ constructor(executor) {
17
+ let superResolve;
18
+ let superReject;
19
+ super((resolve, reject) => {
20
+ superResolve = resolve;
21
+ superReject = reject;
22
+ });
23
+ this.resolve = superResolve;
24
+ this.reject = superReject;
25
+ this.use(executor instanceof Promise ? executor : new Promise(executor));
26
+ }
27
+ pass(promise, value) {
28
+ if (promise === this.fate) {
29
+ this.resolve(value);
30
+ }
31
+ }
32
+ fail(promise, reason) {
33
+ if (promise === this.fate) {
34
+ this.reject(reason);
35
+ }
36
+ }
37
+ use(value) {
38
+ if (value instanceof Promise) {
39
+ const promise = value;
40
+ this.fate = promise;
41
+ promise.then(
42
+ (resolved) => {
43
+ this.pass(promise, resolved);
44
+ },
45
+ (reason) => {
46
+ this.fail(promise, reason);
47
+ }
48
+ );
49
+ } else {
50
+ this.resolve(value);
51
+ this.fate = void 0;
52
+ }
53
+ }
54
+ };
55
+
56
+ // internal/src/lineage.ts
57
+ function newest(scion) {
58
+ while (scion.child !== null) {
59
+ scion = scion.child;
60
+ }
61
+ return scion;
62
+ }
63
+ function eldest(scion) {
64
+ while (scion.parent !== null) {
65
+ scion = scion.parent;
66
+ }
67
+ return scion;
68
+ }
69
+
70
+ // internal/src/store/deposit.ts
71
+ function deposit(state) {
72
+ const token = {
73
+ key: state.key,
74
+ type: state.type
75
+ };
76
+ if (`family` in state) {
77
+ token.family = state.family;
78
+ }
79
+ return token;
80
+ }
81
+
82
+ // internal/src/subject.ts
83
+ var Subject = class {
84
+ Subscriber;
85
+ subscribers = /* @__PURE__ */ new Map();
86
+ subscribe(key, subscriber) {
87
+ this.subscribers.set(key, subscriber);
88
+ const unsubscribe = () => {
89
+ this.unsubscribe(key);
90
+ };
91
+ return unsubscribe;
92
+ }
93
+ unsubscribe(key) {
94
+ this.subscribers.delete(key);
95
+ }
96
+ next(value) {
97
+ const subscribers = this.subscribers.values();
98
+ for (const subscriber of subscribers) {
99
+ subscriber(value);
100
+ }
101
+ }
102
+ };
103
+ var StatefulSubject = class extends Subject {
104
+ state;
105
+ constructor(initialState) {
106
+ super();
107
+ this.state = initialState;
108
+ }
109
+ next(value) {
110
+ this.state = value;
111
+ super.next(value);
112
+ }
113
+ };
114
+
115
+ // internal/src/transaction/is-root-store.ts
116
+ function isRootStore(store) {
117
+ return `epoch` in store.transactionMeta;
118
+ }
119
+ function isChildStore(store) {
120
+ return `phase` in store.transactionMeta;
121
+ }
122
+
123
+ // internal/src/transaction/abort-transaction.ts
124
+ var abortTransaction = (store) => {
125
+ const target = newest(store);
126
+ if (!isChildStore(target)) {
127
+ store.logger.warn(
128
+ `\u{1F41E}`,
129
+ `transaction`,
130
+ `???`,
131
+ `abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`
132
+ );
133
+ return;
134
+ }
135
+ store.logger.info(
136
+ `\u{1FA82}`,
137
+ `transaction`,
138
+ target.transactionMeta.update.key,
139
+ `Aborting transaction`
140
+ );
141
+ target.parent.child = null;
142
+ };
143
+
144
+ // internal/src/pretty-print.ts
145
+ var capitalize = (str) => str[0].toUpperCase() + str.slice(1);
146
+ 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
+ }
163
+ }
164
+
165
+ // internal/src/not-found-error.ts
166
+ var NotFoundError = class extends Error {
167
+ constructor(...params) {
168
+ const token = params[0];
169
+ const store = params.length === 2 ? params[1] : params[2];
170
+ if (params.length === 2) {
171
+ super(
172
+ `${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${store.config.name}".`
173
+ );
174
+ } else {
175
+ const key = params[1];
176
+ super(
177
+ `${prettyPrintTokenType(token)} "${token.key}" member ${stringifyJson(key)} not found in store "${store.config.name}".`
178
+ );
179
+ }
180
+ }
181
+ };
182
+
183
+ // internal/src/transaction/act-upon-store.ts
184
+ function actUponStore(token, id, store) {
185
+ return (...parameters) => {
186
+ const tx = withdraw(token, store);
187
+ if (tx) {
188
+ return tx.run(parameters, id);
189
+ }
190
+ throw new NotFoundError(token, store);
191
+ };
192
+ }
193
+
194
+ // internal/src/set-state/become.ts
195
+ var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
196
+ originalThing instanceof Function ? originalThing() : originalThing
197
+ ) : nextVersionOfThing;
198
+
199
+ // internal/src/get-state/read-or-compute-value.ts
200
+ var readOrComputeValue = (state, target) => {
201
+ if (target.valueMap.has(state.key)) {
202
+ target.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
203
+ return readCachedValue(state, target);
204
+ }
205
+ if (state.type !== `atom` && state.type !== `mutable_atom`) {
206
+ target.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
207
+ return state.get();
208
+ }
209
+ const fallback = state.default instanceof Function ? state.default() : state.default;
210
+ target.logger.info(
211
+ `\u{1F481}`,
212
+ `atom`,
213
+ state.key,
214
+ `could not find cached value; using default`,
215
+ fallback
216
+ );
217
+ return state.default instanceof Function ? state.default() : state.default;
218
+ };
219
+
220
+ // internal/src/operation.ts
221
+ var openOperation = (token, store) => {
222
+ if (store.operation.open) {
223
+ const rejectionTime = performance.now();
224
+ store.logger.info(
225
+ `\u2757`,
226
+ token.type,
227
+ token.key,
228
+ `deferring setState at T-${rejectionTime} until setState for "${store.operation.token.key}" is done`
229
+ );
230
+ return rejectionTime;
231
+ }
232
+ store.operation = {
233
+ open: true,
234
+ done: /* @__PURE__ */ new Set(),
235
+ prev: /* @__PURE__ */ new Map(),
236
+ time: Date.now(),
237
+ token
238
+ };
239
+ store.logger.info(
240
+ `\u2B55`,
241
+ token.type,
242
+ token.key,
243
+ `operation start in store "${store.config.name}"${!isChildStore(store) ? `` : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`}`
244
+ );
245
+ };
246
+ var closeOperation = (store) => {
247
+ if (store.operation.open) {
248
+ store.logger.info(
249
+ `\u{1F534}`,
250
+ store.operation.token.type,
251
+ store.operation.token.key,
252
+ `operation done in store "${store.config.name}"`
253
+ );
254
+ }
255
+ store.operation = { open: false };
256
+ store.on.operationClose.next(store.operation);
257
+ };
258
+ var isDone = (key, store) => {
259
+ if (!store.operation.open) {
260
+ store.logger.warn(
261
+ `\u{1F41E}`,
262
+ `unknown`,
263
+ key,
264
+ `isDone called outside of an operation. This is probably a bug.`
265
+ );
266
+ return true;
267
+ }
268
+ return store.operation.done.has(key);
269
+ };
270
+ var markDone = (key, store) => {
271
+ if (!store.operation.open) {
272
+ store.logger.warn(
273
+ `\u{1F41E}`,
274
+ `unknown`,
275
+ key,
276
+ `markDone called outside of an operation. This is probably a bug.`
277
+ );
278
+ return;
279
+ }
280
+ store.operation.done.add(key);
281
+ };
282
+
283
+ // internal/src/set-state/emit-update.ts
284
+ var emitUpdate = (state, update, store) => {
285
+ switch (state.type) {
286
+ case `mutable_atom`:
287
+ store.logger.info(
288
+ `\u{1F4E2}`,
289
+ state.type,
290
+ state.key,
291
+ `is now (`,
292
+ update.newValue,
293
+ `) subscribers:`,
294
+ state.subject.subscribers
295
+ );
296
+ break;
297
+ default:
298
+ store.logger.info(
299
+ `\u{1F4E2}`,
300
+ state.type,
301
+ state.key,
302
+ `went (`,
303
+ update.oldValue,
304
+ `->`,
305
+ update.newValue,
306
+ `) subscribers:`,
307
+ state.subject.subscribers
308
+ );
309
+ }
310
+ state.subject.next(update);
311
+ };
312
+
313
+ // internal/src/set-state/evict-downstream.ts
314
+ var evictDownStream = (atom, store) => {
315
+ const target = newest(store);
316
+ const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key);
317
+ target.logger.info(
318
+ `\u{1F9F9}`,
319
+ atom.type,
320
+ atom.key,
321
+ downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
322
+ downstreamKeys ?? `to evict`
323
+ );
324
+ if (downstreamKeys) {
325
+ if (target.operation.open) {
326
+ target.logger.info(
327
+ `\u{1F9F9}`,
328
+ atom.type,
329
+ atom.key,
330
+ `[ ${[...target.operation.done].join(`, `)} ] already done`
331
+ );
332
+ }
333
+ for (const key of downstreamKeys) {
334
+ if (isDone(key, target)) {
335
+ continue;
336
+ }
337
+ evictCachedValue(key, target);
338
+ markDone(key, target);
339
+ }
340
+ }
341
+ };
342
+
343
+ // internal/src/set-state/stow-update.ts
344
+ function shouldUpdateBeStowed(key, update) {
345
+ if (isTransceiver(update.newValue)) {
346
+ return false;
347
+ }
348
+ if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
349
+ return false;
350
+ }
351
+ return true;
352
+ }
353
+ var stowUpdate = (state, update, store) => {
354
+ const { key } = state;
355
+ const target = newest(store);
356
+ if (!isChildStore(target) || target.transactionMeta.phase !== `building`) {
357
+ store.logger.error(
358
+ `\u{1F41E}`,
359
+ `atom`,
360
+ key,
361
+ `stowUpdate called outside of a transaction. This is probably a bug.`
362
+ );
363
+ return;
364
+ }
365
+ const shouldStow = shouldUpdateBeStowed(key, update);
366
+ if (!shouldStow) {
367
+ return;
368
+ }
369
+ const atomUpdate = {
370
+ type: `atom_update`,
371
+ key,
372
+ ...update
373
+ };
374
+ if (state.family) {
375
+ atomUpdate.family = state.family;
376
+ }
377
+ target.transactionMeta.update.updates.push(atomUpdate);
378
+ store.logger.info(
379
+ `\u{1F4C1}`,
380
+ `atom`,
381
+ key,
382
+ `stowed (`,
383
+ update.oldValue,
384
+ `->`,
385
+ update.newValue,
386
+ `)`
387
+ );
388
+ };
389
+
390
+ // internal/src/set-state/set-atom.ts
391
+ var setAtom = (atom, next, target) => {
392
+ const oldValue = readOrComputeValue(atom, target);
393
+ let newValue = oldValue;
394
+ if (atom.type === `mutable_atom` && isChildStore(target)) {
395
+ const { parent } = target;
396
+ const copiedValue = copyMutableIfNeeded(atom, parent, target);
397
+ newValue = copiedValue;
398
+ }
399
+ newValue = become(next)(newValue);
400
+ target.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
401
+ newValue = cacheValue(atom.key, newValue, atom.subject, target);
402
+ if (isAtomDefault(atom.key, target)) {
403
+ markAtomAsNotDefault(atom.key, target);
404
+ }
405
+ markDone(atom.key, target);
406
+ evictDownStream(atom, target);
407
+ const update = { oldValue, newValue };
408
+ if (isRootStore(target)) {
409
+ emitUpdate(atom, update, target);
410
+ } else if (target.parent) {
411
+ if (target.on.transactionApplying.state === null) {
412
+ stowUpdate(atom, update, target);
413
+ } else if (atom.key.startsWith(`*`)) {
414
+ const mutableKey = atom.key.slice(1);
415
+ const mutableAtom = target.atoms.get(mutableKey);
416
+ let transceiver = target.valueMap.get(mutableKey);
417
+ if (mutableAtom.type === `mutable_atom` && isChildStore(target)) {
418
+ const { parent } = target;
419
+ const copiedValue = copyMutableIfNeeded(mutableAtom, parent, target);
420
+ transceiver = copiedValue;
421
+ }
422
+ const accepted = transceiver.do(update.newValue) === null;
423
+ if (accepted) evictDownStream(mutableAtom, target);
424
+ }
425
+ }
426
+ };
427
+
428
+ // internal/src/set-state/set-atom-or-selector.ts
429
+ var setAtomOrSelector = (state, value, store) => {
430
+ switch (state.type) {
431
+ case `atom`:
432
+ case `mutable_atom`:
433
+ setAtom(state, value, store);
434
+ break;
435
+ case `selector`:
436
+ state.set(value);
437
+ break;
438
+ }
439
+ };
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) {
455
+ const familyToken = {
456
+ key: options.key,
457
+ type: `atom_family`
458
+ };
459
+ throwInCaseOfConflictingFamily(familyToken, store);
460
+ const subject = new Subject();
461
+ const familyFunction = (key) => {
462
+ const subKey = stringifyJson(key);
463
+ const family = { key: options.key, subKey };
464
+ const fullKey = `${options.key}(${subKey})`;
465
+ const target = newest(store);
466
+ const def = options.default;
467
+ const individualOptions = {
468
+ key: fullKey,
469
+ default: def instanceof Function ? def(key) : def
470
+ };
471
+ if (options.effects) {
472
+ individualOptions.effects = options.effects(key);
473
+ }
474
+ const token = createRegularAtom(individualOptions, family, target);
475
+ subject.next({ type: `state_creation`, token });
476
+ return token;
477
+ };
478
+ const atomFamily = Object.assign(familyFunction, familyToken, {
479
+ subject,
480
+ install: (s) => createRegularAtomFamily(options, s),
481
+ internalRoles
482
+ });
483
+ store.families.set(options.key, atomFamily);
484
+ return familyToken;
485
+ }
486
+
487
+ // internal/src/families/create-atom-family.ts
488
+ function createAtomFamily(options, store) {
489
+ const isMutable = `mutable` in options;
490
+ if (isMutable) {
491
+ return createMutableAtomFamily(options, store);
492
+ }
493
+ return createRegularAtomFamily(options, store);
494
+ }
495
+
496
+ // internal/src/get-state/get-from-store.ts
497
+ function getFromStore(...params) {
498
+ let token;
499
+ let store;
500
+ if (params.length === 2) {
501
+ token = params[0];
502
+ store = params[1];
503
+ } else {
504
+ const family = params[0];
505
+ const key = params[1];
506
+ store = params[2];
507
+ const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
508
+ if (!maybeToken) {
509
+ throw new NotFoundError(family, key, store);
510
+ }
511
+ token = maybeToken;
512
+ }
513
+ switch (token.type) {
514
+ case `atom`:
515
+ case `mutable_atom`:
516
+ case `selector`:
517
+ case `readonly_selector`:
518
+ return readOrComputeValue(withdraw(token, store), store);
519
+ case `molecule`:
520
+ return withdraw(token, store).instance;
521
+ }
522
+ }
523
+
524
+ // internal/src/keys.ts
525
+ var isAtomKey = (key, store) => newest(store).atoms.has(key);
526
+ var isSelectorKey = (key, store) => newest(store).selectors.has(key);
527
+ var isReadonlySelectorKey = (key, store) => newest(store).readonlySelectors.has(key);
528
+ var isStateKey = (key, store) => isAtomKey(key, store) || isSelectorKey(key, store) || isReadonlySelectorKey(key, store);
529
+
530
+ // internal/src/selector/get-selector-dependency-keys.ts
531
+ var getSelectorDependencyKeys = (key, store) => {
532
+ const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(source, store));
533
+ return sources;
534
+ };
535
+
536
+ // internal/src/selector/trace-selector-atoms.ts
537
+ var traceSelectorAtoms = (directDependencyKey, covered, store) => {
538
+ const rootKeys = [];
539
+ const indirectDependencyKeys = getSelectorDependencyKeys(
540
+ directDependencyKey,
541
+ store
542
+ );
543
+ while (indirectDependencyKeys.length > 0) {
544
+ const indirectDependencyKey = indirectDependencyKeys.shift();
545
+ if (covered.has(indirectDependencyKey)) {
546
+ continue;
547
+ }
548
+ covered.add(indirectDependencyKey);
549
+ if (!isAtomKey(indirectDependencyKey, store)) {
550
+ indirectDependencyKeys.push(
551
+ ...getSelectorDependencyKeys(indirectDependencyKey, store)
552
+ );
553
+ } else if (!rootKeys.includes(indirectDependencyKey)) {
554
+ rootKeys.push(indirectDependencyKey);
555
+ }
556
+ }
557
+ return rootKeys;
558
+ };
559
+ var traceAllSelectorAtoms = (selector, store) => {
560
+ const selectorKey = selector.key;
561
+ const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
562
+ const covered = /* @__PURE__ */ new Set();
563
+ return directDependencyKeys.flatMap(
564
+ (depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(depKey, covered, store)
565
+ );
566
+ };
567
+
568
+ // internal/src/selector/update-selector-atoms.ts
569
+ var updateSelectorAtoms = (selectorKey, dependency, covered, store) => {
570
+ const target = newest(store);
571
+ if (dependency.type === `atom` || dependency.type === `mutable_atom`) {
572
+ target.selectorAtoms.set({
573
+ selectorKey,
574
+ atomKey: dependency.key
575
+ });
576
+ store.logger.info(
577
+ `\u{1F50D}`,
578
+ `selector`,
579
+ selectorKey,
580
+ `discovers root atom "${dependency.key}"`
581
+ );
582
+ } else {
583
+ const rootKeys = traceSelectorAtoms(dependency.key, covered, store);
584
+ store.logger.info(
585
+ `\u{1F50D}`,
586
+ `selector`,
587
+ selectorKey,
588
+ `discovers root atoms: [ ${rootKeys.map((key) => `"${key}"`).join(`, `)} ]`
589
+ );
590
+ for (const atomKey of rootKeys) {
591
+ target.selectorAtoms = target.selectorAtoms.set({
592
+ selectorKey,
593
+ atomKey
594
+ });
595
+ }
596
+ }
597
+ covered.add(dependency.key);
598
+ };
599
+
600
+ // internal/src/selector/register-selector.ts
601
+ var registerSelector = (selectorKey, covered, store) => ({
602
+ get: (...params) => {
603
+ const target = newest(store);
604
+ let dependency;
605
+ if (params.length === 2) {
606
+ const [family, key] = params;
607
+ switch (family.type) {
608
+ case `molecule_family`:
609
+ return getFromStore(family, key, store);
610
+ default:
611
+ if (store.config.lifespan === `ephemeral`) {
612
+ dependency = findInStore(family, key, store);
613
+ } else {
614
+ const maybeDependency = seekInStore(family, key, store);
615
+ if (maybeDependency) {
616
+ dependency = maybeDependency;
617
+ } else {
618
+ throw new NotFoundError(family, key, store);
619
+ }
620
+ }
621
+ }
622
+ } else {
623
+ [dependency] = params;
624
+ }
625
+ if (dependency.type === `molecule`) {
626
+ return getFromStore(dependency, store);
627
+ }
628
+ const dependencyState = withdraw(dependency, store);
629
+ const dependencyValue = readOrComputeValue(dependencyState, store);
630
+ store.logger.info(
631
+ `\u{1F50C}`,
632
+ `selector`,
633
+ selectorKey,
634
+ `registers dependency ( "${dependency.key}" =`,
635
+ dependencyValue,
636
+ `)`
637
+ );
638
+ target.selectorGraph.set(
639
+ {
640
+ upstreamSelectorKey: dependency.key,
641
+ downstreamSelectorKey: selectorKey
642
+ },
643
+ {
644
+ source: dependency.key
645
+ }
646
+ );
647
+ updateSelectorAtoms(selectorKey, dependency, covered, store);
648
+ return dependencyValue;
649
+ },
650
+ set: (...params) => {
651
+ let token;
652
+ let value;
653
+ if (params.length === 2) {
654
+ token = params[0];
655
+ value = params[1];
656
+ } else {
657
+ const family = params[0];
658
+ const key = params[1];
659
+ value = params[2];
660
+ const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
661
+ if (!maybeToken) {
662
+ throw new NotFoundError(family, key, store);
663
+ }
664
+ token = maybeToken;
665
+ }
666
+ const target = newest(store);
667
+ const state = withdraw(token, target);
668
+ setAtomOrSelector(state, value, target);
669
+ },
670
+ find: (token, key) => findInStore(token, key, store),
671
+ seek: (token, key) => seekInStore(token, key, store),
672
+ json: (token) => getJsonToken(token, store)
673
+ });
674
+
675
+ // internal/src/selector/create-readonly-selector.ts
676
+ var createReadonlySelector = (options, family, store) => {
677
+ const target = newest(store);
678
+ const subject = new Subject();
679
+ const covered = /* @__PURE__ */ new Set();
680
+ const { get, find, seek, json } = registerSelector(
681
+ options.key,
682
+ covered,
683
+ target
684
+ );
685
+ const getSelf = () => {
686
+ const value = options.get({ get, find, seek, json });
687
+ cacheValue(options.key, value, subject, newest(store));
688
+ covered.clear();
689
+ return value;
690
+ };
691
+ const readonlySelector = {
692
+ ...options,
693
+ subject,
694
+ install: (s) => createReadonlySelector(options, family, s),
695
+ get: getSelf,
696
+ type: `readonly_selector`,
697
+ ...family && { family }
698
+ };
699
+ target.readonlySelectors.set(options.key, readonlySelector);
700
+ const initialValue = getSelf();
701
+ store.logger.info(
702
+ `\u2728`,
703
+ readonlySelector.type,
704
+ readonlySelector.key,
705
+ `=`,
706
+ initialValue
707
+ );
708
+ const token = {
709
+ key: options.key,
710
+ type: `readonly_selector`
711
+ };
712
+ if (family) {
713
+ token.family = family;
714
+ }
715
+ return token;
716
+ };
717
+
718
+ // internal/src/selector/create-writable-selector.ts
719
+ var createWritableSelector = (options, family, store) => {
720
+ const target = newest(store);
721
+ const subject = new Subject();
722
+ const covered = /* @__PURE__ */ new Set();
723
+ const toolkit = registerSelector(options.key, covered, target);
724
+ const { find, get, seek, json } = toolkit;
725
+ const getterToolkit = { find, get, seek, json };
726
+ const getSelf = (innerTarget = newest(store)) => {
727
+ const value = options.get(getterToolkit);
728
+ cacheValue(options.key, value, subject, innerTarget);
729
+ covered.clear();
730
+ return value;
731
+ };
732
+ const setSelf = (next) => {
733
+ const innerTarget = newest(store);
734
+ const oldValue = getSelf(innerTarget);
735
+ const newValue = become(next)(oldValue);
736
+ store.logger.info(
737
+ `\u{1F4DD}`,
738
+ `selector`,
739
+ options.key,
740
+ `set (`,
741
+ oldValue,
742
+ `->`,
743
+ newValue,
744
+ `)`
745
+ );
746
+ cacheValue(options.key, newValue, subject, innerTarget);
747
+ markDone(options.key, innerTarget);
748
+ if (isRootStore(innerTarget)) {
749
+ subject.next({ newValue, oldValue });
750
+ }
751
+ options.set(toolkit, newValue);
752
+ };
753
+ const mySelector = {
754
+ ...options,
755
+ subject,
756
+ install: (s) => createWritableSelector(options, family, s),
757
+ get: getSelf,
758
+ set: setSelf,
759
+ type: `selector`,
760
+ ...family && { family }
761
+ };
762
+ target.selectors.set(options.key, mySelector);
763
+ const initialValue = getSelf();
764
+ store.logger.info(`\u2728`, mySelector.type, mySelector.key, `=`, initialValue);
765
+ const token = {
766
+ key: options.key,
767
+ type: `selector`
768
+ };
769
+ if (family) {
770
+ token.family = family;
771
+ }
772
+ return token;
773
+ };
774
+
775
+ // internal/src/selector/create-standalone-selector.ts
776
+ function createStandaloneSelector(options, store) {
777
+ const isWritable = `set` in options;
778
+ if (isWritable) {
779
+ const state2 = createWritableSelector(options, void 0, store);
780
+ store.on.selectorCreation.next(state2);
781
+ return state2;
782
+ }
783
+ const state = createReadonlySelector(options, void 0, store);
784
+ store.on.selectorCreation.next(state);
785
+ return state;
786
+ }
787
+
788
+ // internal/src/selector/dispose-selector.ts
789
+ function disposeSelector(selectorToken, store) {
790
+ const target = newest(store);
791
+ const { key } = selectorToken;
792
+ const selector = target.selectors.get(key) ?? target.readonlySelectors.get(key);
793
+ if (!selector) {
794
+ store.logger.info(
795
+ `\u274C`,
796
+ `selector`,
797
+ key,
798
+ `Tried to dispose selector, but it does not exist in the store.`
799
+ );
800
+ } else if (!selector.family) {
801
+ store.logger.error(
802
+ `\u274C`,
803
+ `selector`,
804
+ key,
805
+ `Standalone selectors cannot be disposed.`
806
+ );
807
+ } else {
808
+ const molecule = target.molecules.get(selector.family.subKey);
809
+ if (molecule) {
810
+ molecule.tokens.delete(key);
811
+ }
812
+ switch (selectorToken.type) {
813
+ case `selector`:
814
+ {
815
+ target.selectors.delete(key);
816
+ const family = withdraw(
817
+ { key: selector.family.key, type: `selector_family` },
818
+ store
819
+ );
820
+ family.subject.next({
821
+ type: `state_disposal`,
822
+ token: selectorToken
823
+ });
824
+ }
825
+ break;
826
+ case `readonly_selector`:
827
+ {
828
+ target.readonlySelectors.delete(key);
829
+ const family = withdraw(
830
+ { key: selector.family.key, type: `readonly_selector_family` },
831
+ store
832
+ );
833
+ family.subject.next({
834
+ type: `state_disposal`,
835
+ token: selectorToken
836
+ });
837
+ }
838
+ break;
839
+ }
840
+ target.valueMap.delete(key);
841
+ target.selectorAtoms.delete(key);
842
+ const downstreamTokens = target.selectorGraph.getRelationEntries({ upstreamSelectorKey: key }).filter(([_, { source }]) => source === key).map(
843
+ ([downstreamSelectorKey]) => target.selectors.get(downstreamSelectorKey) ?? target.readonlySelectors.get(downstreamSelectorKey)
844
+ );
845
+ for (const downstreamToken of downstreamTokens) {
846
+ if (downstreamToken) {
847
+ disposeSelector(downstreamToken, store);
848
+ }
849
+ }
850
+ target.selectorGraph.delete(key);
851
+ store.logger.info(`\u{1F525}`, selectorToken.type, key, `deleted`);
852
+ if (isChildStore(target) && target.transactionMeta.phase === `building`) {
853
+ target.transactionMeta.update.updates.push({
854
+ type: `state_disposal`,
855
+ token: selectorToken
856
+ });
857
+ } else {
858
+ store.on.selectorDisposal.next(selectorToken);
859
+ }
860
+ }
861
+ }
862
+
863
+ // internal/src/families/create-readonly-selector-family.ts
864
+ function createReadonlySelectorFamily(options, store, internalRoles) {
865
+ const familyToken = {
866
+ key: options.key,
867
+ type: `readonly_selector_family`
868
+ };
869
+ throwInCaseOfConflictingFamily(familyToken, store);
870
+ const subject = new Subject();
871
+ const familyFunction = (key) => {
872
+ const subKey = stringifyJson(key);
873
+ const family = { key: options.key, subKey };
874
+ const fullKey = `${options.key}(${subKey})`;
875
+ const target = newest(store);
876
+ const token = createReadonlySelector(
877
+ {
878
+ key: fullKey,
879
+ get: options.get(key)
880
+ },
881
+ family,
882
+ target
883
+ );
884
+ subject.next({ type: `state_creation`, token });
885
+ return token;
886
+ };
887
+ const readonlySelectorFamily = Object.assign(familyFunction, familyToken, {
888
+ subject,
889
+ install: (s) => createReadonlySelectorFamily(options, s),
890
+ internalRoles
891
+ });
892
+ store.families.set(options.key, readonlySelectorFamily);
893
+ return familyToken;
894
+ }
895
+ function createWritableSelectorFamily(options, store, internalRoles) {
896
+ const familyToken = {
897
+ key: options.key,
898
+ type: `selector_family`
899
+ };
900
+ throwInCaseOfConflictingFamily(familyToken, store);
901
+ const subject = new Subject();
902
+ const familyFunction = (key) => {
903
+ const subKey = stringifyJson(key);
904
+ const family = { key: options.key, subKey };
905
+ const fullKey = `${options.key}(${subKey})`;
906
+ const target = newest(store);
907
+ const token = createWritableSelector(
908
+ {
909
+ key: fullKey,
910
+ get: options.get(key),
911
+ set: options.set(key)
912
+ },
913
+ family,
914
+ target
915
+ );
916
+ subject.next({ type: `state_creation`, token });
917
+ return token;
918
+ };
919
+ const selectorFamily = Object.assign(familyFunction, familyToken, {
920
+ subject,
921
+ install: (s) => createWritableSelectorFamily(options, s),
922
+ internalRoles
923
+ });
924
+ store.families.set(options.key, selectorFamily);
925
+ return familyToken;
926
+ }
927
+
928
+ // internal/src/families/create-selector-family.ts
929
+ function createSelectorFamily(options, store) {
930
+ const isWritable = `set` in options;
931
+ if (isWritable) {
932
+ return createWritableSelectorFamily(options, store);
933
+ }
934
+ return createReadonlySelectorFamily(options, store);
935
+ }
936
+
937
+ // internal/src/molecule/dispose-molecule.ts
938
+ function disposeMolecule(token, store) {
939
+ let molecule;
940
+ try {
941
+ molecule = withdraw(token, store);
942
+ } catch (thrown) {
943
+ if (thrown instanceof Error) {
944
+ store.logger.error(
945
+ `\u{1F41E}`,
946
+ `molecule`,
947
+ JSON.stringify(token.key),
948
+ `Failed to dispose molecule, because it was not found in the store.`,
949
+ thrown.message
950
+ );
951
+ }
952
+ return;
953
+ }
954
+ const { family } = token;
955
+ const context = [];
956
+ for (const above of molecule.above.values()) {
957
+ context.push(deposit(above));
958
+ }
959
+ const values = [];
960
+ for (const stateToken of molecule.tokens.values()) {
961
+ const tokenFamily = stateToken.family;
962
+ values.push([tokenFamily.key, store.valueMap.get(stateToken.key)]);
963
+ }
964
+ if (family) {
965
+ const Formula = withdraw(family, store);
966
+ const disposalEvent = {
967
+ type: `molecule_disposal`,
968
+ token,
969
+ family,
970
+ context,
971
+ values
972
+ };
973
+ if (token.family) {
974
+ disposalEvent.family = token.family;
975
+ }
976
+ for (const state of molecule.tokens.values()) {
977
+ disposeFromStore(state, store);
978
+ }
979
+ for (const child of molecule.below.values()) {
980
+ if (child.family?.dependsOn === `all`) {
981
+ disposeMolecule(child, store);
982
+ } else {
983
+ child.above.delete(molecule.stringKey);
984
+ if (child.above.size === 0) {
985
+ disposeMolecule(child, store);
986
+ }
987
+ }
988
+ }
989
+ molecule.below.clear();
990
+ const isTransaction = isChildStore(store) && store.transactionMeta.phase === `building`;
991
+ if (isTransaction) {
992
+ store.transactionMeta.update.updates.push(disposalEvent);
993
+ } else {
994
+ Formula.subject.next(disposalEvent);
995
+ }
996
+ store.molecules.delete(molecule.stringKey);
997
+ }
998
+ for (const join of molecule.joins.values()) {
999
+ join.molecules.delete(molecule.stringKey);
1000
+ }
1001
+ for (const parent of molecule.above.values()) {
1002
+ parent.below.delete(molecule.stringKey);
1003
+ }
1004
+ }
1005
+
1006
+ // internal/src/families/init-family-member.ts
1007
+ function initFamilyMemberInStore(token, key, store) {
1008
+ const familyKey = token.key;
1009
+ const family = store.families.get(familyKey);
1010
+ if (family === void 0) {
1011
+ throw new NotFoundError(token, store);
1012
+ }
1013
+ const state = family(key);
1014
+ const target = newest(store);
1015
+ if (state.family && target.moleculeInProgress === null) {
1016
+ if (isRootStore(target)) {
1017
+ switch (state.type) {
1018
+ case `atom`:
1019
+ case `mutable_atom`:
1020
+ store.on.atomCreation.next(state);
1021
+ break;
1022
+ case `selector`:
1023
+ case `readonly_selector`:
1024
+ store.on.selectorCreation.next(state);
1025
+ break;
1026
+ }
1027
+ } else if (isChildStore(target) && target.on.transactionApplying.state === null) {
1028
+ target.transactionMeta.update.updates.push({
1029
+ type: `state_creation`,
1030
+ token: state
1031
+ });
1032
+ }
1033
+ }
1034
+ return state;
1035
+ }
1036
+ function seekInStore(token, key, store) {
1037
+ const subKey = stringifyJson(key);
1038
+ const fullKey = `${token.key}(${subKey})`;
1039
+ const target = newest(store);
1040
+ let state;
1041
+ switch (token.type) {
1042
+ case `atom_family`:
1043
+ case `mutable_atom_family`:
1044
+ state = target.atoms.get(fullKey);
1045
+ break;
1046
+ case `selector_family`:
1047
+ state = target.selectors.get(fullKey);
1048
+ break;
1049
+ case `readonly_selector_family`:
1050
+ state = target.readonlySelectors.get(fullKey);
1051
+ break;
1052
+ case `molecule_family`:
1053
+ state = target.molecules.get(stringifyJson(key));
1054
+ if (state) {
1055
+ return deposit(state);
1056
+ }
1057
+ }
1058
+ if (state) {
1059
+ return deposit(state);
1060
+ }
1061
+ return state;
1062
+ }
1063
+
1064
+ // internal/src/families/find-in-store.ts
1065
+ function findInStore(token, key, store) {
1066
+ if (store.config.lifespan === `immortal`) {
1067
+ throw new Error(
1068
+ `Do not use \`find\` or \`findState\` in an immortal store. Prefer \`seek\` or \`seekState\`.`
1069
+ );
1070
+ }
1071
+ let state = seekInStore(token, key, store);
1072
+ if (state) {
1073
+ return state;
1074
+ }
1075
+ state = initFamilyMemberInStore(token, key, store);
1076
+ return state;
1077
+ }
1078
+
1079
+ // internal/src/families/dispose-from-store.ts
1080
+ function disposeFromStore(...params) {
1081
+ let token;
1082
+ let store;
1083
+ if (params.length === 2) {
1084
+ token = params[0];
1085
+ store = params[1];
1086
+ } else {
1087
+ const family = params[0];
1088
+ const key = params[1];
1089
+ store = params[2];
1090
+ const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
1091
+ if (!maybeToken) {
1092
+ throw new NotFoundError(family, key, store);
1093
+ }
1094
+ token = maybeToken;
1095
+ }
1096
+ switch (token.type) {
1097
+ case `atom`:
1098
+ case `mutable_atom`:
1099
+ disposeAtom(token, store);
1100
+ break;
1101
+ case `selector`:
1102
+ case `readonly_selector`:
1103
+ disposeSelector(token, store);
1104
+ break;
1105
+ case `molecule`:
1106
+ disposeMolecule(token, store);
1107
+ break;
1108
+ }
1109
+ }
1110
+
1111
+ // internal/src/set-state/set-into-store.ts
1112
+ function setIntoStore(...params) {
1113
+ let token;
1114
+ let value;
1115
+ let store;
1116
+ if (params.length === 3) {
1117
+ token = params[0];
1118
+ value = params[1];
1119
+ store = params[2];
1120
+ } else {
1121
+ const family = params[0];
1122
+ const key = params[1];
1123
+ value = params[2];
1124
+ store = params[3];
1125
+ const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
1126
+ if (!maybeToken) {
1127
+ throw new NotFoundError(family, key, store);
1128
+ }
1129
+ token = maybeToken;
1130
+ }
1131
+ const rejectionTime = openOperation(token, store);
1132
+ if (rejectionTime) {
1133
+ const unsubscribe = store.on.operationClose.subscribe(
1134
+ `waiting to set "${token.key}" at T-${rejectionTime}`,
1135
+ () => {
1136
+ unsubscribe();
1137
+ store.logger.info(
1138
+ `\u{1F7E2}`,
1139
+ token.type,
1140
+ token.key,
1141
+ `resuming deferred setState from T-${rejectionTime}`
1142
+ );
1143
+ setIntoStore(token, value, store);
1144
+ }
1145
+ );
1146
+ return;
1147
+ }
1148
+ const state = withdraw(token, store);
1149
+ setAtomOrSelector(state, value, store);
1150
+ closeOperation(store);
1151
+ }
1152
+
1153
+ // internal/src/ingest-updates/ingest-atom-update.ts
1154
+ function ingestAtomUpdate(applying, atomUpdate, store) {
1155
+ const { key, newValue, oldValue } = atomUpdate;
1156
+ const value = applying === `newValue` ? newValue : oldValue;
1157
+ const token = { key, type: `atom` };
1158
+ if (atomUpdate.family) {
1159
+ Object.assign(token, { family: atomUpdate.family });
1160
+ }
1161
+ setIntoStore(token, value, store);
1162
+ }
1163
+
1164
+ // internal/src/molecule/create-molecule-family.ts
1165
+ function createMoleculeFamily(options, store) {
1166
+ const subject = new Subject();
1167
+ const token = {
1168
+ type: `molecule_family`,
1169
+ key: options.key,
1170
+ dependsOn: options.dependsOn ?? `all`
1171
+ };
1172
+ const family = {
1173
+ ...token,
1174
+ subject,
1175
+ new: options.new
1176
+ };
1177
+ store.moleculeFamilies.set(options.key, family);
1178
+ return token;
1179
+ }
1180
+
1181
+ // internal/src/molecule/grow-molecule-in-store.ts
1182
+ function growMoleculeInStore(molecule, family, store) {
1183
+ const stateToken = initFamilyMemberInStore(family, molecule.key, store);
1184
+ molecule.tokens.set(stateToken.key, stateToken);
1185
+ const isTransaction = isChildStore(store) && store.transactionMeta.phase === `building`;
1186
+ const moleculeInProgress = store.moleculeInProgress === molecule.key;
1187
+ if (!isTransaction && !moleculeInProgress) {
1188
+ molecule.subject.next({ type: `state_creation`, token: stateToken });
1189
+ }
1190
+ return stateToken;
1191
+ }
1192
+
1193
+ // internal/src/get-environment-data.ts
1194
+ function getEnvironmentData(store) {
1195
+ return {
1196
+ store
1197
+ };
1198
+ }
1199
+ var Molecule = class {
1200
+ constructor(ctx, key, family) {
1201
+ this.key = key;
1202
+ this.stringKey = stringifyJson(key);
1203
+ if (family) {
1204
+ this.family = family;
1205
+ }
1206
+ if (ctx) {
1207
+ if (Array.isArray(ctx)) {
1208
+ for (const molecule of ctx) {
1209
+ this.above.set(molecule.stringKey, molecule);
1210
+ }
1211
+ } else {
1212
+ this.above.set(ctx.stringKey, ctx);
1213
+ }
1214
+ }
1215
+ }
1216
+ type = `molecule`;
1217
+ stringKey;
1218
+ family;
1219
+ subject = new Subject();
1220
+ tokens = /* @__PURE__ */ new Map();
1221
+ above = /* @__PURE__ */ new Map();
1222
+ below = /* @__PURE__ */ new Map();
1223
+ joins = /* @__PURE__ */ new Map();
1224
+ instance;
1225
+ };
1226
+
1227
+ // internal/src/molecule/make-molecule-in-store.ts
1228
+ function capitalize2(string) {
1229
+ return string[0].toUpperCase() + string.slice(1);
1230
+ }
1231
+ function makeMoleculeInStore(store, context, familyToken, key, ...params) {
1232
+ const rootStore = eldest(store);
1233
+ const target = newest(store);
1234
+ const stringKey = stringifyJson(key);
1235
+ target.moleculeInProgress = stringKey;
1236
+ const contextArray = Array.isArray(context) ? context : [context];
1237
+ const owners = contextArray.map((ctx) => {
1238
+ if (ctx instanceof Molecule) {
1239
+ return ctx;
1240
+ }
1241
+ const ctxStringKey = stringifyJson(ctx.key);
1242
+ const molecule2 = store.molecules.get(ctxStringKey);
1243
+ if (!molecule2) {
1244
+ throw new Error(
1245
+ `Molecule ${ctxStringKey} not found in store "${store.config.name}"`
1246
+ );
1247
+ }
1248
+ return molecule2;
1249
+ });
1250
+ const molecule = new Molecule(owners, key, familyToken);
1251
+ target.molecules.set(stringKey, molecule);
1252
+ for (const owner of owners) {
1253
+ owner.below.set(molecule.stringKey, molecule);
1254
+ }
1255
+ const toolkit = {
1256
+ get: (...ps) => getFromStore(...ps, newest(rootStore)),
1257
+ set: (...ps) => {
1258
+ setIntoStore(...ps, newest(rootStore));
1259
+ },
1260
+ seek: (t, k) => seekInStore(t, k, newest(rootStore)),
1261
+ json: (t) => getJsonToken(t, newest(rootStore)),
1262
+ run: (t, i = arbitrary()) => actUponStore(t, i, newest(store)),
1263
+ make: (ctx, f, k, ...args) => makeMoleculeInStore(newest(rootStore), ctx, f, k, ...args),
1264
+ dispose: (t) => {
1265
+ disposeFromStore(t, newest(rootStore));
1266
+ },
1267
+ env: () => getEnvironmentData(newest(rootStore)),
1268
+ bond: (token2, maybeRole) => {
1269
+ if (token2.type === `join`) {
1270
+ const { as: role } = maybeRole;
1271
+ const join = getJoin(token2, rootStore);
1272
+ join.molecules.set(stringKey, molecule);
1273
+ molecule.joins.set(token2.key, join);
1274
+ const unsubFromFamily = family.subject.subscribe(
1275
+ `join:${token2.key}-${stringKey}`,
1276
+ (event) => {
1277
+ if (event.type === `molecule_disposal` && stringifyJson(event.token.key) === stringKey) {
1278
+ unsubFromFamily();
1279
+ join.molecules.delete(stringKey);
1280
+ }
1281
+ }
1282
+ );
1283
+ if (role === null) {
1284
+ return;
1285
+ }
1286
+ const otherRole = token2.a === role ? token2.b : token2.a;
1287
+ const relations = findRelations(token2, key);
1288
+ const relatedKeys = relations[`${otherRole}KeysOf${capitalize2(role)}`];
1289
+ const relatedEntries = relations[`${otherRole}EntriesOf${capitalize2(role)}`];
1290
+ let tokens = { relatedKeys };
1291
+ if (relatedEntries) {
1292
+ tokens = Object.assign(tokens, { relatedEntries });
1293
+ }
1294
+ return tokens;
1295
+ }
1296
+ return growMoleculeInStore(
1297
+ molecule,
1298
+ withdraw(token2, rootStore),
1299
+ newest(rootStore)
1300
+ );
1301
+ },
1302
+ claim: (below, options) => {
1303
+ const { exclusive } = options;
1304
+ const belowMolecule = newest(store).molecules.get(stringifyJson(below.key));
1305
+ if (belowMolecule) {
1306
+ if (exclusive) {
1307
+ for (const value of belowMolecule.above.values()) {
1308
+ value.below.delete(belowMolecule.stringKey);
1309
+ }
1310
+ belowMolecule.above.clear();
1311
+ belowMolecule.above.set(molecule.stringKey, molecule);
1312
+ molecule.below.set(belowMolecule.stringKey, belowMolecule);
1313
+ } else {
1314
+ belowMolecule.above.set(molecule.stringKey, molecule);
1315
+ molecule.below.set(belowMolecule.stringKey, belowMolecule);
1316
+ }
1317
+ }
1318
+ },
1319
+ spawn: (f, k, ...p) => makeMoleculeInStore(
1320
+ newest(store),
1321
+ [molecule],
1322
+ withdraw(f, store),
1323
+ k,
1324
+ ...p
1325
+ )
1326
+ };
1327
+ const family = withdraw(familyToken, store);
1328
+ const Constructor = family.new;
1329
+ molecule.instance = new Constructor(toolkit, key, ...params);
1330
+ const token = {
1331
+ type: `molecule`,
1332
+ key,
1333
+ family: familyToken
1334
+ };
1335
+ const update = {
1336
+ type: `molecule_creation`,
1337
+ token,
1338
+ family: familyToken,
1339
+ context: contextArray,
1340
+ params
1341
+ };
1342
+ if (isRootStore(target)) {
1343
+ family.subject.next(update);
1344
+ } else if (isChildStore(target) && target.on.transactionApplying.state === null) {
1345
+ target.transactionMeta.update.updates.push(update);
1346
+ }
1347
+ target.moleculeInProgress = null;
1348
+ return token;
1349
+ }
1350
+
1351
+ // internal/src/ingest-updates/ingest-creation-disposal.ts
1352
+ function ingestCreationEvent(update, applying, store) {
1353
+ switch (applying) {
1354
+ case `newValue`: {
1355
+ createInStore(update.token, store);
1356
+ break;
1357
+ }
1358
+ case `oldValue`: {
1359
+ disposeFromStore(update.token, store);
1360
+ break;
1361
+ }
1362
+ }
1363
+ }
1364
+ function ingestDisposalEvent(update, applying, store) {
1365
+ switch (applying) {
1366
+ case `newValue`: {
1367
+ disposeFromStore(update.token, store);
1368
+ break;
1369
+ }
1370
+ case `oldValue`: {
1371
+ createInStore(update.token, store);
1372
+ store.valueMap.set(update.token.key, update.value);
1373
+ break;
1374
+ }
1375
+ }
1376
+ }
1377
+ function createInStore(token, store) {
1378
+ if (token.family) {
1379
+ const family = store.families.get(token.family.key);
1380
+ if (family) {
1381
+ const molecule = store.molecules.get(token.family.subKey);
1382
+ if (molecule) {
1383
+ growMoleculeInStore(molecule, family, store);
1384
+ return;
1385
+ }
1386
+ if (store.config.lifespan === `immortal`) {
1387
+ throw new Error(`No molecule found for key "${token.family.subKey}"`);
1388
+ }
1389
+ initFamilyMemberInStore(family, parseJson(token.family.subKey), store);
1390
+ }
1391
+ }
1392
+ }
1393
+ function ingestMoleculeCreationEvent(update, applying, store) {
1394
+ switch (applying) {
1395
+ case `newValue`:
1396
+ makeMoleculeInStore(
1397
+ store,
1398
+ update.context,
1399
+ update.family,
1400
+ update.token.key,
1401
+ ...update.params
1402
+ );
1403
+ break;
1404
+ case `oldValue`:
1405
+ disposeFromStore(update.token, store);
1406
+ break;
1407
+ }
1408
+ }
1409
+ function ingestMoleculeDisposalEvent(update, applying, store) {
1410
+ switch (applying) {
1411
+ case `newValue`:
1412
+ disposeFromStore(update.token, store);
1413
+ break;
1414
+ case `oldValue`:
1415
+ {
1416
+ const moleculeToken = makeMoleculeInStore(
1417
+ store,
1418
+ update.context,
1419
+ update.family,
1420
+ update.token.key
1421
+ );
1422
+ for (const [familyKey, value] of update.values) {
1423
+ const memberKey = `${familyKey}(${stringifyJson(moleculeToken.key)})`;
1424
+ const molecule = withdraw(moleculeToken, store);
1425
+ const alreadyCreated = molecule.tokens.has(memberKey);
1426
+ const family = store.families.get(familyKey);
1427
+ if (family && !alreadyCreated) {
1428
+ growMoleculeInStore(molecule, family, store);
1429
+ }
1430
+ store.valueMap.set(memberKey, value);
1431
+ }
1432
+ }
1433
+ break;
1434
+ }
1435
+ }
1436
+
1437
+ // internal/src/ingest-updates/ingest-selector-update.ts
1438
+ function ingestSelectorUpdate(applying, selectorUpdate, store) {
1439
+ const updates = applying === `newValue` ? selectorUpdate.atomUpdates : selectorUpdate.atomUpdates.toReversed();
1440
+ for (const atomUpdate of updates) {
1441
+ ingestAtomUpdate(applying, atomUpdate, store);
1442
+ }
1443
+ }
1444
+
1445
+ // internal/src/ingest-updates/ingest-transaction-update.ts
1446
+ function ingestTransactionUpdate(applying, transactionUpdate, store) {
1447
+ const updates = applying === `newValue` ? transactionUpdate.updates : [...transactionUpdate.updates].reverse();
1448
+ for (const updateFromTransaction of updates) {
1449
+ switch (updateFromTransaction.type) {
1450
+ case `atom_update`:
1451
+ case `selector_update`:
1452
+ ingestAtomUpdate(applying, updateFromTransaction, store);
1453
+ break;
1454
+ case `state_creation`:
1455
+ ingestCreationEvent(updateFromTransaction, applying, store);
1456
+ break;
1457
+ case `state_disposal`:
1458
+ ingestDisposalEvent(updateFromTransaction, applying, store);
1459
+ break;
1460
+ case `molecule_creation`:
1461
+ ingestMoleculeCreationEvent(updateFromTransaction, applying, store);
1462
+ break;
1463
+ case `molecule_disposal`:
1464
+ ingestMoleculeDisposalEvent(updateFromTransaction, applying, store);
1465
+ break;
1466
+ case `transaction_update`:
1467
+ ingestTransactionUpdate(applying, updateFromTransaction, store);
1468
+ break;
1469
+ }
1470
+ }
1471
+ }
1472
+
1473
+ // internal/src/transaction/set-epoch-number.ts
1474
+ function setEpochNumberOfContinuity(continuityKey, newEpoch, store) {
1475
+ const isRoot = isRootStore(store);
1476
+ if (isRoot && continuityKey) {
1477
+ store.transactionMeta.epoch.set(continuityKey, newEpoch);
1478
+ }
1479
+ }
1480
+ function setEpochNumberOfAction(transactionKey, newEpoch, store) {
1481
+ const isRoot = isRootStore(store);
1482
+ if (!isRoot) {
1483
+ return;
1484
+ }
1485
+ const continuityKey = store.transactionMeta.actionContinuities.getRelatedKey(transactionKey);
1486
+ if (continuityKey !== void 0) {
1487
+ store.transactionMeta.epoch.set(continuityKey, newEpoch);
1488
+ }
1489
+ }
1490
+
1491
+ // internal/src/transaction/apply-transaction.ts
1492
+ var applyTransaction = (output, store) => {
1493
+ const child = newest(store);
1494
+ const { parent } = child;
1495
+ if (parent === null || !isChildStore(child) || child.transactionMeta?.phase !== `building`) {
1496
+ store.logger.warn(
1497
+ `\u{1F41E}`,
1498
+ `transaction`,
1499
+ `???`,
1500
+ `applyTransaction called outside of a transaction. This is probably a bug in AtomIO.`
1501
+ );
1502
+ return;
1503
+ }
1504
+ child.transactionMeta.phase = `applying`;
1505
+ child.transactionMeta.update.output = output;
1506
+ parent.child = null;
1507
+ parent.on.transactionApplying.next(child.transactionMeta);
1508
+ const { updates } = child.transactionMeta.update;
1509
+ store.logger.info(
1510
+ `\u{1F6C4}`,
1511
+ `transaction`,
1512
+ child.transactionMeta.update.key,
1513
+ `Applying transaction with ${updates.length} updates:`,
1514
+ updates
1515
+ );
1516
+ ingestTransactionUpdate(`newValue`, child.transactionMeta.update, parent);
1517
+ if (isRootStore(parent)) {
1518
+ setEpochNumberOfAction(
1519
+ child.transactionMeta.update.key,
1520
+ child.transactionMeta.update.epoch,
1521
+ parent
1522
+ );
1523
+ const myTransaction = withdraw(
1524
+ { key: child.transactionMeta.update.key, type: `transaction` },
1525
+ store
1526
+ );
1527
+ myTransaction?.subject.next(child.transactionMeta.update);
1528
+ store.logger.info(
1529
+ `\u{1F6EC}`,
1530
+ `transaction`,
1531
+ child.transactionMeta.update.key,
1532
+ `Finished applying transaction.`
1533
+ );
1534
+ } else if (isChildStore(parent)) {
1535
+ parent.transactionMeta.update.updates.push(child.transactionMeta.update);
1536
+ }
1537
+ parent.on.transactionApplying.next(null);
1538
+ };
1539
+
1540
+ // internal/src/transaction/assign-transaction-to-continuity.ts
1541
+ function assignTransactionToContinuity(continuityKey, transactionKey, store) {
1542
+ const isRoot = isRootStore(store);
1543
+ if (!isRoot) {
1544
+ return;
1545
+ }
1546
+ const { epoch, actionContinuities } = store.transactionMeta;
1547
+ actionContinuities.set(continuityKey, transactionKey);
1548
+ if (!epoch.has(continuityKey)) {
1549
+ epoch.set(continuityKey, -1);
1550
+ }
1551
+ }
1552
+
1553
+ // internal/src/lazy-map.ts
1554
+ var LazyMap = class extends Map {
1555
+ constructor(source) {
1556
+ super();
1557
+ this.source = source;
1558
+ }
1559
+ deleted = /* @__PURE__ */ new Set();
1560
+ get(key) {
1561
+ const has = super.has(key);
1562
+ if (has) {
1563
+ return super.get(key);
1564
+ }
1565
+ if (!this.deleted.has(key) && this.source.has(key)) {
1566
+ const value = this.source.get(key);
1567
+ return value;
1568
+ }
1569
+ return void 0;
1570
+ }
1571
+ set(key, value) {
1572
+ this.deleted.delete(key);
1573
+ return super.set(key, value);
1574
+ }
1575
+ hasOwn(key) {
1576
+ return super.has(key);
1577
+ }
1578
+ has(key) {
1579
+ return !this.deleted.has(key) && (super.has(key) || this.source.has(key));
1580
+ }
1581
+ delete(key) {
1582
+ this.deleted.add(key);
1583
+ return super.delete(key);
1584
+ }
1585
+ };
1586
+
1587
+ // internal/src/transaction/build-transaction.ts
1588
+ var buildTransaction = (key, params, store, id) => {
1589
+ const parent = newest(store);
1590
+ const childBase = {
1591
+ parent,
1592
+ child: null,
1593
+ on: parent.on,
1594
+ loggers: parent.loggers,
1595
+ logger: parent.logger,
1596
+ config: parent.config,
1597
+ atoms: new LazyMap(parent.atoms),
1598
+ atomsThatAreDefault: new Set(parent.atomsThatAreDefault),
1599
+ families: new LazyMap(parent.families),
1600
+ operation: { open: false },
1601
+ readonlySelectors: new LazyMap(parent.readonlySelectors),
1602
+ timelines: new LazyMap(parent.timelines),
1603
+ timelineTopics: new Junction(parent.timelineTopics.toJSON()),
1604
+ trackers: /* @__PURE__ */ new Map(),
1605
+ transactions: new LazyMap(parent.transactions),
1606
+ selectorAtoms: new Junction(parent.selectorAtoms.toJSON()),
1607
+ selectorGraph: new Junction(parent.selectorGraph.toJSON(), {
1608
+ makeContentKey: (...keys) => keys.sort().join(`:`)
1609
+ }),
1610
+ selectors: new LazyMap(parent.selectors),
1611
+ valueMap: new LazyMap(parent.valueMap),
1612
+ molecules: new LazyMap(parent.molecules),
1613
+ moleculeFamilies: new LazyMap(parent.moleculeFamilies),
1614
+ moleculeInProgress: parent.moleculeInProgress,
1615
+ miscResources: new LazyMap(parent.miscResources)
1616
+ };
1617
+ const epoch = getEpochNumberOfAction(key, store);
1618
+ const transactionMeta = {
1619
+ phase: `building`,
1620
+ update: {
1621
+ type: `transaction_update`,
1622
+ key,
1623
+ id,
1624
+ epoch: epoch === void 0 ? Number.NaN : epoch + 1,
1625
+ updates: [],
1626
+ params,
1627
+ output: void 0
1628
+ },
1629
+ toolkit: {
1630
+ get: (...ps) => getFromStore(...ps, child),
1631
+ set: (...ps) => {
1632
+ setIntoStore(...ps, child);
1633
+ },
1634
+ run: (token, identifier = arbitrary()) => actUponStore(token, identifier, child),
1635
+ find: (token, k) => findInStore(token, k, child),
1636
+ seek: (token, k) => seekInStore(token, k, child),
1637
+ json: (token) => getJsonToken(token, child),
1638
+ make: (context, family, k, ...args) => makeMoleculeInStore(child, context, family, k, ...args),
1639
+ dispose: (...ps) => {
1640
+ disposeFromStore(...ps, child);
1641
+ },
1642
+ env: () => getEnvironmentData(child)
1643
+ }
1644
+ };
1645
+ const child = Object.assign(childBase, {
1646
+ transactionMeta
1647
+ });
1648
+ parent.child = child;
1649
+ store.logger.info(
1650
+ `\u{1F6EB}`,
1651
+ `transaction`,
1652
+ key,
1653
+ `Building transaction with params:`,
1654
+ params
1655
+ );
1656
+ return child;
1657
+ };
1658
+
1659
+ // internal/src/transaction/create-transaction.ts
1660
+ function createTransaction(options, store) {
1661
+ const newTransaction = {
1662
+ key: options.key,
1663
+ type: `transaction`,
1664
+ run: (params, id) => {
1665
+ const childStore = buildTransaction(options.key, params, store, id);
1666
+ try {
1667
+ const target2 = newest(store);
1668
+ const { toolkit } = childStore.transactionMeta;
1669
+ const output = options.do(toolkit, ...params);
1670
+ applyTransaction(output, target2);
1671
+ return output;
1672
+ } catch (thrown) {
1673
+ abortTransaction(target);
1674
+ store.logger.warn(`\u{1F4A5}`, `transaction`, options.key, `caught:`, thrown);
1675
+ throw thrown;
1676
+ }
1677
+ },
1678
+ install: (s) => createTransaction(options, s),
1679
+ subject: new Subject()
1680
+ };
1681
+ const target = newest(store);
1682
+ target.transactions.set(newTransaction.key, newTransaction);
1683
+ const token = deposit(newTransaction);
1684
+ store.on.transactionCreation.next(token);
1685
+ return token;
1686
+ }
1687
+
1688
+ // internal/src/transaction/get-epoch-number.ts
1689
+ function getContinuityKey(transactionKey, store) {
1690
+ const isRoot = isRootStore(store);
1691
+ const continuity = isRoot ? store.transactionMeta.actionContinuities.getRelatedKey(transactionKey) : void 0;
1692
+ return continuity;
1693
+ }
1694
+ function getEpochNumberOfContinuity(continuityKey, store) {
1695
+ const isRoot = isRootStore(store);
1696
+ const epoch = isRoot && continuityKey ? store.transactionMeta.epoch.get(continuityKey) : void 0;
1697
+ return epoch;
1698
+ }
1699
+ function getEpochNumberOfAction(transactionKey, store) {
1700
+ const isRoot = isRootStore(store);
1701
+ const continuity = isRoot ? store.transactionMeta.actionContinuities.getRelatedKey(transactionKey) : void 0;
1702
+ const epoch = isRoot && continuity !== void 0 ? store.transactionMeta.epoch.get(continuity) : void 0;
1703
+ return epoch;
1704
+ }
1705
+
1706
+ // internal/src/transaction/index.ts
1707
+ var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
1708
+
1709
+ // internal/src/store/store.ts
1710
+ var Store = class {
1711
+ parent = null;
1712
+ child = null;
1713
+ valueMap = /* @__PURE__ */ new Map();
1714
+ atoms = /* @__PURE__ */ new Map();
1715
+ selectors = /* @__PURE__ */ new Map();
1716
+ readonlySelectors = /* @__PURE__ */ new Map();
1717
+ atomsThatAreDefault = /* @__PURE__ */ new Set();
1718
+ selectorAtoms = new Junction({
1719
+ between: [`selectorKey`, `atomKey`],
1720
+ cardinality: `n:n`
1721
+ });
1722
+ selectorGraph = new Junction(
1723
+ {
1724
+ between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
1725
+ cardinality: `n:n`
1726
+ },
1727
+ {
1728
+ makeContentKey: (...keys) => keys.sort().join(`:`)
1729
+ }
1730
+ );
1731
+ trackers = /* @__PURE__ */ new Map();
1732
+ families = /* @__PURE__ */ new Map();
1733
+ transactions = /* @__PURE__ */ new Map();
1734
+ transactionMeta = {
1735
+ epoch: /* @__PURE__ */ new Map(),
1736
+ actionContinuities: new Junction({
1737
+ between: [`continuity`, `action`],
1738
+ cardinality: `1:n`
1739
+ })
1740
+ };
1741
+ timelines = /* @__PURE__ */ new Map();
1742
+ timelineTopics = new Junction({
1743
+ between: [`timelineKey`, `topicKey`],
1744
+ cardinality: `1:n`
1745
+ });
1746
+ molecules = /* @__PURE__ */ new Map();
1747
+ moleculeFamilies = /* @__PURE__ */ new Map();
1748
+ moleculeInProgress = null;
1749
+ miscResources = /* @__PURE__ */ new Map();
1750
+ on = {
1751
+ atomCreation: new Subject(),
1752
+ atomDisposal: new Subject(),
1753
+ selectorCreation: new Subject(),
1754
+ selectorDisposal: new Subject(),
1755
+ timelineCreation: new Subject(),
1756
+ transactionCreation: new Subject(),
1757
+ transactionApplying: new StatefulSubject(
1758
+ null
1759
+ ),
1760
+ operationClose: new Subject(),
1761
+ moleculeCreationStart: new Subject(),
1762
+ moleculeCreationDone: new Subject(),
1763
+ moleculeDisposal: new Subject()
1764
+ };
1765
+ operation = { open: false };
1766
+ config = {
1767
+ name: `IMPLICIT_STORE`,
1768
+ lifespan: `ephemeral`
1769
+ };
1770
+ loggers = [
1771
+ new AtomIOLogger(`warn`, (_, __, key) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`))
1772
+ ];
1773
+ logger = {
1774
+ error: (...messages) => {
1775
+ for (const logger of this.loggers) logger.error(...messages);
1776
+ },
1777
+ info: (...messages) => {
1778
+ for (const logger of this.loggers) logger.info(...messages);
1779
+ },
1780
+ warn: (...messages) => {
1781
+ for (const logger of this.loggers) logger.warn(...messages);
1782
+ }
1783
+ };
1784
+ constructor(config, store = null) {
1785
+ this.config = {
1786
+ ...store?.config,
1787
+ ...config
1788
+ };
1789
+ if (store !== null) {
1790
+ this.valueMap = new Map(store?.valueMap);
1791
+ this.operation = { ...store?.operation };
1792
+ if (isRootStore(store)) {
1793
+ this.transactionMeta = {
1794
+ epoch: new Map(store?.transactionMeta.epoch),
1795
+ actionContinuities: new Junction(
1796
+ store?.transactionMeta.actionContinuities.toJSON()
1797
+ )
1798
+ };
1799
+ }
1800
+ for (const [, family] of store.families) {
1801
+ if (family.internalRoles?.includes(`mutable`) || family.internalRoles?.includes(`join`)) {
1802
+ continue;
1803
+ }
1804
+ family.install(this);
1805
+ }
1806
+ const mutableHelpers = /* @__PURE__ */ new Set();
1807
+ for (const [, atom] of store.atoms) {
1808
+ if (mutableHelpers.has(atom.key)) {
1809
+ continue;
1810
+ }
1811
+ atom.install(this);
1812
+ if (atom.type === `mutable_atom`) {
1813
+ const originalJsonToken = getJsonToken(atom, store);
1814
+ const originalUpdateToken = getUpdateToken(atom);
1815
+ mutableHelpers.add(originalJsonToken.key);
1816
+ mutableHelpers.add(originalUpdateToken.key);
1817
+ }
1818
+ }
1819
+ for (const [, selector] of store.readonlySelectors) {
1820
+ selector.install(this);
1821
+ }
1822
+ for (const [, selector] of store.selectors) {
1823
+ if (mutableHelpers.has(selector.key)) {
1824
+ continue;
1825
+ }
1826
+ selector.install(this);
1827
+ }
1828
+ for (const [, tx] of store.transactions) {
1829
+ tx.install(this);
1830
+ }
1831
+ for (const [, timeline] of store.timelines) {
1832
+ timeline.install(this);
1833
+ }
1834
+ }
1835
+ }
1836
+ };
1837
+ var IMPLICIT = {
1838
+ get STORE() {
1839
+ if (!globalThis.ATOM_IO_IMPLICIT_STORE) {
1840
+ globalThis.ATOM_IO_IMPLICIT_STORE = new Store({
1841
+ name: `IMPLICIT_STORE`,
1842
+ lifespan: `ephemeral`
1843
+ });
1844
+ }
1845
+ return globalThis.ATOM_IO_IMPLICIT_STORE;
1846
+ }
1847
+ };
1848
+ var clearStore = (store) => {
1849
+ const { config } = store;
1850
+ for (const disposable of store.miscResources.values()) {
1851
+ disposable[Symbol.dispose]();
1852
+ }
1853
+ Object.assign(store, new Store(config));
1854
+ store.config = config;
1855
+ };
1856
+ function withdraw(token, store) {
1857
+ let withdrawn;
1858
+ let target = store;
1859
+ while (target !== null) {
1860
+ switch (token.type) {
1861
+ case `atom`:
1862
+ case `mutable_atom`:
1863
+ withdrawn = target.atoms.get(token.key);
1864
+ break;
1865
+ case `selector`:
1866
+ withdrawn = target.selectors.get(token.key);
1867
+ break;
1868
+ case `readonly_selector`:
1869
+ withdrawn = target.readonlySelectors.get(token.key);
1870
+ break;
1871
+ case `atom_family`:
1872
+ case `mutable_atom_family`:
1873
+ case `selector_family`:
1874
+ case `readonly_selector_family`:
1875
+ withdrawn = target.families.get(token.key);
1876
+ break;
1877
+ case `timeline`:
1878
+ withdrawn = target.timelines.get(token.key);
1879
+ break;
1880
+ case `transaction`:
1881
+ withdrawn = target.transactions.get(token.key);
1882
+ break;
1883
+ case `molecule`:
1884
+ withdrawn = target.molecules.get(stringifyJson(token.key));
1885
+ break;
1886
+ case `molecule_family`:
1887
+ withdrawn = target.moleculeFamilies.get(token.key);
1888
+ break;
1889
+ }
1890
+ if (withdrawn) {
1891
+ return withdrawn;
1892
+ }
1893
+ target = target.child;
1894
+ }
1895
+ throw new NotFoundError(token, store);
1896
+ }
1897
+
1898
+ // internal/src/subscribe/recall-state.ts
1899
+ var recallState = (state, store) => {
1900
+ const target = newest(store);
1901
+ if (target.operation.open) {
1902
+ return target.operation.prev.get(state.key);
1903
+ }
1904
+ return target.valueMap.get(state.key);
1905
+ };
1906
+
1907
+ // internal/src/subscribe/subscribe-to-root-atoms.ts
1908
+ var subscribeToRootAtoms = (selector, store) => {
1909
+ const target = newest(store);
1910
+ const dependencySubscriptions = traceAllSelectorAtoms(selector, store).map(
1911
+ (atomKey) => {
1912
+ const atom = target.atoms.get(atomKey);
1913
+ if (atom === void 0) {
1914
+ throw new Error(
1915
+ `Atom "${atomKey}", a dependency of selector "${selector.key}", not found in store "${store.config.name}".`
1916
+ );
1917
+ }
1918
+ return atom.subject.subscribe(
1919
+ `${selector.type}:${selector.key}`,
1920
+ (atomChange) => {
1921
+ store.logger.info(
1922
+ `\u{1F4E2}`,
1923
+ selector.type,
1924
+ selector.key,
1925
+ `root`,
1926
+ atomKey,
1927
+ `went`,
1928
+ atomChange.oldValue,
1929
+ `->`,
1930
+ atomChange.newValue
1931
+ );
1932
+ const oldValue = recallState(selector, target);
1933
+ const newValue = readOrComputeValue(selector, target);
1934
+ store.logger.info(
1935
+ `\u2728`,
1936
+ selector.type,
1937
+ selector.key,
1938
+ `went`,
1939
+ oldValue,
1940
+ `->`,
1941
+ newValue
1942
+ );
1943
+ selector.subject.next({ newValue, oldValue });
1944
+ }
1945
+ );
1946
+ }
1947
+ );
1948
+ return dependencySubscriptions;
1949
+ };
1950
+
1951
+ // internal/src/subscribe/subscribe-to-state.ts
1952
+ function subscribeToState(token, handleUpdate, key, store) {
1953
+ function safelyHandleUpdate(update) {
1954
+ if (store.operation.open) {
1955
+ const unsubscribe2 = store.on.operationClose.subscribe(
1956
+ `state subscription ${key}`,
1957
+ () => {
1958
+ unsubscribe2();
1959
+ handleUpdate(update);
1960
+ }
1961
+ );
1962
+ } else {
1963
+ handleUpdate(update);
1964
+ }
1965
+ }
1966
+ const state = withdraw(token, store);
1967
+ store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
1968
+ const isSelector = state.type === `selector` || state.type === `readonly_selector`;
1969
+ let dependencyUnsubFunctions = null;
1970
+ let updateHandler = safelyHandleUpdate;
1971
+ if (isSelector) {
1972
+ dependencyUnsubFunctions = subscribeToRootAtoms(state, store);
1973
+ updateHandler = (update) => {
1974
+ if (dependencyUnsubFunctions) {
1975
+ dependencyUnsubFunctions.length = 0;
1976
+ dependencyUnsubFunctions.push(...subscribeToRootAtoms(state, store));
1977
+ }
1978
+ safelyHandleUpdate(update);
1979
+ };
1980
+ }
1981
+ const mainUnsubFunction = state.subject.subscribe(key, updateHandler);
1982
+ const unsubscribe = () => {
1983
+ store.logger.info(
1984
+ `\u{1F648}`,
1985
+ state.type,
1986
+ state.key,
1987
+ `Removing subscription "${key}"`
1988
+ );
1989
+ mainUnsubFunction();
1990
+ if (dependencyUnsubFunctions) {
1991
+ for (const unsubFromDependency of dependencyUnsubFunctions) {
1992
+ unsubFromDependency();
1993
+ }
1994
+ }
1995
+ };
1996
+ return unsubscribe;
1997
+ }
1998
+
1999
+ // internal/src/subscribe/subscribe-to-timeline.ts
2000
+ var subscribeToTimeline = (token, handleUpdate, key, store) => {
2001
+ const tl = withdraw(token, store);
2002
+ store.logger.info(`\u{1F440}`, `timeline`, token.key, `Adding subscription "${key}"`);
2003
+ const unsubscribe = tl.subject.subscribe(key, handleUpdate);
2004
+ return () => {
2005
+ store.logger.info(
2006
+ `\u{1F648}`,
2007
+ `timeline`,
2008
+ token.key,
2009
+ `Removing subscription "${key}" from timeline`
2010
+ );
2011
+ unsubscribe();
2012
+ };
2013
+ };
2014
+
2015
+ // internal/src/subscribe/subscribe-to-transaction.ts
2016
+ var subscribeToTransaction = (token, handleUpdate, key, store) => {
2017
+ const tx = withdraw(token, store);
2018
+ store.logger.info(
2019
+ `\u{1F440}`,
2020
+ `transaction`,
2021
+ token.key,
2022
+ `Adding subscription "${key}"`
2023
+ );
2024
+ const unsubscribe = tx.subject.subscribe(key, handleUpdate);
2025
+ return () => {
2026
+ store.logger.info(
2027
+ `\u{1F648}`,
2028
+ `transaction`,
2029
+ token.key,
2030
+ `Removing subscription "${key}"`
2031
+ );
2032
+ unsubscribe();
2033
+ };
2034
+ };
2035
+
2036
+ // internal/src/mutable/tracker.ts
2037
+ var Tracker = class {
2038
+ Update;
2039
+ initializeState(mutableState, store) {
2040
+ const latestUpdateStateKey = `*${mutableState.key}`;
2041
+ store.atoms.delete(latestUpdateStateKey);
2042
+ store.valueMap.delete(latestUpdateStateKey);
2043
+ const familyMetaData = mutableState.family ? {
2044
+ key: `*${mutableState.family.key}`,
2045
+ subKey: mutableState.family.subKey
2046
+ } : void 0;
2047
+ const latestUpdateState = createRegularAtom(
2048
+ {
2049
+ key: latestUpdateStateKey,
2050
+ default: null
2051
+ },
2052
+ familyMetaData,
2053
+ store
2054
+ );
2055
+ if (store.parent?.valueMap.has(latestUpdateStateKey)) {
2056
+ const parentValue = store.parent.valueMap.get(latestUpdateStateKey);
2057
+ store.valueMap.set(latestUpdateStateKey, parentValue);
2058
+ }
2059
+ return latestUpdateState;
2060
+ }
2061
+ unsubscribeFromInnerValue;
2062
+ unsubscribeFromState;
2063
+ observeCore(mutableState, latestUpdateState, target) {
2064
+ const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2065
+ const originalInnerValue = getFromStore(mutableState, target);
2066
+ this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
2067
+ subscriptionKey,
2068
+ (update) => {
2069
+ setIntoStore(latestUpdateState, update, target);
2070
+ }
2071
+ );
2072
+ this.unsubscribeFromState = subscribeToState(
2073
+ mutableState,
2074
+ (update) => {
2075
+ if (update.newValue !== update.oldValue) {
2076
+ this.unsubscribeFromInnerValue();
2077
+ this.unsubscribeFromInnerValue = update.newValue.subscribe(
2078
+ subscriptionKey,
2079
+ (transceiverUpdate) => {
2080
+ setIntoStore(latestUpdateState, transceiverUpdate, target);
2081
+ }
2082
+ );
2083
+ }
2084
+ },
2085
+ subscriptionKey,
2086
+ target
2087
+ );
2088
+ }
2089
+ updateCore(mutableState, latestUpdateState, target) {
2090
+ const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2091
+ subscribeToState(
2092
+ latestUpdateState,
2093
+ ({ newValue, oldValue }) => {
2094
+ const timelineId = target.timelineTopics.getRelatedKey(
2095
+ latestUpdateState.key
2096
+ );
2097
+ if (timelineId) {
2098
+ const timelineData = target.timelines.get(timelineId);
2099
+ if (timelineData?.timeTraveling) {
2100
+ const unsubscribe2 = subscribeToTimeline(
2101
+ { key: timelineId, type: `timeline` },
2102
+ (update) => {
2103
+ unsubscribe2();
2104
+ setIntoStore(
2105
+ mutableState,
2106
+ (transceiver) => {
2107
+ if (update === `redo` && newValue) {
2108
+ transceiver.do(newValue);
2109
+ } else if (update === `undo` && oldValue) {
2110
+ transceiver.undo(oldValue);
2111
+ }
2112
+ return transceiver;
2113
+ },
2114
+ target
2115
+ );
2116
+ },
2117
+ subscriptionKey,
2118
+ target
2119
+ );
2120
+ return;
2121
+ }
2122
+ }
2123
+ const unsubscribe = target.on.operationClose.subscribe(
2124
+ subscriptionKey,
2125
+ () => {
2126
+ unsubscribe();
2127
+ const mutable = getFromStore(mutableState, target);
2128
+ const updateNumber = newValue === null ? -1 : mutable.getUpdateNumber(newValue);
2129
+ const eventOffset = updateNumber - mutable.cacheUpdateNumber;
2130
+ if (newValue && eventOffset === 1) {
2131
+ setIntoStore(
2132
+ mutableState,
2133
+ (transceiver) => (transceiver.do(newValue), transceiver),
2134
+ target
2135
+ );
2136
+ } else {
2137
+ target.logger.info(
2138
+ `\u274C`,
2139
+ `mutable_atom`,
2140
+ mutableState.key,
2141
+ `could not be updated. Expected update number ${mutable.cacheUpdateNumber + 1}, but got ${updateNumber}`
2142
+ );
2143
+ }
2144
+ }
2145
+ );
2146
+ },
2147
+ subscriptionKey,
2148
+ target
2149
+ );
2150
+ }
2151
+ mutableState;
2152
+ latestUpdateState;
2153
+ dispose;
2154
+ constructor(mutableState, store) {
2155
+ this.mutableState = mutableState;
2156
+ const target = newest(store);
2157
+ this.latestUpdateState = this.initializeState(mutableState, target);
2158
+ this.observeCore(mutableState, this.latestUpdateState, target);
2159
+ this.updateCore(mutableState, this.latestUpdateState, target);
2160
+ target.trackers.set(mutableState.key, this);
2161
+ this.dispose = () => {
2162
+ this.unsubscribeFromInnerValue();
2163
+ this.unsubscribeFromState();
2164
+ target.trackers.delete(mutableState.key);
2165
+ };
2166
+ }
2167
+ };
2168
+
2169
+ // internal/src/mutable/create-mutable-atom.ts
2170
+ function createMutableAtom(options, family, store) {
2171
+ store.logger.info(
2172
+ `\u{1F528}`,
2173
+ `atom`,
2174
+ options.key,
2175
+ `creating in store "${store.config.name}"`
2176
+ );
2177
+ const target = newest(store);
2178
+ const existing = target.atoms.get(options.key);
2179
+ if (existing && existing.type === `mutable_atom`) {
2180
+ store.logger.error(
2181
+ `\u274C`,
2182
+ `atom`,
2183
+ options.key,
2184
+ `Tried to create atom, but it already exists in the store.`
2185
+ );
2186
+ return deposit(existing);
2187
+ }
2188
+ const subject = new Subject();
2189
+ const newAtom = {
2190
+ ...options,
2191
+ type: `mutable_atom`,
2192
+ install: (s) => {
2193
+ s.logger.info(
2194
+ `\u{1F6E0}\uFE0F`,
2195
+ `atom`,
2196
+ options.key,
2197
+ `installing in store "${s.config.name}"`
2198
+ );
2199
+ return createMutableAtom(options, family, s);
2200
+ },
2201
+ subject
2202
+ };
2203
+ if (family) {
2204
+ newAtom.family = family;
2205
+ }
2206
+ const initialValue = options.default();
2207
+ target.atoms.set(newAtom.key, newAtom);
2208
+ markAtomAsDefault(options.key, store);
2209
+ cacheValue(options.key, initialValue, subject, target);
2210
+ const token = deposit(newAtom);
2211
+ if (options.effects) {
2212
+ let effectIndex = 0;
2213
+ const cleanupFunctions = [];
2214
+ for (const effect of options.effects) {
2215
+ const cleanup = effect({
2216
+ setSelf: (next) => {
2217
+ setIntoStore(token, next, store);
2218
+ },
2219
+ onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
2220
+ });
2221
+ if (cleanup) {
2222
+ cleanupFunctions.push(cleanup);
2223
+ }
2224
+ ++effectIndex;
2225
+ }
2226
+ newAtom.cleanup = () => {
2227
+ for (const cleanup of cleanupFunctions) {
2228
+ cleanup();
2229
+ }
2230
+ };
2231
+ }
2232
+ new Tracker(token, store);
2233
+ if (!family) {
2234
+ selectJson(token, options, store);
2235
+ }
2236
+ return token;
2237
+ }
2238
+ var FamilyTracker = class {
2239
+ Update;
2240
+ latestUpdateAtoms;
2241
+ mutableAtoms;
2242
+ constructor(mutableAtoms, store) {
2243
+ const updateAtoms = createRegularAtomFamily(
2244
+ {
2245
+ key: `*${mutableAtoms.key}`,
2246
+ default: null
2247
+ },
2248
+ store,
2249
+ [`mutable`, `updates`]
2250
+ );
2251
+ this.latestUpdateAtoms = withdraw(updateAtoms, store);
2252
+ this.mutableAtoms = mutableAtoms;
2253
+ this.mutableAtoms.subject.subscribe(
2254
+ `store=${store.config.name}::tracker-atom-family`,
2255
+ (event) => {
2256
+ if (event.token.family) {
2257
+ const key = parseJson(event.token.family.subKey);
2258
+ seekInStore(this.latestUpdateAtoms, key, store);
2259
+ new Tracker(event.token, store);
2260
+ }
2261
+ }
2262
+ );
2263
+ this.latestUpdateAtoms.subject.subscribe(
2264
+ `store=${store.config.name}::tracker-atom-family`,
2265
+ (event) => {
2266
+ if (event.token.family) {
2267
+ const key = parseJson(event.token.family.subKey);
2268
+ const mutableAtomToken = seekInStore(this.mutableAtoms, key, store);
2269
+ if (mutableAtomToken) {
2270
+ new Tracker(mutableAtomToken, store);
2271
+ }
2272
+ }
2273
+ }
2274
+ );
2275
+ }
2276
+ };
2277
+
2278
+ // internal/src/mutable/create-mutable-atom-family.ts
2279
+ function createMutableAtomFamily(options, store, internalRoles) {
2280
+ const familyToken = {
2281
+ key: options.key,
2282
+ type: `mutable_atom_family`
2283
+ };
2284
+ throwInCaseOfConflictingFamily(familyToken, store);
2285
+ const subject = new Subject();
2286
+ const familyFunction = (key) => {
2287
+ const subKey = stringifyJson(key);
2288
+ const family = { key: options.key, subKey };
2289
+ const fullKey = `${options.key}(${subKey})`;
2290
+ const target = newest(store);
2291
+ const individualOptions = {
2292
+ key: fullKey,
2293
+ default: () => options.default(key),
2294
+ toJson: options.toJson,
2295
+ fromJson: options.fromJson,
2296
+ mutable: true
2297
+ };
2298
+ if (options.effects) {
2299
+ individualOptions.effects = options.effects(key);
2300
+ }
2301
+ const token = createMutableAtom(individualOptions, family, target);
2302
+ subject.next({ type: `state_creation`, token });
2303
+ return token;
2304
+ };
2305
+ const atomFamily = Object.assign(familyFunction, familyToken, {
2306
+ subject,
2307
+ install: (s) => createMutableAtomFamily(options, s),
2308
+ toJson: options.toJson,
2309
+ fromJson: options.fromJson,
2310
+ internalRoles
2311
+ });
2312
+ store.families.set(options.key, atomFamily);
2313
+ selectJsonFamily(atomFamily, options, store);
2314
+ new FamilyTracker(atomFamily, store);
2315
+ return familyToken;
2316
+ }
2317
+
2318
+ // internal/src/mutable/get-json-family.ts
2319
+ var getJsonFamily = (mutableAtomFamily, store) => {
2320
+ const target = newest(store);
2321
+ const key = `${mutableAtomFamily.key}:JSON`;
2322
+ const jsonFamily = target.families.get(key);
2323
+ return jsonFamily;
2324
+ };
2325
+
2326
+ // internal/src/mutable/get-json-token.ts
2327
+ var getJsonToken = (mutableAtomToken, store) => {
2328
+ if (mutableAtomToken.family) {
2329
+ const target = newest(store);
2330
+ const jsonFamilyKey = `${mutableAtomToken.family.key}:JSON`;
2331
+ const jsonFamilyToken = {
2332
+ key: jsonFamilyKey,
2333
+ type: `selector_family`
2334
+ };
2335
+ const family = withdraw(jsonFamilyToken, target);
2336
+ const subKey = JSON.parse(mutableAtomToken.family.subKey);
2337
+ const jsonToken = findInStore(family, subKey, store);
2338
+ return jsonToken;
2339
+ }
2340
+ const token = {
2341
+ type: `selector`,
2342
+ key: `${mutableAtomToken.key}:JSON`
2343
+ };
2344
+ return token;
2345
+ };
2346
+
2347
+ // internal/src/mutable/get-update-family.ts
2348
+ var getUpdateFamily = (mutableAtomFamily, store) => {
2349
+ const target = newest(store);
2350
+ const key = `*${mutableAtomFamily.key}`;
2351
+ const updateFamily = target.families.get(
2352
+ key
2353
+ );
2354
+ return updateFamily;
2355
+ };
2356
+
2357
+ // internal/src/mutable/get-update-token.ts
2358
+ var getUpdateToken = (mutableAtomToken) => {
2359
+ const key = `*${mutableAtomToken.key}`;
2360
+ const updateToken = { type: `atom`, key };
2361
+ if (mutableAtomToken.family) {
2362
+ updateToken.family = {
2363
+ key: `*${mutableAtomToken.family.key}`,
2364
+ subKey: mutableAtomToken.family.subKey
2365
+ };
2366
+ }
2367
+ return updateToken;
2368
+ };
2369
+
2370
+ // internal/src/mutable/transceiver.ts
2371
+ function isTransceiver(value) {
2372
+ return typeof value === `object` && value !== null && `do` in value && `undo` in value && `subscribe` in value;
2373
+ }
2374
+
2375
+ // internal/src/set-state/copy-mutable-if-needed.ts
2376
+ function copyMutableIfNeeded(atom, origin, target) {
2377
+ const originValue = origin.valueMap.get(atom.key);
2378
+ const targetValue = target.valueMap.get(atom.key);
2379
+ if (originValue === targetValue) {
2380
+ if (originValue === void 0) {
2381
+ return typeof atom.default === `function` ? atom.default() : atom.default;
2382
+ }
2383
+ origin.logger.info(`\u{1F4C3}`, `atom`, atom.key, `copying`);
2384
+ const jsonValue = atom.toJson(originValue);
2385
+ const copiedValue = atom.fromJson(jsonValue);
2386
+ target.valueMap.set(atom.key, copiedValue);
2387
+ new Tracker(atom, origin);
2388
+ return copiedValue;
2389
+ }
2390
+ return targetValue;
2391
+ }
2392
+
2393
+ // internal/src/caching.ts
2394
+ function cacheValue(key, value, subject, target) {
2395
+ const currentValue = target.valueMap.get(key);
2396
+ if (currentValue instanceof Future) {
2397
+ const future = currentValue;
2398
+ future.use(value);
2399
+ }
2400
+ if (value instanceof Promise) {
2401
+ const future = new Future(value);
2402
+ target.valueMap.set(key, future);
2403
+ future.then((resolved) => {
2404
+ cacheValue(key, resolved, subject, target);
2405
+ subject.next({ newValue: resolved, oldValue: future });
2406
+ }).catch((thrown) => {
2407
+ target.logger.error(`\u{1F4A5}`, `state`, key, `rejected:`, thrown);
2408
+ });
2409
+ return future;
2410
+ }
2411
+ target.valueMap.set(key, value);
2412
+ return value;
2413
+ }
2414
+ var readCachedValue = (token, target) => {
2415
+ let value = target.valueMap.get(token.key);
2416
+ if (token.type === `mutable_atom` && isChildStore(target)) {
2417
+ const { parent } = target;
2418
+ const copiedValue = copyMutableIfNeeded(token, parent, target);
2419
+ value = copiedValue;
2420
+ }
2421
+ return value;
2422
+ };
2423
+ var evictCachedValue = (key, target) => {
2424
+ const currentValue = target.valueMap.get(key);
2425
+ if (currentValue instanceof Future) {
2426
+ const future = currentValue;
2427
+ const selector = target.selectors.get(key) ?? target.readonlySelectors.get(key);
2428
+ if (selector) {
2429
+ future.use(selector.get());
2430
+ }
2431
+ return;
2432
+ }
2433
+ if (target.operation.open) {
2434
+ target.operation.prev.set(key, currentValue);
2435
+ }
2436
+ target.valueMap.delete(key);
2437
+ target.logger.info(`\u{1F5D1}`, `state`, key, `evicted`);
2438
+ };
2439
+
2440
+ // internal/src/atom/is-default.ts
2441
+ var isAtomDefault = (key, store) => {
2442
+ const core = newest(store);
2443
+ return core.atomsThatAreDefault.has(key);
2444
+ };
2445
+ var markAtomAsDefault = (key, store) => {
2446
+ const core = newest(store);
2447
+ core.atomsThatAreDefault = new Set(core.atomsThatAreDefault).add(key);
2448
+ };
2449
+ var markAtomAsNotDefault = (key, store) => {
2450
+ const core = newest(store);
2451
+ core.atomsThatAreDefault = new Set(newest(store).atomsThatAreDefault);
2452
+ core.atomsThatAreDefault.delete(key);
2453
+ };
2454
+
2455
+ // internal/src/atom/create-regular-atom.ts
2456
+ function createRegularAtom(options, family, store) {
2457
+ store.logger.info(
2458
+ `\u{1F528}`,
2459
+ `atom`,
2460
+ options.key,
2461
+ `creating in store "${store.config.name}"`
2462
+ );
2463
+ const target = newest(store);
2464
+ const existing = target.atoms.get(options.key);
2465
+ if (existing && existing.type === `atom`) {
2466
+ store.logger.error(
2467
+ `\u274C`,
2468
+ `atom`,
2469
+ options.key,
2470
+ `Tried to create atom, but it already exists in the store.`
2471
+ );
2472
+ return deposit(existing);
2473
+ }
2474
+ const subject = new Subject();
2475
+ const newAtom = {
2476
+ ...options,
2477
+ type: `atom`,
2478
+ install: (s) => {
2479
+ s.logger.info(
2480
+ `\u{1F6E0}\uFE0F`,
2481
+ `atom`,
2482
+ options.key,
2483
+ `installing in store "${s.config.name}"`
2484
+ );
2485
+ return createRegularAtom(options, family, s);
2486
+ },
2487
+ subject
2488
+ };
2489
+ if (family) {
2490
+ newAtom.family = family;
2491
+ }
2492
+ let initialValue = options.default;
2493
+ if (options.default instanceof Function) {
2494
+ initialValue = options.default();
2495
+ }
2496
+ target.atoms.set(newAtom.key, newAtom);
2497
+ markAtomAsDefault(options.key, store);
2498
+ cacheValue(options.key, initialValue, subject, target);
2499
+ const token = deposit(newAtom);
2500
+ if (options.effects) {
2501
+ let effectIndex = 0;
2502
+ const cleanupFunctions = [];
2503
+ for (const effect of options.effects) {
2504
+ const cleanup = effect({
2505
+ setSelf: (next) => {
2506
+ setIntoStore(token, next, store);
2507
+ },
2508
+ onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
2509
+ });
2510
+ if (cleanup) {
2511
+ cleanupFunctions.push(cleanup);
2512
+ }
2513
+ ++effectIndex;
2514
+ }
2515
+ newAtom.cleanup = () => {
2516
+ for (const cleanup of cleanupFunctions) {
2517
+ cleanup();
2518
+ }
2519
+ };
2520
+ }
2521
+ return token;
2522
+ }
2523
+
2524
+ // internal/src/atom/create-standalone-atom.ts
2525
+ function createStandaloneAtom(options, store) {
2526
+ const isMutable = `mutable` in options;
2527
+ if (isMutable) {
2528
+ const state2 = createMutableAtom(options, void 0, store);
2529
+ store.on.atomCreation.next(state2);
2530
+ return state2;
2531
+ }
2532
+ const state = createRegularAtom(options, void 0, store);
2533
+ store.on.atomCreation.next(state);
2534
+ return state;
2535
+ }
2536
+
2537
+ // internal/src/atom/dispose-atom.ts
2538
+ function disposeAtom(atomToken, store) {
2539
+ const target = newest(store);
2540
+ const { key } = atomToken;
2541
+ const atom = target.atoms.get(key);
2542
+ if (!atom) {
2543
+ store.logger.error(
2544
+ `\u274C`,
2545
+ `atom`,
2546
+ key,
2547
+ `Tried to dispose atom, but it does not exist in the store.`
2548
+ );
2549
+ } else if (!atom.family) {
2550
+ store.logger.error(`\u274C`, `atom`, key, `Standalone atoms cannot be disposed.`);
2551
+ } else {
2552
+ atom.cleanup?.();
2553
+ const lastValue = store.valueMap.get(atom.key);
2554
+ const family = withdraw({ key: atom.family.key, type: `atom_family` }, store);
2555
+ family.subject.next({
2556
+ type: `state_disposal`,
2557
+ token: atomToken,
2558
+ value: lastValue
2559
+ });
2560
+ const molecule = target.molecules.get(atom.family.subKey);
2561
+ if (molecule) {
2562
+ molecule.tokens.delete(key);
2563
+ }
2564
+ target.atoms.delete(key);
2565
+ target.valueMap.delete(key);
2566
+ const selectorKeys = target.selectorAtoms.getRelatedKeys(key);
2567
+ if (selectorKeys) {
2568
+ for (const selectorKey of selectorKeys) {
2569
+ const token = target.selectors.get(selectorKey) ?? target.readonlySelectors.get(selectorKey);
2570
+ if (token) {
2571
+ disposeSelector(token, store);
2572
+ }
2573
+ }
2574
+ }
2575
+ target.selectorAtoms.delete(key);
2576
+ target.atomsThatAreDefault.delete(key);
2577
+ target.timelineTopics.delete(key);
2578
+ if (atomToken.type === `mutable_atom`) {
2579
+ const updateToken = getUpdateToken(atomToken);
2580
+ disposeAtom(updateToken, store);
2581
+ store.trackers.delete(key);
2582
+ }
2583
+ store.logger.info(`\u{1F525}`, `atom`, key, `deleted`);
2584
+ if (isChildStore(target) && target.transactionMeta.phase === `building`) {
2585
+ target.transactionMeta.update.updates.push({
2586
+ type: `state_disposal`,
2587
+ token: atomToken
2588
+ });
2589
+ } else {
2590
+ store.on.atomDisposal.next(atomToken);
2591
+ }
2592
+ }
2593
+ }
2594
+ function createTimeline(options, store, data) {
2595
+ const tl = {
2596
+ type: `timeline`,
2597
+ key: options.key,
2598
+ at: 0,
2599
+ timeTraveling: null,
2600
+ selectorTime: null,
2601
+ transactionKey: null,
2602
+ ...data,
2603
+ history: data?.history.map((update) => ({ ...update })) ?? [],
2604
+ install: (s) => createTimeline(options, s, tl),
2605
+ subject: new Subject(),
2606
+ subscriptions: /* @__PURE__ */ new Map()
2607
+ };
2608
+ if (options.shouldCapture) {
2609
+ tl.shouldCapture = options.shouldCapture;
2610
+ }
2611
+ const timelineKey = options.key;
2612
+ const target = newest(store);
2613
+ for (const initialTopic of options.scope) {
2614
+ switch (initialTopic.type) {
2615
+ case `atom`:
2616
+ case `mutable_atom`:
2617
+ {
2618
+ const atomToken = initialTopic;
2619
+ const atomKey = atomToken.key;
2620
+ let existingTimelineKey = target.timelineTopics.getRelatedKey(atomKey);
2621
+ if (`family` in atomToken) {
2622
+ const familyKey = atomToken.family.key;
2623
+ existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
2624
+ if (existingTimelineKey) {
2625
+ store.logger.error(
2626
+ `\u274C`,
2627
+ `timeline`,
2628
+ options.key,
2629
+ `Failed to add atom "${atomKey}" because its family "${familyKey}" already belongs to timeline "${existingTimelineKey}"`
2630
+ );
2631
+ continue;
2632
+ }
2633
+ }
2634
+ if (existingTimelineKey) {
2635
+ store.logger.error(
2636
+ `\u274C`,
2637
+ `timeline`,
2638
+ options.key,
2639
+ `Failed to add atom "${atomKey}" because it already belongs to timeline "${existingTimelineKey}"`
2640
+ );
2641
+ continue;
2642
+ }
2643
+ addAtomToTimeline(atomToken, tl, store);
2644
+ }
2645
+ break;
2646
+ case `atom_family`:
2647
+ case `mutable_atom_family`:
2648
+ {
2649
+ const familyToken = initialTopic;
2650
+ const familyKey = familyToken.key;
2651
+ const existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
2652
+ if (existingTimelineKey) {
2653
+ store.logger.error(
2654
+ `\u274C`,
2655
+ `timeline`,
2656
+ options.key,
2657
+ `Failed to add atom family "${familyKey}" because it already belongs to timeline "${existingTimelineKey}"`
2658
+ );
2659
+ continue;
2660
+ }
2661
+ addAtomFamilyToTimeline(familyToken, tl, store);
2662
+ }
2663
+ break;
2664
+ case `molecule_family`:
2665
+ {
2666
+ const familyToken = initialTopic;
2667
+ const familyKey = familyToken.key;
2668
+ const existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
2669
+ if (existingTimelineKey) {
2670
+ store.logger.error(
2671
+ `\u274C`,
2672
+ `timeline`,
2673
+ options.key,
2674
+ `Failed to add molecule family "${familyKey}" because it already belongs to timeline "${existingTimelineKey}"`
2675
+ );
2676
+ continue;
2677
+ }
2678
+ addMoleculeFamilyToTimeline(familyToken, tl, store);
2679
+ }
2680
+ break;
2681
+ }
2682
+ }
2683
+ store.timelines.set(options.key, tl);
2684
+ const token = {
2685
+ key: timelineKey,
2686
+ type: `timeline`
2687
+ };
2688
+ store.on.timelineCreation.next(token);
2689
+ return token;
2690
+ }
2691
+ function addAtomToTimeline(atomToken, tl, store) {
2692
+ let maybeAtom = withdraw(atomToken, store);
2693
+ if (maybeAtom.type === `mutable_atom`) {
2694
+ const updateToken = getUpdateToken(maybeAtom);
2695
+ maybeAtom = withdraw(updateToken, store);
2696
+ }
2697
+ const atom = maybeAtom;
2698
+ store.timelineTopics.set(
2699
+ { topicKey: atom.key, timelineKey: tl.key },
2700
+ { topicType: `atom` }
2701
+ );
2702
+ tl.subscriptions.set(
2703
+ atom.key,
2704
+ atom.subject.subscribe(`timeline`, (update) => {
2705
+ const target = newest(store);
2706
+ const currentSelectorKey = store.operation.open && store.operation.token.type === `selector` ? store.operation.token.key : null;
2707
+ const currentSelectorTime = store.operation.open && store.operation.token.type === `selector` ? store.operation.time : null;
2708
+ const txUpdateInProgress = target.on.transactionApplying.state?.update;
2709
+ store.logger.info(
2710
+ `\u23F3`,
2711
+ `timeline`,
2712
+ tl.key,
2713
+ `atom`,
2714
+ atomToken.key,
2715
+ `went`,
2716
+ update.oldValue,
2717
+ `->`,
2718
+ update.newValue,
2719
+ txUpdateInProgress ? `in transaction "${txUpdateInProgress.key}"` : currentSelectorKey ? `in selector "${currentSelectorKey}"` : ``
2720
+ );
2721
+ if (tl.timeTraveling === null) {
2722
+ if (txUpdateInProgress) {
2723
+ joinTransaction(tl, txUpdateInProgress, store);
2724
+ } else if (currentSelectorKey && currentSelectorTime) {
2725
+ let latestUpdate = tl.history.at(-1);
2726
+ if (currentSelectorTime !== tl.selectorTime) {
2727
+ latestUpdate = {
2728
+ type: `selector_update`,
2729
+ timestamp: currentSelectorTime,
2730
+ key: currentSelectorKey,
2731
+ atomUpdates: []
2732
+ };
2733
+ latestUpdate.atomUpdates.push({
2734
+ key: atom.key,
2735
+ type: `atom_update`,
2736
+ ...update
2737
+ });
2738
+ if (tl.at !== tl.history.length) {
2739
+ tl.history.splice(tl.at);
2740
+ }
2741
+ tl.history.push(latestUpdate);
2742
+ store.logger.info(
2743
+ `\u231B`,
2744
+ `timeline`,
2745
+ tl.key,
2746
+ `got a selector_update "${currentSelectorKey}" with`,
2747
+ latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
2748
+ );
2749
+ tl.at = tl.history.length;
2750
+ tl.selectorTime = currentSelectorTime;
2751
+ } else {
2752
+ if (latestUpdate?.type === `selector_update`) {
2753
+ latestUpdate.atomUpdates.push({
2754
+ key: atom.key,
2755
+ type: `atom_update`,
2756
+ ...update
2757
+ });
2758
+ store.logger.info(
2759
+ `\u231B`,
2760
+ `timeline`,
2761
+ tl.key,
2762
+ `set selector_update "${currentSelectorKey}" to`,
2763
+ latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key)
2764
+ );
2765
+ }
2766
+ }
2767
+ if (latestUpdate) {
2768
+ const willCaptureSelectorUpdate = tl.shouldCapture?.(latestUpdate, tl) ?? true;
2769
+ if (willCaptureSelectorUpdate) {
2770
+ tl.subject.next(latestUpdate);
2771
+ } else {
2772
+ tl.history.pop();
2773
+ tl.at = tl.history.length;
2774
+ }
2775
+ }
2776
+ } else {
2777
+ const timestamp = Date.now();
2778
+ tl.selectorTime = null;
2779
+ if (tl.at !== tl.history.length) {
2780
+ tl.history.splice(tl.at);
2781
+ }
2782
+ const atomUpdate = {
2783
+ type: `atom_update`,
2784
+ timestamp,
2785
+ key: atom.key,
2786
+ oldValue: update.oldValue,
2787
+ newValue: update.newValue
2788
+ };
2789
+ if (atom.family) {
2790
+ atomUpdate.family = atom.family;
2791
+ }
2792
+ const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true;
2793
+ store.logger.info(
2794
+ `\u231B`,
2795
+ `timeline`,
2796
+ tl.key,
2797
+ `got an atom_update to "${atom.key}"`
2798
+ );
2799
+ if (willCapture) {
2800
+ tl.history.push(atomUpdate);
2801
+ tl.at = tl.history.length;
2802
+ tl.subject.next(atomUpdate);
2803
+ }
2804
+ }
2805
+ }
2806
+ })
2807
+ );
2808
+ }
2809
+ function addAtomFamilyToTimeline(atomFamilyToken, tl, store) {
2810
+ const family = withdraw(atomFamilyToken, store);
2811
+ store.timelineTopics.set(
2812
+ { topicKey: family.key, timelineKey: tl.key },
2813
+ { topicType: `atom_family` }
2814
+ );
2815
+ tl.subscriptions.set(
2816
+ family.key,
2817
+ family.subject.subscribe(`timeline`, (creationOrDisposal) => {
2818
+ handleStateLifecycleEvent(creationOrDisposal, tl, store);
2819
+ })
2820
+ );
2821
+ for (const atom of store.atoms.values()) {
2822
+ if (atom.family?.key === family.key) {
2823
+ addAtomToTimeline(atom, tl, store);
2824
+ }
2825
+ }
2826
+ }
2827
+ function addMoleculeFamilyToTimeline(familyToken, tl, store) {
2828
+ store.timelineTopics.set(
2829
+ { topicKey: familyToken.key, timelineKey: tl.key },
2830
+ { topicType: `molecule_family` }
2831
+ );
2832
+ const family = store.moleculeFamilies.get(familyToken.key);
2833
+ if (family) {
2834
+ tl.subscriptions.set(
2835
+ familyToken.key,
2836
+ family.subject.subscribe(`timeline:${tl.key}`, (creationOrDisposal) => {
2837
+ store.logger.info(
2838
+ `\u{1F41E}`,
2839
+ `timeline`,
2840
+ tl.key,
2841
+ `got a molecule creation or disposal`,
2842
+ creationOrDisposal
2843
+ );
2844
+ switch (creationOrDisposal.type) {
2845
+ case `molecule_creation`:
2846
+ {
2847
+ store.timelineTopics.set(
2848
+ {
2849
+ topicKey: creationOrDisposal.token.key,
2850
+ timelineKey: tl.key
2851
+ },
2852
+ { topicType: `molecule` }
2853
+ );
2854
+ const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
2855
+ if (txUpdateInProgress) {
2856
+ joinTransaction(tl, txUpdateInProgress, store);
2857
+ } else if (tl.timeTraveling === null) {
2858
+ const event = Object.assign(creationOrDisposal, {
2859
+ timestamp: Date.now()
2860
+ });
2861
+ tl.history.push(event);
2862
+ tl.at = tl.history.length;
2863
+ tl.subject.next(event);
2864
+ }
2865
+ const molecule = withdraw(creationOrDisposal.token, store);
2866
+ for (const token of molecule.tokens.values()) {
2867
+ switch (token.type) {
2868
+ case `atom`:
2869
+ case `mutable_atom`:
2870
+ addAtomToTimeline(token, tl, store);
2871
+ break;
2872
+ }
2873
+ }
2874
+ tl.subscriptions.set(
2875
+ molecule.key,
2876
+ molecule.subject.subscribe(
2877
+ `timeline:${tl.key}`,
2878
+ (stateCreationOrDisposal) => {
2879
+ handleStateLifecycleEvent(stateCreationOrDisposal, tl, store);
2880
+ }
2881
+ )
2882
+ );
2883
+ }
2884
+ break;
2885
+ case `molecule_disposal`:
2886
+ {
2887
+ const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
2888
+ if (txUpdateInProgress) {
2889
+ joinTransaction(tl, txUpdateInProgress, store);
2890
+ } else if (tl.timeTraveling === null) {
2891
+ const event = Object.assign(creationOrDisposal, {
2892
+ timestamp: Date.now()
2893
+ });
2894
+ tl.history.push(event);
2895
+ tl.at = tl.history.length;
2896
+ tl.subject.next(event);
2897
+ }
2898
+ const moleculeKey = creationOrDisposal.token.key;
2899
+ tl.subscriptions.get(moleculeKey)?.();
2900
+ tl.subscriptions.delete(moleculeKey);
2901
+ for (const [familyKey] of creationOrDisposal.values) {
2902
+ const stateKey = `${familyKey}(${stringifyJson(moleculeKey)})`;
2903
+ tl.subscriptions.get(stateKey)?.();
2904
+ tl.subscriptions.delete(stateKey);
2905
+ store.timelineTopics.delete(stateKey);
2906
+ }
2907
+ }
2908
+ break;
2909
+ }
2910
+ })
2911
+ );
2912
+ }
2913
+ }
2914
+ function joinTransaction(tl, txUpdateInProgress, store) {
2915
+ const currentTxKey = txUpdateInProgress.key;
2916
+ const currentTxInstanceId = txUpdateInProgress.id;
2917
+ const currentTxToken = {
2918
+ key: currentTxKey,
2919
+ type: `transaction`
2920
+ };
2921
+ const currentTransaction = withdraw(currentTxToken, store);
2922
+ if (currentTxKey && tl.transactionKey === null) {
2923
+ tl.transactionKey = currentTxKey;
2924
+ const unsubscribe = currentTransaction.subject.subscribe(
2925
+ `timeline:${tl.key}`,
2926
+ (transactionUpdate) => {
2927
+ unsubscribe();
2928
+ tl.transactionKey = null;
2929
+ if (tl.timeTraveling === null && currentTxInstanceId) {
2930
+ if (tl.at !== tl.history.length) {
2931
+ tl.history.splice(tl.at);
2932
+ }
2933
+ const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key);
2934
+ const updates = filterTransactionUpdates(
2935
+ transactionUpdate.updates,
2936
+ timelineTopics
2937
+ );
2938
+ const timelineTransactionUpdate = {
2939
+ timestamp: Date.now(),
2940
+ ...transactionUpdate,
2941
+ updates
2942
+ };
2943
+ const willCapture = tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true;
2944
+ if (willCapture) {
2945
+ tl.history.push(timelineTransactionUpdate);
2946
+ tl.at = tl.history.length;
2947
+ tl.subject.next(timelineTransactionUpdate);
2948
+ }
2949
+ }
2950
+ }
2951
+ );
2952
+ }
2953
+ }
2954
+ function filterTransactionUpdates(updates, timelineTopics) {
2955
+ return updates.filter((updateFromTx) => {
2956
+ if (updateFromTx.type === `transaction_update`) {
2957
+ return true;
2958
+ }
2959
+ let key;
2960
+ switch (updateFromTx.type) {
2961
+ case `state_creation`:
2962
+ case `state_disposal`:
2963
+ case `molecule_creation`:
2964
+ case `molecule_disposal`:
2965
+ key = updateFromTx.token.key;
2966
+ break;
2967
+ default:
2968
+ key = updateFromTx.key;
2969
+ break;
2970
+ }
2971
+ return timelineTopics.has(key);
2972
+ }).map((updateFromTx) => {
2973
+ if (`updates` in updateFromTx) {
2974
+ return {
2975
+ ...updateFromTx,
2976
+ updates: filterTransactionUpdates(
2977
+ updateFromTx.updates,
2978
+ timelineTopics
2979
+ )
2980
+ };
2981
+ }
2982
+ return updateFromTx;
2983
+ });
2984
+ }
2985
+ function handleStateLifecycleEvent(event, tl, store) {
2986
+ const timestamp = Date.now();
2987
+ const timelineEvent = Object.assign(event, {
2988
+ timestamp
2989
+ });
2990
+ if (!tl.timeTraveling) {
2991
+ const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
2992
+ if (txUpdateInProgress) {
2993
+ joinTransaction(tl, txUpdateInProgress, store);
2994
+ } else {
2995
+ tl.history.push(timelineEvent);
2996
+ tl.at = tl.history.length;
2997
+ tl.subject.next(timelineEvent);
2998
+ }
2999
+ }
3000
+ switch (event.type) {
3001
+ case `state_creation`:
3002
+ addAtomToTimeline(event.token, tl, store);
3003
+ break;
3004
+ case `state_disposal`:
3005
+ tl.subscriptions.get(event.token.key)?.();
3006
+ tl.subscriptions.delete(event.token.key);
3007
+ break;
3008
+ }
3009
+ }
3010
+
3011
+ // internal/src/timeline/time-travel.ts
3012
+ var timeTravel = (action, token, store) => {
3013
+ store.logger.info(
3014
+ action === `redo` ? `\u23E9` : `\u23EA`,
3015
+ `timeline`,
3016
+ token.key,
3017
+ action
3018
+ );
3019
+ const timelineData = store.timelines.get(token.key);
3020
+ if (!timelineData) {
3021
+ store.logger.error(
3022
+ `\u{1F41E}`,
3023
+ `timeline`,
3024
+ token.key,
3025
+ `Failed to ${action}. This timeline has not been initialized.`
3026
+ );
3027
+ return;
3028
+ }
3029
+ if (action === `redo` && timelineData.at === timelineData.history.length || action === `undo` && timelineData.at === 0) {
3030
+ store.logger.warn(
3031
+ `\u{1F481}`,
3032
+ `timeline`,
3033
+ token.key,
3034
+ `Failed to ${action} at the ${action === `redo` ? `end` : `beginning`} of timeline "${token.key}". There is nothing to ${action}.`
3035
+ );
3036
+ return;
3037
+ }
3038
+ timelineData.timeTraveling = action === `redo` ? `into_future` : `into_past`;
3039
+ if (action === `undo`) {
3040
+ --timelineData.at;
3041
+ }
3042
+ const update = timelineData.history[timelineData.at];
3043
+ const applying = action === `redo` ? `newValue` : `oldValue`;
3044
+ switch (update.type) {
3045
+ case `atom_update`: {
3046
+ ingestAtomUpdate(applying, update, store);
3047
+ break;
3048
+ }
3049
+ case `selector_update`: {
3050
+ ingestSelectorUpdate(applying, update, store);
3051
+ break;
3052
+ }
3053
+ case `transaction_update`: {
3054
+ ingestTransactionUpdate(applying, update, store);
3055
+ break;
3056
+ }
3057
+ case `state_creation`: {
3058
+ ingestCreationEvent(update, applying, store);
3059
+ break;
3060
+ }
3061
+ case `state_disposal`: {
3062
+ ingestDisposalEvent(update, applying, store);
3063
+ break;
3064
+ }
3065
+ case `molecule_creation`: {
3066
+ ingestMoleculeCreationEvent(update, applying, store);
3067
+ break;
3068
+ }
3069
+ case `molecule_disposal`: {
3070
+ ingestMoleculeDisposalEvent(update, applying, store);
3071
+ break;
3072
+ }
3073
+ }
3074
+ if (action === `redo`) {
3075
+ ++timelineData.at;
3076
+ }
3077
+ timelineData.subject.next(action);
3078
+ timelineData.timeTraveling = null;
3079
+ store.logger.info(
3080
+ `\u23F9\uFE0F`,
3081
+ `timeline`,
3082
+ token.key,
3083
+ `"${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
3084
+ );
3085
+ };
3086
+
3087
+ 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 };