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