atom.io 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -18,53 +18,153 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  var __objRest = (source, exclude) => {
21
- var target = {};
21
+ var target3 = {};
22
22
  for (var prop in source)
23
23
  if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
- target[prop] = source[prop];
24
+ target3[prop] = source[prop];
25
25
  if (source != null && __getOwnPropSymbols)
26
26
  for (var prop of __getOwnPropSymbols(source)) {
27
27
  if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
- target[prop] = source[prop];
28
+ target3[prop] = source[prop];
29
29
  }
30
- return target;
30
+ return target3;
31
31
  };
32
- var __export = (target, all) => {
32
+ var __export = (target3, all) => {
33
33
  for (var name in all)
34
- __defProp(target, name, { get: all[name], enumerable: true });
34
+ __defProp(target3, name, { get: all[name], enumerable: true });
35
35
  };
36
36
 
37
37
  // src/internal/index.ts
38
38
  var internal_exports = {};
39
39
  __export(internal_exports, {
40
40
  IMPLICIT: () => IMPLICIT,
41
+ LOG_LEVELS: () => LOG_LEVELS,
42
+ TRANSACTION_PHASES: () => TRANSACTION_PHASES,
41
43
  abortTransaction: () => abortTransaction,
44
+ applyTransaction: () => applyTransaction,
45
+ atomFamily__INTERNAL: () => atomFamily__INTERNAL,
46
+ atom__INTERNAL: () => atom__INTERNAL,
47
+ buildTransaction: () => buildTransaction,
48
+ cacheValue: () => cacheValue,
42
49
  clearStore: () => clearStore,
43
- configure: () => configure,
50
+ closeOperation: () => closeOperation,
51
+ computeSelectorState: () => computeSelectorState,
44
52
  createStore: () => createStore,
45
53
  deposit: () => deposit,
46
- finishAction: () => finishAction,
47
- finishTransaction: () => finishTransaction,
48
- getCachedState: () => getCachedState,
49
- getSelectorState: () => getSelectorState,
54
+ emitUpdate: () => emitUpdate,
55
+ evictCachedValue: () => evictCachedValue,
56
+ evictDownStream: () => evictDownStream,
50
57
  getState__INTERNAL: () => getState__INTERNAL,
58
+ hasKeyBeenUsed: () => hasKeyBeenUsed,
59
+ isAtomDefault: () => isAtomDefault,
51
60
  isDone: () => isDone,
61
+ isSelectorDefault: () => isSelectorDefault,
62
+ isValueCached: () => isValueCached,
63
+ lookup: () => lookup,
64
+ lookupSelectorSources: () => lookupSelectorSources,
65
+ markAtomAsDefault: () => markAtomAsDefault,
66
+ markAtomAsNotDefault: () => markAtomAsNotDefault,
52
67
  markDone: () => markDone,
53
- propagateDown: () => propagateDown,
54
- recall: () => recall,
68
+ openOperation: () => openOperation,
69
+ prepareUpdate: () => prepareUpdate,
70
+ readCachedValue: () => readCachedValue,
71
+ readonlySelectorFamily__INTERNAL: () => readonlySelectorFamily__INTERNAL,
72
+ recallState: () => recallState,
73
+ redoTransactionUpdate: () => redoTransactionUpdate,
74
+ redo__INTERNAL: () => redo__INTERNAL,
75
+ registerSelector: () => registerSelector,
76
+ selectorFamily__INTERNAL: () => selectorFamily__INTERNAL,
77
+ selector__INTERNAL: () => selector__INTERNAL,
55
78
  setAtomState: () => setAtomState,
79
+ setLogLevel: () => setLogLevel,
56
80
  setSelectorState: () => setSelectorState,
57
81
  setState__INTERNAL: () => setState__INTERNAL,
58
- startAction: () => startAction,
59
- startTransaction: () => startTransaction,
82
+ storeAtom: () => storeAtom,
83
+ storeReadonlySelector: () => storeReadonlySelector,
84
+ storeSelector: () => storeSelector,
85
+ stowUpdate: () => stowUpdate,
86
+ subscribeToRootAtoms: () => subscribeToRootAtoms,
87
+ target: () => target,
88
+ timeline__INTERNAL: () => timeline__INTERNAL,
89
+ traceAllSelectorAtoms: () => traceAllSelectorAtoms,
90
+ traceSelectorAtoms: () => traceSelectorAtoms,
91
+ transaction__INTERNAL: () => transaction__INTERNAL,
92
+ undoTransactionUpdate: () => undoTransactionUpdate,
93
+ undo__INTERNAL: () => undo__INTERNAL,
94
+ updateSelectorAtoms: () => updateSelectorAtoms,
95
+ useLogger: () => useLogger,
60
96
  withdraw: () => withdraw
61
97
  });
62
98
 
99
+ // src/internal/atom-internal.ts
100
+ import * as Rx2 from "rxjs";
101
+
63
102
  // src/internal/get.ts
64
- import HAMT2 from "hamt_plus";
103
+ import HAMT from "hamt_plus";
104
+ var computeSelectorState = (selector2) => selector2.get();
105
+ function lookup(key, store) {
106
+ const core = target(store);
107
+ const type = HAMT.has(key, core.atoms) ? `atom` : HAMT.has(key, core.selectors) ? `selector` : `readonly_selector`;
108
+ return { key, type };
109
+ }
110
+ function withdraw(token, store) {
111
+ var _a, _b, _c;
112
+ const core = target(store);
113
+ return (_c = (_b = (_a = HAMT.get(token.key, core.atoms)) != null ? _a : HAMT.get(token.key, core.selectors)) != null ? _b : HAMT.get(token.key, core.readonlySelectors)) != null ? _c : HAMT.get(token.key, core.transactions);
114
+ }
115
+ function deposit(state) {
116
+ return __spreadValues({
117
+ key: state.key,
118
+ type: state.type
119
+ }, `family` in state && { family: state.family });
120
+ }
121
+ var getState__INTERNAL = (state, store = IMPLICIT.STORE) => {
122
+ var _a, _b, _c;
123
+ if (isValueCached(state.key, store)) {
124
+ (_a = store.config.logger) == null ? void 0 : _a.info(`>> read "${state.key}"`);
125
+ return readCachedValue(state.key, store);
126
+ }
127
+ if (`get` in state) {
128
+ (_b = store.config.logger) == null ? void 0 : _b.info(`-> calc "${state.key}"`);
129
+ return computeSelectorState(state);
130
+ }
131
+ (_c = store.config.logger) == null ? void 0 : _c.error(
132
+ `Attempted to get atom "${state.key}", which was never initialized in store "${store.config.name}".`
133
+ );
134
+ return state.default;
135
+ };
136
+
137
+ // src/internal/is-default.ts
138
+ var isAtomDefault = (key, store = IMPLICIT.STORE) => {
139
+ const core = target(store);
140
+ return core.atomsThatAreDefault.has(key);
141
+ };
142
+ var markAtomAsDefault = (key, store = IMPLICIT.STORE) => {
143
+ const core = target(store);
144
+ core.atomsThatAreDefault = new Set(core.atomsThatAreDefault).add(key);
145
+ };
146
+ var markAtomAsNotDefault = (key, store = IMPLICIT.STORE) => {
147
+ const core = target(store);
148
+ core.atomsThatAreDefault = new Set(target(store).atomsThatAreDefault);
149
+ core.atomsThatAreDefault.delete(key);
150
+ };
151
+ var isSelectorDefault = (key, store = IMPLICIT.STORE) => {
152
+ const roots = traceAllSelectorAtoms(key, store);
153
+ return roots.every((root) => isAtomDefault(root.key, store));
154
+ };
155
+
156
+ // src/internal/operation.ts
157
+ import HAMT3 from "hamt_plus";
65
158
 
66
159
  // src/internal/store.ts
67
- import HAMT from "hamt_plus";
160
+ import HAMT2 from "hamt_plus";
161
+
162
+ // ../anvl/src/function/index.ts
163
+ var doNothing = () => void 0;
164
+ var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
165
+ originalThing instanceof Function ? originalThing() : originalThing
166
+ ) : nextVersionOfThing;
167
+ var pass = (...params) => (fn) => fn(...params);
68
168
 
