atom.io 0.2.0 → 0.3.1

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