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