69
169
  // ../anvl/src/join/core-relation-data.ts
70
170
  import { isString } from "fp-ts/string";
@@ -110,12 +210,6 @@ var mapObject = (obj, fn) => pipe(
110
210
  );
111
211
  var mob = (fn) => (obj) => mapObject(obj, fn);
112
212
 
113
- // ../anvl/src/function/index.ts
114
- var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
115
- originalThing instanceof Function ? originalThing() : originalThing
116
- ) : nextVersionOfThing;
117
- var pass = (...params) => (fn) => fn(...params);
118
-
119
213
  // ../anvl/src/nullish/index.ts
120
214
  var isUndefined = (input) => input === void 0;
121
215
  var ifNullish = (alt) => (input) => input != null ? input : alt;
@@ -454,20 +548,29 @@ var Join = class {
454
548
 
455
549
  // src/internal/store.ts
456
550
  var createStore = (name) => ({
457
- valueMap: HAMT.make(),
551
+ atoms: HAMT2.make(),
552
+ atomsThatAreDefault: /* @__PURE__ */ new Set(),
553
+ readonlySelectors: HAMT2.make(),
554
+ selectorAtoms: new Join({ relationType: `n:n` }),
458
555
  selectorGraph: new Join({ relationType: `n:n` }),
459
- atoms: HAMT.make(),
460
- selectors: HAMT.make(),
461
- readonlySelectors: HAMT.make(),
556
+ selectors: HAMT2.make(),
557
+ timelines: HAMT2.make(),
558
+ timelineAtoms: new Join({ relationType: `1:n` }),
559
+ timelineStore: HAMT2.make(),
560
+ transactions: HAMT2.make(),
561
+ valueMap: HAMT2.make(),
462
562
  operation: {
463
563
  open: false
464
564
  },
465
- transaction: {
466
- open: false
565
+ transactionStatus: {
566
+ phase: `idle`
467
567
  },
468
568
  config: {
469
569
  name,
470
- logger: null
570
+ logger: __spreadProps(__spreadValues({}, console), {
571
+ info: doNothing
572
+ }),
573
+ logger__INTERNAL: console
471
574
  }
472
575
  });
473
576
  var IMPLICIT = {
@@ -477,420 +580,880 @@ var IMPLICIT = {
477
580
  return (_a = this.STORE_INTERNAL) != null ? _a : this.STORE_INTERNAL = createStore(`DEFAULT`);
478
581
  }
479
582
  };
480
- var configure = (config, store = IMPLICIT.STORE) => {
481
- Object.assign(store.config, config);
482
- };
483
583
  var clearStore = (store = IMPLICIT.STORE) => {
484
584
  const { config } = store;
485
585
  Object.assign(store, createStore(config.name));
486
586
  store.config = config;
487
587
  };
488
588
 
489
- // src/internal/get.ts
490
- var getCachedState = (state, store = IMPLICIT.STORE) => {
491
- const value = HAMT2.get(state.key, store.valueMap);
492
- return value;
493
- };
494
- var getSelectorState = (selector2) => selector2.get();
495
- function withdraw(token, store) {
496
- var _a, _b;
497
- return (_b = (_a = HAMT2.get(token.key, store.atoms)) != null ? _a : HAMT2.get(token.key, store.selectors)) != null ? _b : HAMT2.get(token.key, store.readonlySelectors);
498
- }
499
- function deposit(state) {
500
- if (`get` in state) {
501
- if (`set` in state) {
502
- return { key: state.key, type: `selector` };
503
- }
504
- return { key: state.key, type: `readonly_selector` };
505
- }
506
- return { key: state.key, type: `atom` };
507
- }
508
- var getState__INTERNAL = (state, store = IMPLICIT.STORE) => {
509
- var _a;
510
- if (HAMT2.has(state.key, store.valueMap)) {
511
- return getCachedState(state, store);
512
- }
513
- if (`get` in state) {
514
- return getSelectorState(state);
515
- }
516
- (_a = store.config.logger) == null ? void 0 : _a.error(
517
- `Attempted to get atom "${state.key}", which was never initialized in store "${store.config.name}".`
518
- );
519
- return state.default;
520
- };
521
-
522
- // src/internal/set.ts
523
- import HAMT4 from "hamt_plus";
524
-
525
589
  // src/internal/operation.ts
526
- import HAMT3 from "hamt_plus";
527
- var startAction = (store) => {
590
+ var openOperation = (store) => {
528
591
  var _a;
529
- store.operation = {
592
+ const core = target(store);
593
+ core.operation = {
530
594
  open: true,
531
595
  done: /* @__PURE__ */ new Set(),
532
596
  prev: store.valueMap
533
597
  };
534
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u2610`, `operation start`);
598
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u2B55`, `operation start`);
535
599
  };
536
- var finishAction = (store) => {
600
+ var closeOperation = (store) => {
537
601
  var _a;
538
- store.operation = { open: false };
539
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u2611\uFE0F`, `operation done`);
602
+ const core = target(store);
603
+ core.operation = { open: false };
604
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F534}`, `operation done`);
540
605
  };
541
606
  var isDone = (key, store = IMPLICIT.STORE) => {
542
607
  var _a;
543
- if (!store.operation.open) {
608
+ const core = target(store);
609
+ if (!core.operation.open) {
544
610
  (_a = store.config.logger) == null ? void 0 : _a.warn(
545
- `isDone called outside of an action. This is probably a bug.`
611
+ `isDone called outside of an operation. This is probably a bug.`
546
612
  );
547
613
  return true;
548
614
  }
549
- return store.operation.done.has(key);
615
+ return core.operation.done.has(key);
550
616
  };
551
617
  var markDone = (key, store = IMPLICIT.STORE) => {
552
618
  var _a;
553
- if (!store.operation.open) {
619
+ const core = target(store);
620
+ if (!core.operation.open) {
554
621
  (_a = store.config.logger) == null ? void 0 : _a.warn(
555
- `markDone called outside of an action. This is probably a bug.`
622
+ `markDone called outside of an operation. This is probably a bug.`
556
623
  );
557
624
  return;
558
625
  }
559
- store.operation.done.add(key);
626
+ core.operation.done.add(key);
560
627
  };
561
- var recall = (state, store = IMPLICIT.STORE) => {
628
+ var recallState = (state, store = IMPLICIT.STORE) => {
562
629
  var _a;
563
- if (!store.operation.open) {
630
+ const core = target(store);
631
+ if (!core.operation.open) {
564
632
  (_a = store.config.logger) == null ? void 0 : _a.warn(
565
- `recall called outside of an action. This is probably a bug.`
633
+ `recall called outside of an operation. This is probably a bug.`
566
634
  );
567
- return HAMT3.get(state.key, store.valueMap);
635
+ return HAMT3.get(state.key, core.valueMap);
568
636
  }
569
- return HAMT3.get(state.key, store.operation.prev);
637
+ return HAMT3.get(state.key, core.operation.prev);
570
638
  };
571
-
572
- // src/internal/set.ts
573
- var propagateDown = (state, store = IMPLICIT.STORE) => {
574
- var _a, _b;
575
- const relatedStateKeys = store.selectorGraph.getRelations(state.key);
576
- (_a = store.config.logger) == null ? void 0 : _a.info(
577
- ` ||`,
578
- `bumping`,
579
- relatedStateKeys.length,
580
- `states:`,
581
- relatedStateKeys.map(({ id }) => id)
582
- );
583
- if (store.operation.open) {
584
- (_b = store.config.logger) == null ? void 0 : _b.info(` ||`, `done:`, store.operation.done);
585
- }
586
- relatedStateKeys.forEach(({ id: stateKey }) => {
587
- var _a2, _b2, _c, _d, _e;
588
- if (isDone(stateKey, store)) {
589
- (_a2 = store.config.logger) == null ? void 0 : _a2.info(` ||`, stateKey, `already done`);
590
- return;
591
- }
592
- (_b2 = store.config.logger) == null ? void 0 : _b2.info(`->`, `bumping`, stateKey);
593
- const state2 = (_c = HAMT4.get(stateKey, store.selectors)) != null ? _c : HAMT4.get(stateKey, store.readonlySelectors);
594
- if (!state2) {
595
- (_d = store.config.logger) == null ? void 0 : _d.info(
596
- ` ||`,
597
- stateKey,
598
- `is an atom - no need to propagate down`
599
- );
600
- return;
601
- }
602
- store.valueMap = HAMT4.remove(stateKey, store.valueMap);
603
- const newValue = getState__INTERNAL(state2, store);
604
- (_e = store.config.logger) == null ? void 0 : _e.info(` <-`, stateKey, `became`, newValue);
605
- const oldValue = recall(state2, store);
606
- state2.subject.next({ newValue, oldValue });
607
- markDone(stateKey, store);
608
- if (`set` in state2)
609
- propagateDown(state2, store);
610
- });
639
+ var cacheValue = (key, value, store = IMPLICIT.STORE) => {
640
+ const core = target(store);
641
+ core.valueMap = HAMT3.set(key, value, core.valueMap);
611
642
  };
612
- var setAtomState = (atom2, next, store = IMPLICIT.STORE) => {
613
- var _a, _b;
614
- const oldValue = getState__INTERNAL(atom2, store);
615
- const newValue = become(next)(oldValue);
616
- (_a = store.config.logger) == null ? void 0 : _a.info(
617
- `->`,
618
- `setting atom`,
619
- `"${atom2.key}"`,
620
- `to`,
621
- newValue
622
- );
623
- store.valueMap = HAMT4.set(atom2.key, newValue, store.valueMap);
624
- markDone(atom2.key, store);
625
- atom2.subject.next({ newValue, oldValue });
626
- (_b = store.config.logger) == null ? void 0 : _b.info(
627
- ` ||`,
628
- `propagating change made to`,
629
- `"${atom2.key}"`
630
- );
631
- propagateDown(atom2, store);
643
+ var evictCachedValue = (key, store = IMPLICIT.STORE) => {
644
+ const core = target(store);
645
+ core.valueMap = HAMT3.remove(key, core.valueMap);
632
646
  };
633
- var setSelectorState = (selector2, next, store = IMPLICIT.STORE) => {
634
- var _a, _b;
635
- const oldValue = getState__INTERNAL(selector2, store);
636
- const newValue = become(next)(oldValue);
637
- (_a = store.config.logger) == null ? void 0 : _a.info(
638
- `->`,
639
- `setting selector`,
640
- `"${selector2.key}"`,
641
- `to`,
642
- newValue
643
- );
644
- (_b = store.config.logger) == null ? void 0 : _b.info(
645
- ` ||`,
646
- `propagating change made to`,
647
- `"${selector2.key}"`
647
+ var readCachedValue = (key, store = IMPLICIT.STORE) => HAMT3.get(key, target(store).valueMap);
648
+ var isValueCached = (key, store = IMPLICIT.STORE) => HAMT3.has(key, target(store).valueMap);
649
+ var storeAtom = (atom2, store = IMPLICIT.STORE) => {
650
+ const core = target(store);
651
+ core.atoms = HAMT3.set(atom2.key, atom2, core.atoms);
652
+ };
653
+ var storeSelector = (selector2, store = IMPLICIT.STORE) => {
654
+ const core = target(store);
655
+ core.selectors = HAMT3.set(selector2.key, selector2, core.selectors);
656
+ };
657
+ var storeReadonlySelector = (selector2, store = IMPLICIT.STORE) => {
658
+ const core = target(store);
659
+ core.readonlySelectors = HAMT3.set(
660
+ selector2.key,
661
+ selector2,
662
+ core.readonlySelectors
648
663
  );
649
- selector2.set(newValue);
650
- propagateDown(selector2, store);
651
664
  };
652
- var setState__INTERNAL = (token, value, store = IMPLICIT.STORE) => {
653
- const state = withdraw(token, store);
654
- if (`set` in state) {
655
- setSelectorState(state, value, store);
656
- } else {
657
- setAtomState(state, value, store);
658
- }
665
+ var hasKeyBeenUsed = (key, store = IMPLICIT.STORE) => {
666
+ const core = target(store);
667
+ return HAMT3.has(key, core.atoms) || HAMT3.has(key, core.selectors) || HAMT3.has(key, core.readonlySelectors);
659
668
  };
660
669
 
661
670
  // src/internal/transaction-internal.ts
662
- var finishTransaction = (store) => {
663
- var _a;
664
- store.transaction = { open: false };
665
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F6EC}`, `transaction done`);
666
- };
667
- var startTransaction = (store) => {
671
+ import HAMT4 from "hamt_plus";
672
+ import * as Rx from "rxjs";
673
+ var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
674
+ var buildTransaction = (key, params, store) => {
668
675
  var _a;
669
- store.transaction = {
670
- open: true,
671
- prev: {
676
+ store.transactionStatus = {
677
+ key,
678
+ phase: `building`,
679
+ core: {
672
680
  atoms: store.atoms,
681
+ atomsThatAreDefault: store.atomsThatAreDefault,
682
+ operation: { open: false },
673
683
  readonlySelectors: store.readonlySelectors,
684
+ timelines: store.timelines,
685
+ timelineAtoms: store.timelineAtoms,
686
+ transactions: store.transactions,
687
+ selectorAtoms: store.selectorAtoms,
674
688
  selectorGraph: store.selectorGraph,
675
689
  selectors: store.selectors,
676
690
  valueMap: store.valueMap
677
- }
691
+ },
692
+ atomUpdates: [],
693
+ params,
694
+ output: void 0
678
695
  };
679
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F6EB}`, `transaction start`);
696
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F6EB}`, `transaction "${key}" started`);
697
+ };
698
+ var applyTransaction = (output, store) => {
699
+ var _a, _b, _c;
700
+ if (store.transactionStatus.phase !== `building`) {
701
+ (_a = store.config.logger) == null ? void 0 : _a.warn(
702
+ `abortTransaction called outside of a transaction. This is probably a bug.`
703
+ );
704
+ return;
705
+ }
706
+ (_b = store.config.logger) == null ? void 0 : _b.info(
707
+ ` \u25B6\uFE0F apply transaction "${store.transactionStatus.key}" (init)`
708
+ );
709
+ store.transactionStatus.phase = `applying`;
710
+ store.transactionStatus.output = output;
711
+ const { atomUpdates } = store.transactionStatus;
712
+ for (const { key, oldValue, newValue } of atomUpdates) {
713
+ const token = { key, type: `atom` };
714
+ const state = withdraw(token, store);
715
+ setState(state, newValue, store);
716
+ }
717
+ const myTransaction = withdraw(
718
+ { key: store.transactionStatus.key, type: `transaction` },
719
+ store
720
+ );
721
+ myTransaction.subject.next({
722
+ key: store.transactionStatus.key,
723
+ atomUpdates,
724
+ output,
725
+ params: store.transactionStatus.params
726
+ });
727
+ store.transactionStatus = { phase: `idle` };
728
+ (_c = store.config.logger) == null ? void 0 : _c.info(`\u{1F6EC}`, `transaction done`);
729
+ };
730
+ var undoTransactionUpdate = (update, store) => {
731
+ var _a;
732
+ (_a = store.config.logger) == null ? void 0 : _a.info(` \u23EE undo transaction "${update.key}" (undo)`);
733
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
734
+ const token = { key, type: `atom` };
735
+ const state = withdraw(token, store);
736
+ setState(state, oldValue, store);
737
+ }
738
+ };
739
+ var redoTransactionUpdate = (update, store) => {
740
+ var _a;
741
+ (_a = store.config.logger) == null ? void 0 : _a.info(` \u23ED redo transaction "${update.key}" (redo)`);
742
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
743
+ const token = { key, type: `atom` };
744
+ const state = withdraw(token, store);
745
+ setState(state, newValue, store);
746
+ }
680
747
  };
681
748
  var abortTransaction = (store) => {
682
749
  var _a, _b;
683
- if (!store.transaction.open) {
750
+ if (store.transactionStatus.phase === `idle`) {
684
751
  (_a = store.config.logger) == null ? void 0 : _a.warn(
685
752
  `abortTransaction called outside of a transaction. This is probably a bug.`
686
753
  );
687
754
  return;
688
755
  }
689
- store.atoms = store.transaction.prev.atoms;
690
- store.readonlySelectors = store.transaction.prev.readonlySelectors;
691
- store.selectorGraph = store.transaction.prev.selectorGraph;
692
- store.selectors = store.transaction.prev.selectors;
693
- store.valueMap = store.transaction.prev.valueMap;
694
- store.transaction = { open: false };
756
+ store.transactionStatus = { phase: `idle` };
695
757
  (_b = store.config.logger) == null ? void 0 : _b.info(`\u{1FA82}`, `transaction fail`);
696
758
  };
759
+ function transaction__INTERNAL(options, store = IMPLICIT.STORE) {
760
+ const newTransaction = {
761
+ key: options.key,
762
+ type: `transaction`,
763
+ run: (...params) => {
764
+ var _a;
765
+ buildTransaction(options.key, params, store);
766
+ try {
767
+ const output = options.do(
768
+ {
769
+ get: (token2) => getState(token2, store),
770
+ set: (token2, value) => setState(token2, value, store)
771
+ },
772
+ ...params
773
+ );
774
+ applyTransaction(output, store);
775
+ return output;
776
+ } catch (thrown) {
777
+ abortTransaction(store);
778
+ (_a = store.config.logger) == null ? void 0 : _a.error(`Transaction ${options.key} failed`, thrown);
779
+ throw thrown;
780
+ }
781
+ },
782
+ subject: new Rx.Subject()
783
+ };
784
+ const core = target(store);
785
+ core.transactions = HAMT4.set(
786
+ newTransaction.key,
787
+ newTransaction,
788
+ core.transactions
789
+ );
790
+ const token = deposit(newTransaction);
791
+ return token;
792
+ }
793
+ var target = (store = IMPLICIT.STORE) => store.transactionStatus.phase === `building` ? store.transactionStatus.core : store;
697
794
 
698
- // src/atom.ts
699
- import HAMT5 from "hamt_plus";
700
- import * as Rx from "rxjs";
701
-
702
- // ../anvl/src/json/index.ts
703
- import { pipe as pipe6 } from "fp-ts/function";
704
- var stringifyJson = (json) => JSON.stringify(json);
705
-
706
- // src/atom.ts
707
- var atom = (options, store = IMPLICIT.STORE) => {
795
+ // src/internal/atom-internal.ts
796
+ function atom__INTERNAL(options, family, store = IMPLICIT.STORE) {
708
797
  var _a, _b, _c;
709
- if (HAMT5.has(options.key, store.atoms)) {
798
+ const core = target(store);
799
+ if (hasKeyBeenUsed(options.key, store)) {
710
800
  (_b = (_a = store.config.logger) == null ? void 0 : _a.error) == null ? void 0 : _b.call(
711
801
  _a,
712
802
  `Key "${options.key}" already exists in the store.`
713
803
  );
714
- return deposit(store.atoms.get(options.key));
804
+ return deposit(core.atoms.get(options.key));
715
805
  }
716
- const subject = new Rx.Subject();
717
- const newAtom = __spreadProps(__spreadValues({}, options), { subject });
718
- store.atoms = HAMT5.set(options.key, newAtom, store.atoms);
719
- store.valueMap = HAMT5.set(options.key, options.default, store.valueMap);
806
+ const subject = new Rx2.Subject();
807
+ const newAtom = __spreadValues(__spreadProps(__spreadValues({}, options), {
808
+ subject,
809
+ type: `atom`
810
+ }), family && { family });
811
+ const initialValue = options.default instanceof Function ? options.default() : options.default;
812
+ storeAtom(newAtom, store);
813
+ markAtomAsDefault(options.key, store);
814
+ cacheValue(options.key, initialValue, store);
720
815
  const token = deposit(newAtom);
721
816
  const setSelf = (next) => setState(token, next, store);
722
- const onSet = (observe) => subscribe(token, observe, store);
723
- setSelf(options.default);
817
+ const onSet = (handle) => subscribe(token, handle, store);
724
818
  (_c = options.effects) == null ? void 0 : _c.forEach((effect) => effect({ setSelf, onSet }));
725
819
  return token;
726
- };
727
- var atomFamily = (options, store = IMPLICIT.STORE) => (key) => {
728
- var _a;
729
- const fullKey = `${options.key}__${stringifyJson(key)}`;
730
- const existing = store.atoms.get(fullKey);
731
- if (existing) {
732
- return deposit(existing);
733
- }
734
- return atom(
820
+ }
821
+
822
+ // src/internal/families-internal.ts
823
+ import * as Rx3 from "rxjs";
824
+
825
+ // ../anvl/src/json/index.ts
826
+ import { pipe as pipe6 } from "fp-ts/function";
827
+ var stringifyJson = (json) => JSON.stringify(json);
828
+
829
+ // src/internal/families-internal.ts
830
+ function atomFamily__INTERNAL(options, store = IMPLICIT.STORE) {
831
+ const subject = new Rx3.Subject();
832
+ return Object.assign(
833
+ (key) => {
834
+ var _a;
835
+ const subKey = stringifyJson(key);
836
+ const family = { key: options.key, subKey };
837
+ const fullKey = `${options.key}__${subKey}`;
838
+ const existing = withdraw({ key: fullKey, type: `atom` }, store);
839
+ const token = existing ? deposit(existing) : atom__INTERNAL(
840
+ {
841
+ key: fullKey,
842
+ default: options.default instanceof Function ? options.default(key) : options.default,
843
+ effects: (_a = options.effects) == null ? void 0 : _a.call(options, key)
844
+ },
845
+ family,
846
+ store
847
+ );
848
+ subject.next(token);
849
+ return token;
850
+ },
735
851
  {
736
- key: fullKey,
737
- default: options.default instanceof Function ? options.default(key) : options.default,
738
- effects: (_a = options.effects) == null ? void 0 : _a.call(options, key)
852
+ key: options.key,
853
+ type: `atom_family`,
854
+ subject
855
+ }
856
+ );
857
+ }
858
+ function readonlySelectorFamily__INTERNAL(options, store) {
859
+ const core = target(store);
860
+ const subject = new Rx3.Subject();
861
+ return Object.assign(
862
+ (key) => {
863
+ const subKey = stringifyJson(key);
864
+ const family = { key: options.key, subKey };
865
+ const fullKey = `${options.key}__${subKey}`;
866
+ const existing = core.readonlySelectors.get(fullKey);
867
+ if (existing) {
868
+ return deposit(existing);
869
+ }
870
+ return selector__INTERNAL(
871
+ {
872
+ key: fullKey,
873
+ get: options.get(key)
874
+ },
875
+ family,
876
+ store
877
+ );
739
878
  },
740
- store
879
+ {
880
+ key: options.key,
881
+ type: `readonly_selector_family`,
882
+ subject
883
+ }
884
+ );
885
+ }
886
+ function selectorFamily__INTERNAL(options, store = IMPLICIT.STORE) {
887
+ const isReadonly = !(`set` in options);
888
+ if (isReadonly) {
889
+ return readonlySelectorFamily__INTERNAL(options, store);
890
+ }
891
+ const core = target(store);
892
+ const subject = new Rx3.Subject();
893
+ return Object.assign(
894
+ (key) => {
895
+ const subKey = stringifyJson(key);
896
+ const family = { key: options.key, subKey };
897
+ const fullKey = `${options.key}__${subKey}`;
898
+ const existing = core.selectors.get(fullKey);
899
+ if (existing) {
900
+ return deposit(existing);
901
+ }
902
+ const token = selector__INTERNAL(
903
+ {
904
+ key: fullKey,
905
+ get: options.get(key),
906
+ set: options.set(key)
907
+ },
908
+ family,
909
+ store
910
+ );
911
+ subject.next(token);
912
+ return token;
913
+ },
914
+ {
915
+ key: options.key,
916
+ type: `selector_family`
917
+ }
741
918
  );
919
+ }
920
+
921
+ // src/internal/logger.ts
922
+ var LOG_LEVELS = [
923
+ `info`,
924
+ `warn`,
925
+ `error`
926
+ ];
927
+ var setLogLevel = (preferredLevel, store = IMPLICIT.STORE) => {
928
+ const { logger__INTERNAL } = store.config;
929
+ if (preferredLevel === null) {
930
+ store.config.logger = null;
931
+ } else {
932
+ store.config.logger = __spreadValues({}, console);
933
+ LOG_LEVELS.forEach((logLevel) => {
934
+ if (LOG_LEVELS.indexOf(logLevel) < LOG_LEVELS.indexOf(preferredLevel)) {
935
+ store.config.logger[logLevel] = doNothing;
936
+ } else {
937
+ store.config.logger[logLevel] = logger__INTERNAL[logLevel];
938
+ }
939
+ });
940
+ }
941
+ };
942
+ var useLogger = (logger, store = IMPLICIT.STORE) => {
943
+ var _a;
944
+ const currentLogLevel = store.config.logger === null ? null : (_a = LOG_LEVELS.find(
945
+ (logLevel) => {
946
+ var _a2;
947
+ return ((_a2 = store.config.logger) == null ? void 0 : _a2[logLevel]) !== doNothing;
948
+ }
949
+ )) != null ? _a : null;
950
+ store.config.logger__INTERNAL = __spreadValues({}, logger);
951
+ setLogLevel(currentLogLevel, store);
742
952
  };
743
953
 
744
- // src/selector.ts
745
- import HAMT6 from "hamt_plus";
746
- import * as Rx2 from "rxjs";
747
- function selector(options, store = IMPLICIT.STORE) {
954
+ // src/internal/selector-internal.ts
955
+ import HAMT5 from "hamt_plus";
956
+ import * as Rx4 from "rxjs";
957
+ var lookupSelectorSources = (key, store) => target(store).selectorGraph.getRelations(key).filter(({ source }) => source !== key).map(({ source }) => lookup(source, store));
958
+ var traceSelectorAtoms = (selectorKey, dependency, store) => {
959
+ const roots = [];
960
+ const sources = lookupSelectorSources(dependency.key, store);
961
+ let depth = 0;
962
+ while (sources.length > 0) {
963
+ const source = sources.shift();
964
+ ++depth;
965
+ if (depth > 999) {
966
+ throw new Error(
967
+ `Maximum selector dependency depth exceeded in selector "${selectorKey}".`
968
+ );
969
+ }
970
+ if (source.type !== `atom`) {
971
+ sources.push(...lookupSelectorSources(source.key, store));
972
+ } else {
973
+ roots.push(source);
974
+ }
975
+ }
976
+ return roots;
977
+ };
978
+ var traceAllSelectorAtoms = (selectorKey, store) => {
979
+ const sources = lookupSelectorSources(selectorKey, store);
980
+ return sources.flatMap(
981
+ (source) => source.type === `atom` ? source : traceSelectorAtoms(selectorKey, source, store)
982
+ );
983
+ };
984
+ var updateSelectorAtoms = (selectorKey, dependency, store) => {
748
985
  var _a, _b;
749
- if (HAMT6.has(options.key, store.selectors)) {
750
- throw new Error(`Key "${options.key}" already exists in the store.`);
986
+ const core = target(store);
987
+ if (dependency.type === `atom`) {
988
+ core.selectorAtoms = core.selectorAtoms.set(selectorKey, dependency.key);
989
+ (_a = store.config.logger) == null ? void 0 : _a.info(
990
+ ` || adding root for "${selectorKey}": ${dependency.key}`
991
+ );
992
+ return;
751
993
  }
752
- const subject = new Rx2.Subject();
994
+ const roots = traceSelectorAtoms(selectorKey, dependency, store);
995
+ (_b = store.config.logger) == null ? void 0 : _b.info(
996
+ ` || adding roots for "${selectorKey}":`,
997
+ roots.map((r) => r.key)
998
+ );
999
+ for (const root of roots) {
1000
+ core.selectorAtoms = core.selectorAtoms.set(selectorKey, root.key);
1001
+ }
1002
+ };
1003
+ var registerSelector = (selectorKey, store = IMPLICIT.STORE) => ({
1004
+ get: (dependency) => {
1005
+ var _a, _b;
1006
+ const core = target(store);
1007
+ const alreadyRegistered = core.selectorGraph.getRelations(selectorKey).some(({ source }) => source === dependency.key);
1008
+ const dependencyState = withdraw(dependency, store);
1009
+ const dependencyValue = getState__INTERNAL(dependencyState, store);
1010
+ if (alreadyRegistered) {
1011
+ (_a = store.config.logger) == null ? void 0 : _a.info(
1012
+ ` || ${selectorKey} <- ${dependency.key} =`,
1013
+ dependencyValue
1014
+ );
1015
+ } else {
1016
+ (_b = store.config.logger) == null ? void 0 : _b.info(
1017
+ `\u{1F50C} registerSelector "${selectorKey}" <- "${dependency.key}" =`,
1018
+ dependencyValue
1019
+ );
1020
+ core.selectorGraph = core.selectorGraph.set(selectorKey, dependency.key, {
1021
+ source: dependency.key
1022
+ });
1023
+ }
1024
+ updateSelectorAtoms(selectorKey, dependency, store);
1025
+ return dependencyValue;
1026
+ },
1027
+ set: (stateToken, newValue) => {
1028
+ const state = withdraw(stateToken, store);
1029
+ setState__INTERNAL(state, newValue, store);
1030
+ }
1031
+ });
1032
+ function selector__INTERNAL(options, family, store = IMPLICIT.STORE) {
1033
+ var _a, _b, _c;
1034
+ const core = target(store);
1035
+ if (HAMT5.has(options.key, core.selectors)) {
1036
+ (_a = store.config.logger) == null ? void 0 : _a.error(
1037
+ `Key "${options.key}" already exists in the store.`
1038
+ );
1039
+ }
1040
+ const subject = new Rx4.Subject();
753
1041
  const { get, set } = registerSelector(options.key, store);
754
1042
  const getSelf = () => {
755
1043
  const value = options.get({ get });
756
- store.valueMap = HAMT6.set(options.key, value, store.valueMap);
1044
+ cacheValue(options.key, value, store);
757
1045
  return value;
758
1046
  };
759
1047
  if (!(`set` in options)) {
760
- const readonlySelector = __spreadProps(__spreadValues({}, options), {
1048
+ const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
761
1049
  subject,
762
- get: getSelf
763
- });
764
- store.readonlySelectors = HAMT6.set(
1050
+ get: getSelf,
1051
+ type: `readonly_selector`
1052
+ }), family && { family });
1053
+ core.readonlySelectors = HAMT5.set(
765
1054
  options.key,
766
1055
  readonlySelector,
767
- store.readonlySelectors
1056
+ core.readonlySelectors
768
1057
  );
769
1058
  const initialValue2 = getSelf();
770
- (_a = store.config.logger) == null ? void 0 : _a.info(` \u2728`, options.key, `=`, initialValue2);
1059
+ (_b = store.config.logger) == null ? void 0 : _b.info(` \u2728 "${options.key}" =`, initialValue2);
771
1060
  return __spreadProps(__spreadValues({}, readonlySelector), { type: `readonly_selector` });
772
1061
  }
773
1062
  const setSelf = (next) => {
774
1063
  var _a2;
775
- (_a2 = store.config.logger) == null ? void 0 : _a2.info(`${options.key}.set`, next);
1064
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(` <- "${options.key}" became`, next);
776
1065
  const oldValue = getSelf();
777
1066
  const newValue = become(next)(oldValue);
778
- store.valueMap = HAMT6.set(options.key, newValue, store.valueMap);
1067
+ cacheValue(options.key, newValue, store);
779
1068
  markDone(options.key, store);
780
- subject.next({ newValue, oldValue });
1069
+ if (store.transactionStatus.phase === `idle`) {
1070
+ subject.next({ newValue, oldValue });
1071
+ }
781
1072
  options.set({ get, set }, newValue);
782
1073
  };
783
- const mySelector = __spreadProps(__spreadValues({}, options), {
1074
+ const mySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
784
1075
  subject,
785
1076
  get: getSelf,
786
- set: setSelf
787
- });
788
- store.selectors = HAMT6.set(options.key, mySelector, store.selectors);
1077
+ set: setSelf,
1078
+ type: `selector`
1079
+ }), family && { family });
1080
+ core.selectors = HAMT5.set(options.key, mySelector, core.selectors);
789
1081
  const initialValue = getSelf();
790
- (_b = store.config.logger) == null ? void 0 : _b.info(` \u2728`, options.key, `=`, initialValue);
1082
+ (_c = store.config.logger) == null ? void 0 : _c.info(` \u2728 "${options.key}" =`, initialValue);
791
1083
  return __spreadProps(__spreadValues({}, mySelector), { type: `selector` });
792
1084
  }
793
- function selectorFamily(options, store = IMPLICIT.STORE) {
794
- return (key) => {
795
- var _a;
796
- const fullKey = `${options.key}__${stringifyJson(key)}`;
797
- const existing = (_a = store.selectors.get(fullKey)) != null ? _a : store.readonlySelectors.get(fullKey);
798
- if (existing) {
799
- return deposit(existing);
1085
+
1086
+ // src/internal/set.ts
1087
+ import HAMT6 from "hamt_plus";
1088
+ var evictDownStream = (state, store = IMPLICIT.STORE) => {
1089
+ var _a, _b;
1090
+ const core = target(store);
1091
+ const downstream = core.selectorAtoms.getRelations(state.key);
1092
+ const downstreamKeys = downstream.map(({ id }) => id);
1093
+ (_a = store.config.logger) == null ? void 0 : _a.info(
1094
+ ` || ${downstreamKeys.length} downstream:`,
1095
+ downstreamKeys
1096
+ );
1097
+ if (core.operation.open) {
1098
+ (_b = store.config.logger) == null ? void 0 : _b.info(` ||`, [...core.operation.done], `already done`);
1099
+ }
1100
+ downstream.forEach(({ id: stateKey }) => {
1101
+ var _a2, _b2, _c, _d;
1102
+ if (isDone(stateKey, store)) {
1103
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(` || ${stateKey} already done`);
1104
+ return;
800
1105
  }
801
- const readonlySelectorOptions = {
802
- key: fullKey,
803
- get: options.get(key)
804
- };
805
- if (!(`set` in options)) {
806
- return selector(
807
- __spreadValues({}, readonlySelectorOptions),
808
- store
1106
+ const state2 = (_b2 = HAMT6.get(stateKey, core.selectors)) != null ? _b2 : HAMT6.get(stateKey, core.readonlySelectors);
1107
+ if (!state2) {
1108
+ (_c = store.config.logger) == null ? void 0 : _c.info(
1109
+ ` || ${stateKey} is an atom, and can't be downstream`
809
1110
  );
1111
+ return;
810
1112
  }
811
- return selector(
812
- __spreadProps(__spreadValues({}, readonlySelectorOptions), {
813
- set: options.set(key)
814
- }),
815
- store
1113
+ evictCachedValue(stateKey, store);
1114
+ (_d = store.config.logger) == null ? void 0 : _d.info(` xx evicted "${stateKey}"`);
1115
+ markDone(stateKey, store);
1116
+ });
1117
+ };
1118
+ var setAtomState = (atom2, next, store = IMPLICIT.STORE) => {
1119
+ var _a, _b;
1120
+ const oldValue = getState__INTERNAL(atom2, store);
1121
+ const newValue = become(next)(oldValue);
1122
+ (_a = store.config.logger) == null ? void 0 : _a.info(`<< setting atom "${atom2.key}" to`, newValue);
1123
+ cacheValue(atom2.key, newValue, store);
1124
+ if (isAtomDefault(atom2.key)) {
1125
+ markAtomAsNotDefault(atom2.key, store);
1126
+ }
1127
+ markDone(atom2.key, store);
1128
+ (_b = store.config.logger) == null ? void 0 : _b.info(
1129
+ ` || evicting caches downstream from "${atom2.key}"`
1130
+ );
1131
+ evictDownStream(atom2, store);
1132
+ const update = { oldValue, newValue };
1133
+ if (store.transactionStatus.phase !== `building`) {
1134
+ emitUpdate(atom2, update, store);
1135
+ } else {
1136
+ stowUpdate(atom2, update, store);
1137
+ }
1138
+ };
1139
+ var setSelectorState = (selector2, next, store = IMPLICIT.STORE) => {
1140
+ var _a, _b;
1141
+ const oldValue = getState__INTERNAL(selector2, store);
1142
+ const newValue = become(next)(oldValue);
1143
+ (_a = store.config.logger) == null ? void 0 : _a.info(`<< setting selector "${selector2.key}" to`, newValue);
1144
+ (_b = store.config.logger) == null ? void 0 : _b.info(` || propagating change made to "${selector2.key}"`);
1145
+ selector2.set(newValue);
1146
+ };
1147
+ var setState__INTERNAL = (state, value, store = IMPLICIT.STORE) => {
1148
+ if (`set` in state) {
1149
+ setSelectorState(state, value, store);
1150
+ } else {
1151
+ setAtomState(state, value, store);
1152
+ }
1153
+ };
1154
+
1155
+ // src/internal/subscribe-internal.ts
1156
+ var prepareUpdate = (state, store) => {
1157
+ const oldValue = recallState(state, store);
1158
+ const newValue = getState__INTERNAL(state, store);
1159
+ return { newValue, oldValue };
1160
+ };
1161
+ var stowUpdate = (state, update, store) => {
1162
+ var _a;
1163
+ const { key } = state;
1164
+ const { logger } = store.config;
1165
+ if (store.transactionStatus.phase !== `building`) {
1166
+ (_a = store.config.logger) == null ? void 0 : _a.warn(
1167
+ `stowUpdate called outside of a transaction. This is probably a bug.`
816
1168
  );
1169
+ return;
1170
+ }
1171
+ store.transactionStatus.atomUpdates.push(__spreadValues({ key }, update));
1172
+ logger == null ? void 0 : logger.info(`\u{1F4DD} ${key} stowed (`, update.oldValue, `->`, update.newValue, `)`);
1173
+ };
1174
+ var emitUpdate = (state, update, store) => {
1175
+ const { key } = state;
1176
+ const { logger } = store.config;
1177
+ logger == null ? void 0 : logger.info(
1178
+ `\u{1F4E2} ${state.type} "${key}" went (`,
1179
+ update.oldValue,
1180
+ `->`,
1181
+ update.newValue,
1182
+ `)`
1183
+ );
1184
+ state.subject.next(update);
1185
+ };
1186
+ var subscribeToRootAtoms = (state, store) => {
1187
+ const dependencySubscriptions = `default` in state ? null : traceAllSelectorAtoms(state.key, store).map((atomToken) => {
1188
+ const atom2 = withdraw(atomToken, store);
1189
+ return atom2.subject.subscribe((atomChange) => {
1190
+ var _a, _b;
1191
+ (_a = store.config.logger) == null ? void 0 : _a.info(
1192
+ `\u{1F4E2} selector "${state.key}" saw root "${atomToken.key}" go (`,
1193
+ atomChange.oldValue,
1194
+ `->`,
1195
+ atomChange.newValue,
1196
+ `)`
1197
+ );
1198
+ const oldValue = recallState(state, store);
1199
+ const newValue = getState__INTERNAL(state, store);
1200
+ (_b = store.config.logger) == null ? void 0 : _b.info(` <- ${state.key} became`, newValue);
1201
+ state.subject.next({ newValue, oldValue });
1202
+ });
1203
+ });
1204
+ return dependencySubscriptions;
1205
+ };
1206
+
1207
+ // src/internal/timeline-internal.ts
1208
+ import HAMT7 from "hamt_plus";
1209
+ function timeline__INTERNAL(options, store = IMPLICIT.STORE) {
1210
+ let incompleteTransactionKey = null;
1211
+ const timelineData = {
1212
+ at: 0,
1213
+ timeTraveling: false,
1214
+ history: []
817
1215
  };
818
- }
819
- var registerSelector = (selectorKey, store = IMPLICIT.STORE) => ({
820
- get: (state) => {
821
- var _a, _b, _c;
822
- const isRegistered = store.selectorGraph.getRelatedIds(selectorKey).includes(state.key);
823
- if (isRegistered) {
824
- (_a = store.config.logger) == null ? void 0 : _a.info(` ||`, selectorKey, `<-`, state.key);
825
- } else {
826
- (_b = store.config.logger) == null ? void 0 : _b.info(
827
- `\u{1F50C} registerSelector`,
828
- selectorKey,
829
- `<-`,
830
- state.key
1216
+ const subscribeToAtom = (token) => {
1217
+ const state = withdraw(token, store);
1218
+ state.subject.subscribe((update) => {
1219
+ var _a, _b, _c;
1220
+ const storeCurrentTransactionKey = store.transactionStatus.phase === `applying` ? store.transactionStatus.key : null;
1221
+ (_a = store.config.logger) == null ? void 0 : _a.info(
1222
+ `\u23F3 timeline "${options.key}" saw atom "${token.key}" go (`,
1223
+ update.oldValue,
1224
+ `->`,
1225
+ update.newValue,
1226
+ storeCurrentTransactionKey ? `) in "${storeCurrentTransactionKey}"` : `) independently`
831
1227
  );
832
- store.selectorGraph = store.selectorGraph.set(selectorKey, state.key);
1228
+ if (storeCurrentTransactionKey && store.transactionStatus.phase === `applying`) {
1229
+ const currentTransaction = withdraw(
1230
+ { key: storeCurrentTransactionKey, type: `transaction` },
1231
+ store
1232
+ );
1233
+ if (incompleteTransactionKey !== storeCurrentTransactionKey) {
1234
+ if (incompleteTransactionKey) {
1235
+ (_b = store.config.logger) == null ? void 0 : _b.error(
1236
+ `Timeline "${options.key}" was unable to resolve transaction "${incompleteTransactionKey}. This is probably a bug.`
1237
+ );
1238
+ }
1239
+ incompleteTransactionKey = storeCurrentTransactionKey;
1240
+ const subscription = currentTransaction.subject.subscribe((update2) => {
1241
+ var _a2;
1242
+ if (timelineData.timeTraveling === false) {
1243
+ timelineData.history.push(__spreadProps(__spreadValues({
1244
+ type: `transaction_update`
1245
+ }, update2), {
1246
+ atomUpdates: update2.atomUpdates.filter(
1247
+ (atomUpdate) => options.atoms.some((atom2) => atom2.key === atomUpdate.key)
1248
+ )
1249
+ }));
1250
+ }
1251
+ timelineData.at = timelineData.history.length;
1252
+ subscription.unsubscribe();
1253
+ incompleteTransactionKey = null;
1254
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(
1255
+ `\u231B timeline "${options.key}" pushed a transaction_update from "${update2.key}"`
1256
+ );
1257
+ });
1258
+ }
1259
+ } else {
1260
+ if (timelineData.timeTraveling === false) {
1261
+ timelineData.history.push({
1262
+ type: `state_update`,
1263
+ key: token.key,
1264
+ oldValue: update.oldValue,
1265
+ newValue: update.newValue
1266
+ });
1267
+ (_c = store.config.logger) == null ? void 0 : _c.info(
1268
+ `\u231B timeline "${options.key}" pushed a state_update to "${token.key}"`
1269
+ );
1270
+ timelineData.at = timelineData.history.length;
1271
+ }
1272
+ }
1273
+ });
1274
+ };
1275
+ for (const tokenOrFamily of options.atoms) {
1276
+ if (tokenOrFamily.type === `atom_family`) {
1277
+ const family = tokenOrFamily;
1278
+ family.subject.subscribe((token) => subscribeToAtom(token));
1279
+ } else {
1280
+ const token = tokenOrFamily;
1281
+ subscribeToAtom(token);
833
1282
  }
834
- const currentValue = getState(state, store);
835
- (_c = store.config.logger) == null ? void 0 : _c.info(` ||`, state.key, `=`, currentValue);
836
- return currentValue;
837
- },
838
- set: (token, newValue) => {
839
- store.selectorGraph.set(token.key, selectorKey);
840
- setState__INTERNAL(token, newValue, store);
841
1283
  }
842
- });
1284
+ store.timelineStore = HAMT7.set(options.key, timelineData, store.timelineStore);
1285
+ return {
1286
+ key: options.key,
1287
+ type: `timeline`
1288
+ };
1289
+ }
1290
+ var redo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1291
+ var _a, _b;
1292
+ const timelineData = store.timelineStore.get(token.key);
1293
+ if (!timelineData) {
1294
+ (_a = store.config.logger) == null ? void 0 : _a.error(
1295
+ `Tried to redo on timeline "${token.key}" has not been initialized.`
1296
+ );
1297
+ return;
1298
+ }
1299
+ if (timelineData.at === timelineData.history.length) {
1300
+ (_b = store.config.logger) == null ? void 0 : _b.warn(
1301
+ `Tried to redo on timeline "${token.key}" but there is nothing to redo.`
1302
+ );
1303
+ return;
1304
+ }
1305
+ timelineData.timeTraveling = true;
1306
+ const update = timelineData.history[timelineData.at];
1307
+ switch (update.type) {
1308
+ case `state_update`: {
1309
+ const { key, newValue } = update;
1310
+ setState({ key, type: `atom` }, newValue);
1311
+ break;
1312
+ }
1313
+ case `transaction_update`: {
1314
+ for (const atomUpdate of update.atomUpdates) {
1315
+ const { key, newValue } = atomUpdate;
1316
+ setState({ key, type: `atom` }, newValue);
1317
+ }
1318
+ break;
1319
+ }
1320
+ }
1321
+ ++timelineData.at;
1322
+ timelineData.timeTraveling = false;
1323
+ };
1324
+ var undo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1325
+ var _a, _b;
1326
+ const timelineData = store.timelineStore.get(token.key);
1327
+ if (!timelineData) {
1328
+ (_a = store.config.logger) == null ? void 0 : _a.error(
1329
+ `Tried to undo on timeline "${token.key}" has not been initialized.`
1330
+ );
1331
+ return;
1332
+ }
1333
+ if (timelineData.at === 0) {
1334
+ (_b = store.config.logger) == null ? void 0 : _b.warn(
1335
+ `Tried to undo on timeline "${token.key}" but there is nothing to undo.`
1336
+ );
1337
+ return;
1338
+ }
1339
+ timelineData.timeTraveling = true;
1340
+ --timelineData.at;
1341
+ const update = timelineData.history[timelineData.at];
1342
+ switch (update.type) {
1343
+ case `state_update`: {
1344
+ const { key, oldValue } = update;
1345
+ setState({ key, type: `atom` }, oldValue);
1346
+ break;
1347
+ }
1348
+ case `transaction_update`: {
1349
+ for (const atomUpdate of update.atomUpdates) {
1350
+ const { key, oldValue } = atomUpdate;
1351
+ setState({ key, type: `atom` }, oldValue);
1352
+ }
1353
+ break;
1354
+ }
1355
+ }
1356
+ timelineData.timeTraveling = false;
1357
+ };
1358
+
1359
+ // src/atom.ts
1360
+ function atom(options) {
1361
+ return atom__INTERNAL(options);
1362
+ }
1363
+ function atomFamily(options) {
1364
+ return atomFamily__INTERNAL(options);
1365
+ }
1366
+
1367
+ // src/selector.ts
1368
+ function selector(options) {
1369
+ return selector__INTERNAL(options);
1370
+ }
1371
+ function selectorFamily(options) {
1372
+ return selectorFamily__INTERNAL(options);
1373
+ }
1374
+
1375
+ // src/timeline.ts
1376
+ var timeline = (options) => {
1377
+ return timeline__INTERNAL(options);
1378
+ };
1379
+ var redo = (token) => {
1380
+ return redo__INTERNAL(token, IMPLICIT.STORE);
1381
+ };
1382
+ var undo = (token) => {
1383
+ return undo__INTERNAL(token, IMPLICIT.STORE);
1384
+ };
843
1385
 
844
1386
  // src/transaction.ts
845
- var transaction = (options, store = IMPLICIT.STORE) => Object.assign(
846
- (...parameters) => {
847
- var _a;
848
- startTransaction(store);
849
- try {
850
- const result = options.do(
851
- {
852
- get: (token) => getState(token, store),
853
- set: (token, value) => setState(token, value, store)
854
- },
855
- ...parameters
856
- );
857
- finishTransaction(store);
858
- return result;
859
- } catch (thrown) {
860
- abortTransaction(store);
861
- (_a = store.config.logger) == null ? void 0 : _a.error(`Transaction ${options.key} failed`, thrown);
862
- throw thrown;
1387
+ function transaction(options) {
1388
+ return transaction__INTERNAL(options);
1389
+ }
1390
+ var runTransaction = (token, store = IMPLICIT.STORE) => (...parameters) => withdraw(token, store).run(...parameters);
1391
+
1392
+ // src/subscribe.ts
1393
+ var subscribe = (token, handleUpdate, store = IMPLICIT.STORE) => {
1394
+ var _a;
1395
+ const state = withdraw(token, store);
1396
+ const subscription = state.subject.subscribe(handleUpdate);
1397
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F440} subscribe to "${state.key}"`);
1398
+ const dependencySubscriptions = `get` in state ? subscribeToRootAtoms(state, store) : null;
1399
+ const unsubscribe = dependencySubscriptions === null ? () => {
1400
+ var _a2;
1401
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(`\u{1F648} unsubscribe from "${state.key}"`);
1402
+ subscription.unsubscribe();
1403
+ } : () => {
1404
+ var _a2;
1405
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(
1406
+ `\u{1F648} unsubscribe from "${state.key}" and its dependencies`
1407
+ );
1408
+ subscription.unsubscribe();
1409
+ for (const dependencySubscription of dependencySubscriptions) {
1410
+ dependencySubscription.unsubscribe();
863
1411
  }
864
- },
865
- { key: options.key }
866
- );
1412
+ };
1413
+ return unsubscribe;
1414
+ };
1415
+ var subscribeToTransaction = (token, handleUpdate, store = IMPLICIT.STORE) => {
1416
+ var _a;
1417
+ const tx = withdraw(token, store);
1418
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F440} subscribe to transaction "${token.key}"`);
1419
+ const subscription = tx.subject.subscribe(handleUpdate);
1420
+ const unsubscribe = () => {
1421
+ var _a2;
1422
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(`\u{1F648} unsubscribe from transaction "${token.key}"`);
1423
+ subscription.unsubscribe();
1424
+ };
1425
+ return unsubscribe;
1426
+ };
867
1427
 
868
1428
  // src/index.ts
869
1429
  var getState = (token, store = IMPLICIT.STORE) => {
870
1430
  const state = withdraw(token, store);
871
1431
  return getState__INTERNAL(state, store);
872
1432
  };
873
- var setState = (state, value, store = IMPLICIT.STORE) => {
874
- startAction(store);
875
- setState__INTERNAL(state, value, store);
876
- finishAction(store);
877
- };
878
- var subscribe = (token, observe, store = IMPLICIT.STORE) => {
1433
+ var setState = (token, value, store = IMPLICIT.STORE) => {
1434
+ openOperation(store);
879
1435
  const state = withdraw(token, store);
880
- const subscription = state.subject.subscribe(observe);
881
- return () => subscription.unsubscribe();
1436
+ setState__INTERNAL(state, value, store);
1437
+ closeOperation(store);
882
1438
  };
1439
+ var isDefault = (token, store = IMPLICIT.STORE) => token.type === `atom` ? isAtomDefault(token.key, store) : isSelectorDefault(token.key, store);
883
1440
  export {
884
1441
  internal_exports as __INTERNAL__,
885
1442
  atom,
886
1443
  atomFamily,
887
- configure,
888
1444
  getState,
889
- registerSelector,
1445
+ isDefault,
1446
+ redo,
1447
+ runTransaction,
890
1448
  selector,
891
1449
  selectorFamily,
1450
+ setLogLevel,
892
1451
  setState,
893
1452
  subscribe,
894
- transaction
1453
+ subscribeToTransaction,
1454
+ timeline,
1455
+ transaction,
1456
+ undo,
1457
+ useLogger
895
1458
  };
896
1459
  //# sourceMappingURL=index.mjs.map