atom.io 0.3.0 → 0.4.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.
Files changed (55) hide show
  1. package/README.md +14 -8
  2. package/dist/index.d.ts +117 -62
  3. package/dist/index.js +577 -287
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +574 -285
  6. package/dist/index.mjs.map +1 -1
  7. package/package.json +16 -6
  8. package/react/dist/index.d.ts +12 -17
  9. package/react/dist/index.js +25 -34
  10. package/react/dist/index.js.map +1 -1
  11. package/react/dist/index.mjs +21 -34
  12. package/react/dist/index.mjs.map +1 -1
  13. package/react-devtools/dist/index.css +26 -0
  14. package/react-devtools/dist/index.css.map +1 -0
  15. package/react-devtools/dist/index.d.ts +15 -0
  16. package/react-devtools/dist/index.js +1579 -0
  17. package/react-devtools/dist/index.js.map +1 -0
  18. package/react-devtools/dist/index.mjs +1551 -0
  19. package/react-devtools/dist/index.mjs.map +1 -0
  20. package/react-devtools/package.json +15 -0
  21. package/src/index.ts +14 -8
  22. package/src/internal/atom-internal.ts +10 -5
  23. package/src/internal/families-internal.ts +7 -7
  24. package/src/internal/get.ts +9 -9
  25. package/src/internal/index.ts +2 -1
  26. package/src/internal/meta/attach-meta.ts +17 -0
  27. package/src/internal/meta/index.ts +4 -0
  28. package/src/internal/meta/meta-state.ts +135 -0
  29. package/src/internal/meta/meta-timelines.ts +1 -0
  30. package/src/internal/meta/meta-transactions.ts +1 -0
  31. package/src/internal/operation.ts +14 -3
  32. package/src/internal/selector-internal.ts +37 -15
  33. package/src/internal/store.ts +35 -6
  34. package/src/internal/time-travel-internal.ts +89 -0
  35. package/src/internal/timeline-internal.ts +110 -93
  36. package/src/internal/transaction-internal.ts +14 -5
  37. package/src/{internal/logger.ts → logger.ts} +2 -2
  38. package/src/react/index.ts +28 -46
  39. package/src/react-devtools/AtomIODevtools.tsx +107 -0
  40. package/src/react-devtools/StateEditor.tsx +73 -0
  41. package/src/react-devtools/TokenList.tsx +49 -0
  42. package/src/react-devtools/devtools.scss +130 -0
  43. package/src/react-devtools/index.ts +1 -0
  44. package/src/react-explorer/AtomIOExplorer.tsx +208 -0
  45. package/src/react-explorer/explorer-effects.ts +20 -0
  46. package/src/react-explorer/explorer-states.ts +224 -0
  47. package/src/react-explorer/index.ts +23 -0
  48. package/src/react-explorer/space-states.ts +73 -0
  49. package/src/react-explorer/view-states.ts +43 -0
  50. package/src/selector.ts +11 -11
  51. package/src/subscribe.ts +3 -3
  52. package/src/timeline.ts +3 -12
  53. package/src/transaction.ts +9 -4
  54. package/src/web-effects/index.ts +1 -0
  55. package/src/web-effects/storage.ts +30 -0
package/dist/index.mjs CHANGED
@@ -18,27 +18,27 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
  var __objRest = (source, exclude) => {
21
- var target3 = {};
21
+ var target2 = {};
22
22
  for (var prop in source)
23
23
  if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
- target3[prop] = source[prop];
24
+ target2[prop] = source[prop];
25
25
  if (source != null && __getOwnPropSymbols)
26
26
  for (var prop of __getOwnPropSymbols(source)) {
27
27
  if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
- target3[prop] = source[prop];
28
+ target2[prop] = source[prop];
29
29
  }
30
- return target3;
30
+ return target2;
31
31
  };
32
- var __export = (target3, all) => {
32
+ var __export = (target2, all) => {
33
33
  for (var name in all)
34
- __defProp(target3, name, { get: all[name], enumerable: true });
34
+ __defProp(target2, name, { get: all[name], enumerable: true });
35
35
  };
36
36
 
37
37
  // src/internal/index.ts
38
38
  var internal_exports = {};
39
39
  __export(internal_exports, {
40
40
  IMPLICIT: () => IMPLICIT,
41
- LOG_LEVELS: () => LOG_LEVELS,
41
+ META: () => meta_exports,
42
42
  TRANSACTION_PHASES: () => TRANSACTION_PHASES,
43
43
  abortTransaction: () => abortTransaction,
44
44
  applyTransaction: () => applyTransaction,
@@ -76,7 +76,6 @@ __export(internal_exports, {
76
76
  selectorFamily__INTERNAL: () => selectorFamily__INTERNAL,
77
77
  selector__INTERNAL: () => selector__INTERNAL,
78
78
  setAtomState: () => setAtomState,
79
- setLogLevel: () => setLogLevel,
80
79
  setSelectorState: () => setSelectorState,
81
80
  setState__INTERNAL: () => setState__INTERNAL,
82
81
  storeAtom: () => storeAtom,
@@ -92,12 +91,12 @@ __export(internal_exports, {
92
91
  undoTransactionUpdate: () => undoTransactionUpdate,
93
92
  undo__INTERNAL: () => undo__INTERNAL,
94
93
  updateSelectorAtoms: () => updateSelectorAtoms,
95
- useLogger: () => useLogger,
96
94
  withdraw: () => withdraw
97
95
  });
98
96
 
99
97
  // src/internal/atom-internal.ts
100
- import * as Rx2 from "rxjs";
98
+ import HAMT5 from "hamt_plus";
99
+ import * as Rx3 from "rxjs";
101
100
 
102
101
  // src/internal/get.ts
103
102
  import HAMT from "hamt_plus";
@@ -124,7 +123,7 @@ var getState__INTERNAL = (state, store = IMPLICIT.STORE) => {
124
123
  (_a = store.config.logger) == null ? void 0 : _a.info(`>> read "${state.key}"`);
125
124
  return readCachedValue(state.key, store);
126
125
  }
127
- if (`get` in state) {
126
+ if (state.type !== `atom`) {
128
127
  (_b = store.config.logger) == null ? void 0 : _b.info(`-> calc "${state.key}"`);
129
128
  return computeSelectorState(state);
130
129
  }
@@ -158,6 +157,7 @@ import HAMT3 from "hamt_plus";
158
157
 
159
158
  // src/internal/store.ts
160
159
  import HAMT2 from "hamt_plus";
160
+ import * as Rx from "rxjs";
161
161
 
162
162
  // ../anvl/src/function/index.ts
163
163
  var doNothing = () => void 0;
@@ -249,18 +249,68 @@ var hasExactProperties = (
249
249
  (isValue) => hasProperties(isValue, { allowExtraProperties: false })
250
250
  );
251
251
 
252
+ // ../anvl/src/refinement/index.ts
253
+ var canExist = (_) => true;
254
+ var cannotExist = (_) => false;
255
+ var isLiteral = (value) => (input) => input === value;
256
+ var couldBe = (isTypeA, logging = false, refinements = [isTypeA]) => {
257
+ const name = `(${refinements.map((r) => r.name || `anon`).join(` | `)})`;
258
+ const _ = {
259
+ [name]: (input) => refinements.some(
260
+ (refinement) => {
261
+ var _a;
262
+ return logging && console.log(
263
+ refinements.map((r) => r.name || `anon`).join(` | `),
264
+ `>`,
265
+ (_a = refinement.name) != null ? _a : `anon`,
266
+ `:`,
267
+ refinement(input)
268
+ ), refinement(input);
269
+ }
270
+ )
271
+ };
272
+ const checkTypes = Object.assign(_[name], {
273
+ or: (isTypeB) => couldBe(isTypeB, logging, [...refinements, isTypeB])
274
+ });
275
+ return checkTypes;
276
+ };
277
+ var isUnion = couldBe(cannotExist);
278
+ var mustBe = (isTypeA, logging = false, refinements = [isTypeA]) => {
279
+ const name = `(${refinements.map((r) => r.name || `anon`).join(` & `)})`;
280
+ const _ = {
281
+ [name]: (input) => refinements.every(
282
+ (refinement) => (logging && console.log(
283
+ refinements.map((r) => r.name || `anon`).join(` & `),
284
+ `>`,
285
+ refinement.name || `anon`,
286
+ `:`,
287
+ refinement(input)
288
+ ), refinement(input))
289
+ )
290
+ };
291
+ const checkTypes = Object.assign(_[name], {
292
+ and: (isTypeB) => mustBe(isTypeB, logging, [...refinements, isTypeB])
293
+ });
294
+ return checkTypes;
295
+ };
296
+ var isIntersection = mustBe(canExist);
297
+
252
298
  // ../anvl/src/join/core-relation-data.ts
253
299
  var RELATION_TYPES = [`1:1`, `1:n`, `n:n`];
254
300
  var isRelationType = (x) => RELATION_TYPES.includes(x);
255
301
  var EMPTY_RELATION_DATA = {
256
302
  contents: {},
257
303
  relations: {},
258
- relationType: `n:n`
304
+ relationType: `n:n`,
305
+ a: `from`,
306
+ b: `to`
259
307
  };
260
- var isRelationData = (isContent) => (input) => hasExactProperties({
308
+ var isRelationData = (isContent, a = `from`, b = `to`) => (input) => hasExactProperties({
261
309
  contents: isContent ? isRecord(isString, isContent) : hasExactProperties({}),
262
310
  relations: isRecord(isString, isArray(isString)),
263
- relationType: isRelationType
311
+ relationType: isRelationType,
312
+ a: isLiteral(a),
313
+ b: isLiteral(b)
264
314
  })(input);
265
315
 
266
316
  // ../anvl/src/join/get-related-ids.ts
@@ -349,7 +399,11 @@ var removeAll = (current, idToRemove) => {
349
399
  });
350
400
  return next;
351
401
  };
352
- var removeRelation = (current, idA, idB) => idB ? removeSpecific(current, idA, idB) : removeAll(current, idA);
402
+ var removeRelation = (current, relation) => {
403
+ const idA = relation[current.a];
404
+ const idB = relation[current.b];
405
+ return idB ? removeSpecific(current, idA, idB) : removeAll(current, idA);
406
+ };
353
407
 
354
408
  // ../anvl/src/join/set-relation.ts
355
409
  var setManyToMany = (map2, idA, idB, ...rest) => {
@@ -393,7 +447,8 @@ var set1To1 = (current, wifeId, husbandId, ...rest) => {
393
447
  const content = rest[0];
394
448
  return content ? setContent(next, wifeId, husbandId, content) : next;
395
449
  };
396
- var setRelationWithContent = (current, idA, idB, ...rest) => {
450
+ var setRelationWithContent = (current, relation, ...rest) => {
451
+ const { [current.a]: idA, [current.b]: idB } = relation;
397
452
  switch (current.relationType) {
398
453
  case `1:1`:
399
454
  return set1To1(current, idA, idB, ...rest);
@@ -417,96 +472,69 @@ var getRelations = (relationMap, id) => getRelationEntries(relationMap, id).map(
417
472
  id: id2
418
473
  }, content)
419
474
  );
420
- var setRelations = (current, idA, relations) => pipe5(
421
- current,
422
- (relationData) => {
423
- const relatedIds = getRelatedIds(current, idA);
424
- const removedIds = relatedIds.filter(
425
- (id) => !relations.some((r) => r.id === id)
426
- );
427
- let step = relationData;
428
- for (const idB of removedIds)
429
- step = removeRelation(step, idA, idB);
430
- return step;
431
- },
432
- (relationData) => {
433
- let step = relationData;
434
- for (const _a of relations) {
435
- const _b = _a, { id: idB } = _b, rest = __objRest(_b, ["id"]);
436
- const content = isEmptyObject(rest) ? void 0 : rest;
437
- step = setRelationWithContent(step, idA, idB, content);
438
- }
439
- return step;
440
- },
441
- (relationData) => {
442
- const newlyOrderedIds = relations.map((r) => r.id);
443
- return __spreadProps(__spreadValues({}, relationData), {
444
- relations: __spreadProps(__spreadValues({}, relationData.relations), {
445
- [idA]: newlyOrderedIds
446
- })
447
- });
448
- }
449
- );
450
-
451
- // ../anvl/src/refinement/index.ts
452
- var canExist = (_) => true;
453
- var cannotExist = (_) => false;
454
- var couldBe = (isTypeA, logging = false, refinements = [isTypeA]) => {
455
- const name = `(${refinements.map((r) => r.name || `anon`).join(` | `)})`;
456
- const _ = {
457
- [name]: (input) => refinements.some(
458
- (refinement) => {
459
- var _a;
460
- return logging && console.log(
461
- refinements.map((r) => r.name || `anon`).join(` | `),
462
- `>`,
463
- (_a = refinement.name) != null ? _a : `anon`,
464
- `:`,
465
- refinement(input)
466
- ), refinement(input);
475
+ var setRelations = (current, subject, relations) => {
476
+ const idA = subject[current.a];
477
+ const idB = subject[current.b];
478
+ return pipe5(
479
+ current,
480
+ (relationData) => {
481
+ const relatedIds = getRelatedIds(current, idA);
482
+ const removedIds = relatedIds.filter(
483
+ (id) => !relations.some((r) => r.id === id)
484
+ );
485
+ let step = relationData;
486
+ for (const id of removedIds) {
487
+ const remove = {
488
+ [current.a]: idA != null ? idA : id,
489
+ [current.b]: idB != null ? idB : id
490
+ };
491
+ step = removeRelation(step, remove);
467
492
  }
468
- )
469
- };
470
- const checkTypes = Object.assign(_[name], {
471
- or: (isTypeB) => couldBe(isTypeB, logging, [...refinements, isTypeB])
472
- });
473
- return checkTypes;
474
- };
475
- var isUnion = couldBe(cannotExist);
476
- var mustBe = (isTypeA, logging = false, refinements = [isTypeA]) => {
477
- const name = `(${refinements.map((r) => r.name || `anon`).join(` & `)})`;
478
- const _ = {
479
- [name]: (input) => refinements.every(
480
- (refinement) => (logging && console.log(
481
- refinements.map((r) => r.name || `anon`).join(` & `),
482
- `>`,
483
- refinement.name || `anon`,
484
- `:`,
485
- refinement(input)
486
- ), refinement(input))
487
- )
488
- };
489
- const checkTypes = Object.assign(_[name], {
490
- and: (isTypeB) => mustBe(isTypeB, logging, [...refinements, isTypeB])
491
- });
492
- return checkTypes;
493
+ return step;
494
+ },
495
+ (relationData) => {
496
+ let step = relationData;
497
+ for (const _a of relations) {
498
+ const _b = _a, { id } = _b, rest = __objRest(_b, ["id"]);
499
+ const content = isEmptyObject(rest) ? void 0 : rest;
500
+ step = setRelationWithContent(
501
+ step,
502
+ { [current.a]: idA != null ? idA : id, [current.b]: idB != null ? idB : id },
503
+ // @ts-expect-error hacky
504
+ content
505
+ );
506
+ }
507
+ return step;
508
+ },
509
+ (relationData) => {
510
+ const newlyOrderedIds = relations.map((r) => r.id);
511
+ return __spreadProps(__spreadValues({}, relationData), {
512
+ relations: __spreadProps(__spreadValues({}, relationData.relations), {
513
+ [idA != null ? idA : idB]: newlyOrderedIds
514
+ })
515
+ });
516
+ }
517
+ );
493
518
  };
494
- var isIntersection = mustBe(canExist);
495
519
 
496
520
  // ../anvl/src/join/index.ts
497
521
  var Join = class {
498
522
  constructor(json) {
523
+ this.a = `from`;
524
+ this.b = `to`;
499
525
  Object.assign(this, __spreadValues(__spreadValues({}, EMPTY_RELATION_DATA), json));
500
526
  }
501
527
  toJSON() {
502
528
  return {
503
529
  relationType: this.relationType,
504
530
  relations: this.relations,
505
- contents: this.contents
531
+ contents: this.contents,
532
+ a: this.a,
533
+ b: this.b
506
534
  };
507
535
  }
508
- static fromJSON(json, isContent = cannotExist) {
509
- const isValid = isRelationData(isContent)(json);
536
+ static fromJSON(json, isContent = cannotExist, a = `from`, b = `to`) {
537
+ const isValid = isRelationData(isContent, a, b)(json);
510
538
  if (isValid) {
511
539
  return new Join(json);
512
540
  }
@@ -514,6 +542,12 @@ var Join = class {
514
542
  `Saved JSON for this Join is invalid: ${JSON.stringify(json)}`
515
543
  );
516
544
  }
545
+ from(newA) {
546
+ return new Join(__spreadProps(__spreadValues({}, this), { a: newA }));
547
+ }
548
+ to(newB) {
549
+ return new Join(__spreadProps(__spreadValues({}, this), { b: newB }));
550
+ }
517
551
  getRelatedId(id) {
518
552
  return getRelatedId(this, id);
519
553
  }
@@ -535,14 +569,16 @@ var Join = class {
535
569
  getRelations(id) {
536
570
  return getRelations(this, id);
537
571
  }
538
- setRelations(id, relations) {
539
- return new Join(setRelations(this, id, relations));
572
+ setRelations(subject, relations) {
573
+ return new Join(setRelations(this, subject, relations));
540
574
  }
541
- set(idA, idB, ...rest) {
542
- return new Join(setRelationWithContent(this, idA, idB, ...rest));
575
+ set(relation, ...rest) {
576
+ return new Join(setRelationWithContent(this, relation, ...rest));
543
577
  }
544
- remove(idA, idB) {
545
- return new Join(removeRelation(this, idA, idB));
578
+ remove(relation) {
579
+ return new Join(
580
+ removeRelation(this, relation)
581
+ );
546
582
  }
547
583
  };
548
584
 
@@ -551,14 +587,20 @@ var createStore = (name) => ({
551
587
  atoms: HAMT2.make(),
552
588
  atomsThatAreDefault: /* @__PURE__ */ new Set(),
553
589
  readonlySelectors: HAMT2.make(),
554
- selectorAtoms: new Join({ relationType: `n:n` }),
590
+ selectorAtoms: new Join({ relationType: `n:n` }).from(`selectorKey`).to(`atomKey`),
555
591
  selectorGraph: new Join({ relationType: `n:n` }),
556
592
  selectors: HAMT2.make(),
557
593
  timelines: HAMT2.make(),
558
- timelineAtoms: new Join({ relationType: `1:n` }),
594
+ timelineAtoms: new Join({ relationType: `1:n` }).from(`timelineKey`).to(`atomKey`),
559
595
  timelineStore: HAMT2.make(),
560
596
  transactions: HAMT2.make(),
561
597
  valueMap: HAMT2.make(),
598
+ subject: {
599
+ atomCreation: new Rx.Subject(),
600
+ selectorCreation: new Rx.Subject(),
601
+ transactionCreation: new Rx.Subject(),
602
+ timelineCreation: new Rx.Subject()
603
+ },
562
604
  operation: {
563
605
  open: false
564
606
  },
@@ -587,21 +629,29 @@ var clearStore = (store = IMPLICIT.STORE) => {
587
629
  };
588
630
 
589
631
  // src/internal/operation.ts
590
- var openOperation = (store) => {
591
- var _a;
632
+ var openOperation = (token, store) => {
633
+ var _a, _b;
592
634
  const core = target(store);
635
+ if (core.operation.open) {
636
+ (_a = store.config.logger) == null ? void 0 : _a.error(
637
+ `\u274C failed to setState to "${token.key}" during a setState for "${core.operation.token.key}"`
638
+ );
639
+ throw Symbol(`violation`);
640
+ }
593
641
  core.operation = {
594
642
  open: true,
595
643
  done: /* @__PURE__ */ new Set(),
596
- prev: store.valueMap
644
+ prev: store.valueMap,
645
+ time: Date.now(),
646
+ token
597
647
  };
598
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u2B55`, `operation start`);
648
+ (_b = store.config.logger) == null ? void 0 : _b.info(`\u2B55 operation start from "${token.key}"`);
599
649
  };
600
650
  var closeOperation = (store) => {
601
651
  var _a;
602
652
  const core = target(store);
603
653
  core.operation = { open: false };
604
- (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F534}`, `operation done`);
654
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F534} operation done`);
605
655
  };
606
656
  var isDone = (key, store = IMPLICIT.STORE) => {
607
657
  var _a;
@@ -669,7 +719,7 @@ var hasKeyBeenUsed = (key, store = IMPLICIT.STORE) => {
669
719
 
670
720
  // src/internal/transaction-internal.ts
671
721
  import HAMT4 from "hamt_plus";
672
- import * as Rx from "rxjs";
722
+ import * as Rx2 from "rxjs";
673
723
  var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
674
724
  var buildTransaction = (key, params, store) => {
675
725
  var _a;
@@ -696,7 +746,7 @@ var buildTransaction = (key, params, store) => {
696
746
  (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F6EB}`, `transaction "${key}" started`);
697
747
  };
698
748
  var applyTransaction = (output, store) => {
699
- var _a, _b, _c;
749
+ var _a, _b, _c, _d;
700
750
  if (store.transactionStatus.phase !== `building`) {
701
751
  (_a = store.config.logger) == null ? void 0 : _a.warn(
702
752
  `abortTransaction called outside of a transaction. This is probably a bug.`
@@ -704,13 +754,19 @@ var applyTransaction = (output, store) => {
704
754
  return;
705
755
  }
706
756
  (_b = store.config.logger) == null ? void 0 : _b.info(
707
- ` \u25B6\uFE0F apply transaction "${store.transactionStatus.key}" (init)`
757
+ `\u{1F6C3} apply transaction "${store.transactionStatus.key}"`
708
758
  );
709
759
  store.transactionStatus.phase = `applying`;
710
760
  store.transactionStatus.output = output;
711
761
  const { atomUpdates } = store.transactionStatus;
712
- for (const { key, oldValue, newValue } of atomUpdates) {
762
+ for (const { key, newValue } of atomUpdates) {
713
763
  const token = { key, type: `atom` };
764
+ if (!HAMT4.has(token.key, store.valueMap)) {
765
+ const atom2 = HAMT4.get(token.key, store.transactionStatus.core.atoms);
766
+ store.atoms = HAMT4.set(atom2.key, atom2, store.atoms);
767
+ store.valueMap = HAMT4.set(atom2.key, atom2.default, store.valueMap);
768
+ (_c = store.config.logger) == null ? void 0 : _c.info(`\u{1F527}`, `add atom "${atom2.key}"`);
769
+ }
714
770
  const state = withdraw(token, store);
715
771
  setState(state, newValue, store);
716
772
  }
@@ -725,12 +781,12 @@ var applyTransaction = (output, store) => {
725
781
  params: store.transactionStatus.params
726
782
  });
727
783
  store.transactionStatus = { phase: `idle` };
728
- (_c = store.config.logger) == null ? void 0 : _c.info(`\u{1F6EC}`, `transaction done`);
784
+ (_d = store.config.logger) == null ? void 0 : _d.info(`\u{1F6EC}`, `transaction done`);
729
785
  };
730
786
  var undoTransactionUpdate = (update, store) => {
731
787
  var _a;
732
788
  (_a = store.config.logger) == null ? void 0 : _a.info(` \u23EE undo transaction "${update.key}" (undo)`);
733
- for (const { key, oldValue, newValue } of update.atomUpdates) {
789
+ for (const { key, oldValue } of update.atomUpdates) {
734
790
  const token = { key, type: `atom` };
735
791
  const state = withdraw(token, store);
736
792
  setState(state, oldValue, store);
@@ -739,7 +795,7 @@ var undoTransactionUpdate = (update, store) => {
739
795
  var redoTransactionUpdate = (update, store) => {
740
796
  var _a;
741
797
  (_a = store.config.logger) == null ? void 0 : _a.info(` \u23ED redo transaction "${update.key}" (redo)`);
742
- for (const { key, oldValue, newValue } of update.atomUpdates) {
798
+ for (const { key, newValue } of update.atomUpdates) {
743
799
  const token = { key, type: `atom` };
744
800
  const state = withdraw(token, store);
745
801
  setState(state, newValue, store);
@@ -779,7 +835,7 @@ function transaction__INTERNAL(options, store = IMPLICIT.STORE) {
779
835
  throw thrown;
780
836
  }
781
837
  },
782
- subject: new Rx.Subject()
838
+ subject: new Rx2.Subject()
783
839
  };
784
840
  const core = target(store);
785
841
  core.transactions = HAMT4.set(
@@ -788,6 +844,7 @@ function transaction__INTERNAL(options, store = IMPLICIT.STORE) {
788
844
  core.transactions
789
845
  );
790
846
  const token = deposit(newTransaction);
847
+ store.subject.transactionCreation.next(token);
791
848
  return token;
792
849
  }
793
850
  var target = (store = IMPLICIT.STORE) => store.transactionStatus.phase === `building` ? store.transactionStatus.core : store;
@@ -803,24 +860,28 @@ function atom__INTERNAL(options, family, store = IMPLICIT.STORE) {
803
860
  );
804
861
  return deposit(core.atoms.get(options.key));
805
862
  }
806
- const subject = new Rx2.Subject();
863
+ const subject = new Rx3.Subject();
807
864
  const newAtom = __spreadValues(__spreadProps(__spreadValues({}, options), {
808
865
  subject,
809
866
  type: `atom`
810
867
  }), family && { family });
811
868
  const initialValue = options.default instanceof Function ? options.default() : options.default;
812
- storeAtom(newAtom, store);
869
+ core.atoms = HAMT5.set(newAtom.key, newAtom, core.atoms);
813
870
  markAtomAsDefault(options.key, store);
814
871
  cacheValue(options.key, initialValue, store);
815
872
  const token = deposit(newAtom);
816
- const setSelf = (next) => setState(token, next, store);
817
- const onSet = (handle) => subscribe(token, handle, store);
818
- (_c = options.effects) == null ? void 0 : _c.forEach((effect) => effect({ setSelf, onSet }));
873
+ (_c = options.effects) == null ? void 0 : _c.forEach(
874
+ (effect) => effect({
875
+ setSelf: (next) => setState(token, next, store),
876
+ onSet: (handle) => subscribe(token, handle, store)
877
+ })
878
+ );
879
+ store.subject.atomCreation.next(token);
819
880
  return token;
820
881
  }
821
882
 
822
883
  // src/internal/families-internal.ts
823
- import * as Rx3 from "rxjs";
884
+ import * as Rx4 from "rxjs";
824
885
 
825
886
  // ../anvl/src/json/index.ts
826
887
  import { pipe as pipe6 } from "fp-ts/function";
@@ -828,13 +889,13 @@ var stringifyJson = (json) => JSON.stringify(json);
828
889
 
829
890
  // src/internal/families-internal.ts
830
891
  function atomFamily__INTERNAL(options, store = IMPLICIT.STORE) {
831
- const subject = new Rx3.Subject();
892
+ const subject = new Rx4.Subject();
832
893
  return Object.assign(
833
894
  (key) => {
834
895
  var _a;
835
896
  const subKey = stringifyJson(key);
836
897
  const family = { key: options.key, subKey };
837
- const fullKey = `${options.key}__${subKey}`;
898
+ const fullKey = `${options.key}(${subKey})`;
838
899
  const existing = withdraw({ key: fullKey, type: `atom` }, store);
839
900
  const token = existing ? deposit(existing) : atom__INTERNAL(
840
901
  {
@@ -857,12 +918,12 @@ function atomFamily__INTERNAL(options, store = IMPLICIT.STORE) {
857
918
  }
858
919
  function readonlySelectorFamily__INTERNAL(options, store) {
859
920
  const core = target(store);
860
- const subject = new Rx3.Subject();
921
+ const subject = new Rx4.Subject();
861
922
  return Object.assign(
862
923
  (key) => {
863
924
  const subKey = stringifyJson(key);
864
925
  const family = { key: options.key, subKey };
865
- const fullKey = `${options.key}__${subKey}`;
926
+ const fullKey = `${options.key}(${subKey})`;
866
927
  const existing = core.readonlySelectors.get(fullKey);
867
928
  if (existing) {
868
929
  return deposit(existing);
@@ -889,12 +950,12 @@ function selectorFamily__INTERNAL(options, store = IMPLICIT.STORE) {
889
950
  return readonlySelectorFamily__INTERNAL(options, store);
890
951
  }
891
952
  const core = target(store);
892
- const subject = new Rx3.Subject();
953
+ const subject = new Rx4.Subject();
893
954
  return Object.assign(
894
955
  (key) => {
895
956
  const subKey = stringifyJson(key);
896
957
  const family = { key: options.key, subKey };
897
- const fullKey = `${options.key}__${subKey}`;
958
+ const fullKey = `${options.key}(${subKey})`;
898
959
  const existing = core.selectors.get(fullKey);
899
960
  if (existing) {
900
961
  return deposit(existing);
@@ -918,42 +979,123 @@ function selectorFamily__INTERNAL(options, store = IMPLICIT.STORE) {
918
979
  );
919
980
  }
920
981
 
921
- // src/internal/logger.ts
922
- var LOG_LEVELS = [
923
- `info`,
924
- `warn`,
925
- `error`
926
- ];
927
- var setLogLevel = (preferredLevel, store = IMPLICIT.STORE) => {
928
- const { logger__INTERNAL } = store.config;
929
- if (preferredLevel === null) {
930
- store.config.logger = null;
931
- } else {
932
- store.config.logger = __spreadValues({}, console);
933
- LOG_LEVELS.forEach((logLevel) => {
934
- if (LOG_LEVELS.indexOf(logLevel) < LOG_LEVELS.indexOf(preferredLevel)) {
935
- store.config.logger[logLevel] = doNothing;
936
- } else {
937
- store.config.logger[logLevel] = logger__INTERNAL[logLevel];
982
+ // src/internal/meta/index.ts
983
+ var meta_exports = {};
984
+ __export(meta_exports, {
985
+ attachMetaAtoms: () => attachMetaAtoms,
986
+ attachMetaSelectors: () => attachMetaSelectors,
987
+ attachMetaState: () => attachMetaState
988
+ });
989
+
990
+ // src/internal/meta/meta-state.ts
991
+ var attachMetaAtoms = (store = IMPLICIT.STORE) => {
992
+ const atomTokenIndexState__INTERNAL = atom({
993
+ key: `\u{1F441}\u200D\u{1F5E8}_atom_token_index__INTERNAL`,
994
+ default: () => [...store.atoms].reduce((acc, [key]) => {
995
+ acc[key] = { key, type: `atom` };
996
+ return acc;
997
+ }, {}),
998
+ effects: [
999
+ ({ setSelf }) => {
1000
+ store.subject.atomCreation.subscribe((atomToken) => {
1001
+ if (store.operation.open) {
1002
+ return;
1003
+ }
1004
+ setSelf((state) => {
1005
+ const { key, family } = atomToken;
1006
+ if (family) {
1007
+ const { key: familyKey, subKey } = family;
1008
+ const current = state[familyKey];
1009
+ if (current === void 0 || `familyMembers` in current) {
1010
+ const familyKeyState = current || {
1011
+ key: familyKey,
1012
+ familyMembers: {}
1013
+ };
1014
+ return __spreadProps(__spreadValues({}, state), {
1015
+ [familyKey]: __spreadProps(__spreadValues({}, familyKeyState), {
1016
+ familyMembers: __spreadProps(__spreadValues({}, familyKeyState.familyMembers), {
1017
+ [subKey]: atomToken
1018
+ })
1019
+ })
1020
+ });
1021
+ }
1022
+ }
1023
+ return __spreadProps(__spreadValues({}, state), {
1024
+ [key]: atomToken
1025
+ });
1026
+ });
1027
+ });
938
1028
  }
939
- });
940
- }
1029
+ ]
1030
+ });
1031
+ return selector({
1032
+ key: `\u{1F441}\u200D\u{1F5E8}_atom_token_index`,
1033
+ get: ({ get }) => get(atomTokenIndexState__INTERNAL)
1034
+ });
941
1035
  };
942
- var useLogger = (logger, store = IMPLICIT.STORE) => {
943
- var _a;
944
- const currentLogLevel = store.config.logger === null ? null : (_a = LOG_LEVELS.find(
945
- (logLevel) => {
946
- var _a2;
947
- return ((_a2 = store.config.logger) == null ? void 0 : _a2[logLevel]) !== doNothing;
948
- }
949
- )) != null ? _a : null;
950
- store.config.logger__INTERNAL = __spreadValues({}, logger);
951
- setLogLevel(currentLogLevel, store);
1036
+ var attachMetaSelectors = (store = IMPLICIT.STORE) => {
1037
+ const readonlySelectorTokenIndexState__INTERNAL = atom({
1038
+ key: `\u{1F441}\u200D\u{1F5E8}_selector_token_index__INTERNAL`,
1039
+ default: () => Object.assign(
1040
+ [...store.readonlySelectors].reduce((acc, [key]) => {
1041
+ acc[key] = { key, type: `readonly_selector` };
1042
+ return acc;
1043
+ }, {}),
1044
+ [...store.selectors].reduce((acc, [key]) => {
1045
+ acc[key] = { key, type: `selector` };
1046
+ return acc;
1047
+ }, {})
1048
+ ),
1049
+ effects: [
1050
+ ({ setSelf }) => {
1051
+ store.subject.selectorCreation.subscribe((selectorToken) => {
1052
+ if (store.operation.open) {
1053
+ return;
1054
+ }
1055
+ setSelf((state) => {
1056
+ const { key, family } = selectorToken;
1057
+ if (family) {
1058
+ const { key: familyKey, subKey } = family;
1059
+ const current = state[familyKey];
1060
+ if (current === void 0 || `familyMembers` in current) {
1061
+ const familyKeyState = current || {
1062
+ key: familyKey,
1063
+ familyMembers: {}
1064
+ };
1065
+ return __spreadProps(__spreadValues({}, state), {
1066
+ [familyKey]: __spreadProps(__spreadValues({}, familyKeyState), {
1067
+ familyMembers: __spreadProps(__spreadValues({}, familyKeyState.familyMembers), {
1068
+ [subKey]: selectorToken
1069
+ })
1070
+ })
1071
+ });
1072
+ }
1073
+ }
1074
+ return __spreadProps(__spreadValues({}, state), {
1075
+ [key]: selectorToken
1076
+ });
1077
+ });
1078
+ });
1079
+ }
1080
+ ]
1081
+ });
1082
+ return selector({
1083
+ key: `\u{1F441}\u200D\u{1F5E8}_selector_token_index`,
1084
+ get: ({ get }) => get(readonlySelectorTokenIndexState__INTERNAL)
1085
+ });
1086
+ };
1087
+
1088
+ // src/internal/meta/attach-meta.ts
1089
+ var attachMetaState = (store = IMPLICIT.STORE) => {
1090
+ return {
1091
+ atomTokenIndexState: attachMetaAtoms(store),
1092
+ selectorTokenIndexState: attachMetaSelectors(store)
1093
+ };
952
1094
  };
953
1095
 
954
1096
  // src/internal/selector-internal.ts
955
- import HAMT5 from "hamt_plus";
956
- import * as Rx4 from "rxjs";
1097
+ import HAMT6 from "hamt_plus";
1098
+ import * as Rx5 from "rxjs";
957
1099
  var lookupSelectorSources = (key, store) => target(store).selectorGraph.getRelations(key).filter(({ source }) => source !== key).map(({ source }) => lookup(source, store));
958
1100
  var traceSelectorAtoms = (selectorKey, dependency, store) => {
959
1101
  const roots = [];
@@ -985,7 +1127,10 @@ var updateSelectorAtoms = (selectorKey, dependency, store) => {
985
1127
  var _a, _b;
986
1128
  const core = target(store);
987
1129
  if (dependency.type === `atom`) {
988
- core.selectorAtoms = core.selectorAtoms.set(selectorKey, dependency.key);
1130
+ core.selectorAtoms = core.selectorAtoms.set({
1131
+ selectorKey,
1132
+ atomKey: dependency.key
1133
+ });
989
1134
  (_a = store.config.logger) == null ? void 0 : _a.info(
990
1135
  ` || adding root for "${selectorKey}": ${dependency.key}`
991
1136
  );
@@ -997,7 +1142,10 @@ var updateSelectorAtoms = (selectorKey, dependency, store) => {
997
1142
  roots.map((r) => r.key)
998
1143
  );
999
1144
  for (const root of roots) {
1000
- core.selectorAtoms = core.selectorAtoms.set(selectorKey, root.key);
1145
+ core.selectorAtoms = core.selectorAtoms.set({
1146
+ selectorKey,
1147
+ atomKey: root.key
1148
+ });
1001
1149
  }
1002
1150
  };
1003
1151
  var registerSelector = (selectorKey, store = IMPLICIT.STORE) => ({
@@ -1014,12 +1162,16 @@ var registerSelector = (selectorKey, store = IMPLICIT.STORE) => ({
1014
1162
  );
1015
1163
  } else {
1016
1164
  (_b = store.config.logger) == null ? void 0 : _b.info(
1017
- `\u{1F50C} registerSelector "${selectorKey}" <- "${dependency.key}" =`,
1018
- dependencyValue
1165
+ `\u{1F50C} registerSelector "${selectorKey}" <- ( "${dependency.key}" =`,
1166
+ dependencyValue,
1167
+ `)`
1168
+ );
1169
+ core.selectorGraph = core.selectorGraph.set(
1170
+ { from: dependency.key, to: selectorKey },
1171
+ {
1172
+ source: dependency.key
1173
+ }
1019
1174
  );
1020
- core.selectorGraph = core.selectorGraph.set(selectorKey, dependency.key, {
1021
- source: dependency.key
1022
- });
1023
1175
  }
1024
1176
  updateSelectorAtoms(selectorKey, dependency, store);
1025
1177
  return dependencyValue;
@@ -1032,12 +1184,12 @@ var registerSelector = (selectorKey, store = IMPLICIT.STORE) => ({
1032
1184
  function selector__INTERNAL(options, family, store = IMPLICIT.STORE) {
1033
1185
  var _a, _b, _c;
1034
1186
  const core = target(store);
1035
- if (HAMT5.has(options.key, core.selectors)) {
1187
+ if (HAMT6.has(options.key, core.selectors)) {
1036
1188
  (_a = store.config.logger) == null ? void 0 : _a.error(
1037
1189
  `Key "${options.key}" already exists in the store.`
1038
1190
  );
1039
1191
  }
1040
- const subject = new Rx4.Subject();
1192
+ const subject = new Rx5.Subject();
1041
1193
  const { get, set } = registerSelector(options.key, store);
1042
1194
  const getSelf = () => {
1043
1195
  const value = options.get({ get });
@@ -1050,14 +1202,20 @@ function selector__INTERNAL(options, family, store = IMPLICIT.STORE) {
1050
1202
  get: getSelf,
1051
1203
  type: `readonly_selector`
1052
1204
  }), family && { family });
1053
- core.readonlySelectors = HAMT5.set(
1205
+ core.readonlySelectors = HAMT6.set(
1054
1206
  options.key,
1055
1207
  readonlySelector,
1056
1208
  core.readonlySelectors
1057
1209
  );
1058
1210
  const initialValue2 = getSelf();
1059
1211
  (_b = store.config.logger) == null ? void 0 : _b.info(` \u2728 "${options.key}" =`, initialValue2);
1060
- return __spreadProps(__spreadValues({}, readonlySelector), { type: `readonly_selector` });
1212
+ const token2 = {
1213
+ key: options.key,
1214
+ type: `readonly_selector`,
1215
+ family
1216
+ };
1217
+ store.subject.selectorCreation.next(token2);
1218
+ return token2;
1061
1219
  }
1062
1220
  const setSelf = (next) => {
1063
1221
  var _a2;
@@ -1077,14 +1235,20 @@ function selector__INTERNAL(options, family, store = IMPLICIT.STORE) {
1077
1235
  set: setSelf,
1078
1236
  type: `selector`
1079
1237
  }), family && { family });
1080
- core.selectors = HAMT5.set(options.key, mySelector, core.selectors);
1238
+ core.selectors = HAMT6.set(options.key, mySelector, core.selectors);
1081
1239
  const initialValue = getSelf();
1082
1240
  (_c = store.config.logger) == null ? void 0 : _c.info(` \u2728 "${options.key}" =`, initialValue);
1083
- return __spreadProps(__spreadValues({}, mySelector), { type: `selector` });
1241
+ const token = {
1242
+ key: options.key,
1243
+ type: `selector`,
1244
+ family
1245
+ };
1246
+ store.subject.selectorCreation.next(token);
1247
+ return token;
1084
1248
  }
1085
1249
 
1086
1250
  // src/internal/set.ts
1087
- import HAMT6 from "hamt_plus";
1251
+ import HAMT7 from "hamt_plus";
1088
1252
  var evictDownStream = (state, store = IMPLICIT.STORE) => {
1089
1253
  var _a, _b;
1090
1254
  const core = target(store);
@@ -1103,7 +1267,7 @@ var evictDownStream = (state, store = IMPLICIT.STORE) => {
1103
1267
  (_a2 = store.config.logger) == null ? void 0 : _a2.info(` || ${stateKey} already done`);
1104
1268
  return;
1105
1269
  }
1106
- const state2 = (_b2 = HAMT6.get(stateKey, core.selectors)) != null ? _b2 : HAMT6.get(stateKey, core.readonlySelectors);
1270
+ const state2 = (_b2 = HAMT7.get(stateKey, core.selectors)) != null ? _b2 : HAMT7.get(stateKey, core.readonlySelectors);
1107
1271
  if (!state2) {
1108
1272
  (_c = store.config.logger) == null ? void 0 : _c.info(
1109
1273
  ` || ${stateKey} is an atom, and can't be downstream`
@@ -1204,112 +1368,32 @@ var subscribeToRootAtoms = (state, store) => {
1204
1368
  return dependencySubscriptions;
1205
1369
  };
1206
1370
 
1207
- // src/internal/timeline-internal.ts
1208
- import HAMT7 from "hamt_plus";
1209
- function timeline__INTERNAL(options, store = IMPLICIT.STORE) {
1210
- let incompleteTransactionKey = null;
1211
- const timelineData = {
1212
- at: 0,
1213
- timeTraveling: false,
1214
- history: []
1215
- };
1216
- const subscribeToAtom = (token) => {
1217
- const state = withdraw(token, store);
1218
- state.subject.subscribe((update) => {
1219
- var _a, _b, _c;
1220
- const storeCurrentTransactionKey = store.transactionStatus.phase === `applying` ? store.transactionStatus.key : null;
1221
- (_a = store.config.logger) == null ? void 0 : _a.info(
1222
- `\u23F3 timeline "${options.key}" saw atom "${token.key}" go (`,
1223
- update.oldValue,
1224
- `->`,
1225
- update.newValue,
1226
- storeCurrentTransactionKey ? `) in "${storeCurrentTransactionKey}"` : `) independently`
1227
- );
1228
- if (storeCurrentTransactionKey && store.transactionStatus.phase === `applying`) {
1229
- const currentTransaction = withdraw(
1230
- { key: storeCurrentTransactionKey, type: `transaction` },
1231
- store
1232
- );
1233
- if (incompleteTransactionKey !== storeCurrentTransactionKey) {
1234
- if (incompleteTransactionKey) {
1235
- (_b = store.config.logger) == null ? void 0 : _b.error(
1236
- `Timeline "${options.key}" was unable to resolve transaction "${incompleteTransactionKey}. This is probably a bug.`
1237
- );
1238
- }
1239
- incompleteTransactionKey = storeCurrentTransactionKey;
1240
- const subscription = currentTransaction.subject.subscribe((update2) => {
1241
- var _a2;
1242
- if (timelineData.timeTraveling === false) {
1243
- timelineData.history.push(__spreadProps(__spreadValues({
1244
- type: `transaction_update`
1245
- }, update2), {
1246
- atomUpdates: update2.atomUpdates.filter(
1247
- (atomUpdate) => options.atoms.some((atom2) => atom2.key === atomUpdate.key)
1248
- )
1249
- }));
1250
- }
1251
- timelineData.at = timelineData.history.length;
1252
- subscription.unsubscribe();
1253
- incompleteTransactionKey = null;
1254
- (_a2 = store.config.logger) == null ? void 0 : _a2.info(
1255
- `\u231B timeline "${options.key}" pushed a transaction_update from "${update2.key}"`
1256
- );
1257
- });
1258
- }
1259
- } else {
1260
- if (timelineData.timeTraveling === false) {
1261
- timelineData.history.push({
1262
- type: `state_update`,
1263
- key: token.key,
1264
- oldValue: update.oldValue,
1265
- newValue: update.newValue
1266
- });
1267
- (_c = store.config.logger) == null ? void 0 : _c.info(
1268
- `\u231B timeline "${options.key}" pushed a state_update to "${token.key}"`
1269
- );
1270
- timelineData.at = timelineData.history.length;
1271
- }
1272
- }
1273
- });
1274
- };
1275
- for (const tokenOrFamily of options.atoms) {
1276
- if (tokenOrFamily.type === `atom_family`) {
1277
- const family = tokenOrFamily;
1278
- family.subject.subscribe((token) => subscribeToAtom(token));
1279
- } else {
1280
- const token = tokenOrFamily;
1281
- subscribeToAtom(token);
1282
- }
1283
- }
1284
- store.timelineStore = HAMT7.set(options.key, timelineData, store.timelineStore);
1285
- return {
1286
- key: options.key,
1287
- type: `timeline`
1288
- };
1289
- }
1371
+ // src/internal/time-travel-internal.ts
1290
1372
  var redo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1291
- var _a, _b;
1373
+ var _a, _b, _c, _d;
1374
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u23E9 redo "${token.key}"`);
1292
1375
  const timelineData = store.timelineStore.get(token.key);
1293
1376
  if (!timelineData) {
1294
- (_a = store.config.logger) == null ? void 0 : _a.error(
1295
- `Tried to redo on timeline "${token.key}" has not been initialized.`
1377
+ (_b = store.config.logger) == null ? void 0 : _b.error(
1378
+ `Failed to redo on timeline "${token.key}". This timeline has not been initialized.`
1296
1379
  );
1297
1380
  return;
1298
1381
  }
1299
1382
  if (timelineData.at === timelineData.history.length) {
1300
- (_b = store.config.logger) == null ? void 0 : _b.warn(
1301
- `Tried to redo on timeline "${token.key}" but there is nothing to redo.`
1383
+ (_c = store.config.logger) == null ? void 0 : _c.warn(
1384
+ `Failed to redo at the end of timeline "${token.key}". There is nothing to redo.`
1302
1385
  );
1303
1386
  return;
1304
1387
  }
1305
1388
  timelineData.timeTraveling = true;
1306
1389
  const update = timelineData.history[timelineData.at];
1307
1390
  switch (update.type) {
1308
- case `state_update`: {
1391
+ case `atom_update`: {
1309
1392
  const { key, newValue } = update;
1310
1393
  setState({ key, type: `atom` }, newValue);
1311
1394
  break;
1312
1395
  }
1396
+ case `selector_update`:
1313
1397
  case `transaction_update`: {
1314
1398
  for (const atomUpdate of update.atomUpdates) {
1315
1399
  const { key, newValue } = atomUpdate;
@@ -1320,19 +1404,23 @@ var redo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1320
1404
  }
1321
1405
  ++timelineData.at;
1322
1406
  timelineData.timeTraveling = false;
1407
+ (_d = store.config.logger) == null ? void 0 : _d.info(
1408
+ `\u23F9\uFE0F "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
1409
+ );
1323
1410
  };
1324
1411
  var undo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1325
- var _a, _b;
1412
+ var _a, _b, _c, _d;
1413
+ (_a = store.config.logger) == null ? void 0 : _a.info(`\u23EA undo "${token.key}"`);
1326
1414
  const timelineData = store.timelineStore.get(token.key);
1327
1415
  if (!timelineData) {
1328
- (_a = store.config.logger) == null ? void 0 : _a.error(
1329
- `Tried to undo on timeline "${token.key}" has not been initialized.`
1416
+ (_b = store.config.logger) == null ? void 0 : _b.error(
1417
+ `Failed to undo on timeline "${token.key}". This timeline has not been initialized.`
1330
1418
  );
1331
1419
  return;
1332
1420
  }
1333
1421
  if (timelineData.at === 0) {
1334
- (_b = store.config.logger) == null ? void 0 : _b.warn(
1335
- `Tried to undo on timeline "${token.key}" but there is nothing to undo.`
1422
+ (_c = store.config.logger) == null ? void 0 : _c.warn(
1423
+ `Failed to undo at the beginning of timeline "${token.key}". There is nothing to undo.`
1336
1424
  );
1337
1425
  return;
1338
1426
  }
@@ -1340,11 +1428,12 @@ var undo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1340
1428
  --timelineData.at;
1341
1429
  const update = timelineData.history[timelineData.at];
1342
1430
  switch (update.type) {
1343
- case `state_update`: {
1431
+ case `atom_update`: {
1344
1432
  const { key, oldValue } = update;
1345
1433
  setState({ key, type: `atom` }, oldValue);
1346
1434
  break;
1347
1435
  }
1436
+ case `selector_update`:
1348
1437
  case `transaction_update`: {
1349
1438
  for (const atomUpdate of update.atomUpdates) {
1350
1439
  const { key, oldValue } = atomUpdate;
@@ -1354,8 +1443,167 @@ var undo__INTERNAL = (token, store = IMPLICIT.STORE) => {
1354
1443
  }
1355
1444
  }
1356
1445
  timelineData.timeTraveling = false;
1446
+ (_d = store.config.logger) == null ? void 0 : _d.info(
1447
+ `\u23F9\uFE0F "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
1448
+ );
1357
1449
  };
1358
1450
 
1451
+ // src/internal/timeline-internal.ts
1452
+ import HAMT8 from "hamt_plus";
1453
+ function timeline__INTERNAL(options, store = IMPLICIT.STORE) {
1454
+ var _a, _b;
1455
+ const timelineData = {
1456
+ at: 0,
1457
+ timeTraveling: false,
1458
+ history: [],
1459
+ selectorTime: null,
1460
+ transactionKey: null
1461
+ };
1462
+ const subscribeToAtom = (token2) => {
1463
+ const state = withdraw(token2, store);
1464
+ state.subject.subscribe((update) => {
1465
+ var _a2, _b2, _c, _d, _e;
1466
+ const storeCurrentSelectorKey = store.operation.open && store.operation.token.type === `selector` ? store.operation.token.key : null;
1467
+ const storeCurrentSelectorTime = store.operation.open && store.operation.token.type === `selector` ? store.operation.time : null;
1468
+ const storeCurrentTransactionKey = store.transactionStatus.phase === `applying` ? store.transactionStatus.key : null;
1469
+ (_a2 = store.config.logger) == null ? void 0 : _a2.info(
1470
+ `\u23F3 timeline "${options.key}" saw atom "${token2.key}" go (`,
1471
+ update.oldValue,
1472
+ `->`,
1473
+ update.newValue,
1474
+ storeCurrentTransactionKey ? `) in transaction "${storeCurrentTransactionKey}"` : storeCurrentSelectorKey ? `) in selector "${storeCurrentSelectorKey}"` : `)`
1475
+ );
1476
+ if (storeCurrentTransactionKey && store.transactionStatus.phase === `applying`) {
1477
+ const currentTransaction = withdraw(
1478
+ { key: storeCurrentTransactionKey, type: `transaction` },
1479
+ store
1480
+ );
1481
+ if (timelineData.transactionKey !== storeCurrentTransactionKey) {
1482
+ if (timelineData.transactionKey) {
1483
+ (_b2 = store.config.logger) == null ? void 0 : _b2.error(
1484
+ `Timeline "${options.key}" was unable to resolve transaction "${timelineData.transactionKey}. This is probably a bug.`
1485
+ );
1486
+ }
1487
+ timelineData.transactionKey = storeCurrentTransactionKey;
1488
+ const subscription = currentTransaction.subject.subscribe((update2) => {
1489
+ var _a3;
1490
+ if (timelineData.timeTraveling === false) {
1491
+ if (timelineData.at !== timelineData.history.length) {
1492
+ timelineData.history.splice(timelineData.at);
1493
+ }
1494
+ timelineData.history.push(__spreadProps(__spreadValues({
1495
+ type: `transaction_update`
1496
+ }, update2), {
1497
+ atomUpdates: update2.atomUpdates.filter(
1498
+ (atomUpdate) => options.atoms.some((atom2) => atom2.key === atomUpdate.key)
1499
+ )
1500
+ }));
1501
+ }
1502
+ timelineData.at = timelineData.history.length;
1503
+ subscription.unsubscribe();
1504
+ timelineData.transactionKey = null;
1505
+ (_a3 = store.config.logger) == null ? void 0 : _a3.info(
1506
+ `\u231B timeline "${options.key}" got a transaction_update "${update2.key}"`
1507
+ );
1508
+ });
1509
+ }
1510
+ } else if (storeCurrentSelectorKey) {
1511
+ if (timelineData.timeTraveling === false) {
1512
+ if (storeCurrentSelectorTime !== timelineData.selectorTime) {
1513
+ const newSelectorUpdate = {
1514
+ type: `selector_update`,
1515
+ key: storeCurrentSelectorKey,
1516
+ atomUpdates: []
1517
+ };
1518
+ newSelectorUpdate.atomUpdates.push(__spreadValues({
1519
+ key: token2.key,
1520
+ type: `atom_update`
1521
+ }, update));
1522
+ if (timelineData.at !== timelineData.history.length) {
1523
+ timelineData.history.splice(timelineData.at);
1524
+ }
1525
+ timelineData.history.push(newSelectorUpdate);
1526
+ (_c = store.config.logger) == null ? void 0 : _c.info(
1527
+ `\u231B timeline "${options.key}" got a selector_update "${storeCurrentSelectorKey}" with`,
1528
+ newSelectorUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
1529
+ );
1530
+ timelineData.at = timelineData.history.length;
1531
+ timelineData.selectorTime = storeCurrentSelectorTime;
1532
+ } else {
1533
+ const latestUpdate = timelineData.history.at(-1);
1534
+ if ((latestUpdate == null ? void 0 : latestUpdate.type) === `selector_update`) {
1535
+ latestUpdate.atomUpdates.push(__spreadValues({
1536
+ key: token2.key,
1537
+ type: `atom_update`
1538
+ }, update));
1539
+ (_d = store.config.logger) == null ? void 0 : _d.info(
1540
+ ` \u231B timeline "${options.key}" set selector_update "${storeCurrentSelectorKey}" to`,
1541
+ latestUpdate == null ? void 0 : latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
1542
+ );
1543
+ }
1544
+ }
1545
+ }
1546
+ } else {
1547
+ if (timelineData.timeTraveling === false) {
1548
+ timelineData.selectorTime = null;
1549
+ if (timelineData.at !== timelineData.history.length) {
1550
+ timelineData.history.splice(timelineData.at);
1551
+ }
1552
+ timelineData.history.push({
1553
+ type: `atom_update`,
1554
+ key: token2.key,
1555
+ oldValue: update.oldValue,
1556
+ newValue: update.newValue
1557
+ });
1558
+ (_e = store.config.logger) == null ? void 0 : _e.info(
1559
+ `\u231B timeline "${options.key}" got a state_update to "${token2.key}"`
1560
+ );
1561
+ timelineData.at = timelineData.history.length;
1562
+ }
1563
+ }
1564
+ });
1565
+ };
1566
+ const core = target(store);
1567
+ for (const tokenOrFamily of options.atoms) {
1568
+ const timelineKey = core.timelineAtoms.getRelatedId(tokenOrFamily.key);
1569
+ if (timelineKey) {
1570
+ (_a = store.config.logger) == null ? void 0 : _a.error(
1571
+ `\u274C Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`
1572
+ );
1573
+ continue;
1574
+ }
1575
+ if (tokenOrFamily.type === `atom_family`) {
1576
+ const family = tokenOrFamily;
1577
+ family.subject.subscribe((token2) => subscribeToAtom(token2));
1578
+ } else {
1579
+ const token2 = tokenOrFamily;
1580
+ if (`family` in token2 && token2.family) {
1581
+ const familyTimelineKey = core.timelineAtoms.getRelatedId(
1582
+ token2.family.key
1583
+ );
1584
+ if (familyTimelineKey) {
1585
+ (_b = store.config.logger) == null ? void 0 : _b.error(
1586
+ `\u274C Failed to add atom "${token2.key}" to timeline "${options.key}" because its family "${token2.family.key}" belongs to timeline "${familyTimelineKey}"`
1587
+ );
1588
+ continue;
1589
+ }
1590
+ }
1591
+ subscribeToAtom(token2);
1592
+ }
1593
+ core.timelineAtoms = core.timelineAtoms.set({
1594
+ atomKey: tokenOrFamily.key,
1595
+ timelineKey: options.key
1596
+ });
1597
+ }
1598
+ store.timelineStore = HAMT8.set(options.key, timelineData, store.timelineStore);
1599
+ const token = {
1600
+ key: options.key,
1601
+ type: `timeline`
1602
+ };
1603
+ store.subject.timelineCreation.next(token);
1604
+ return token;
1605
+ }
1606
+
1359
1607
  // src/atom.ts
1360
1608
  function atom(options) {
1361
1609
  return atom__INTERNAL(options);
@@ -1364,6 +1612,39 @@ function atomFamily(options) {
1364
1612
  return atomFamily__INTERNAL(options);
1365
1613
  }
1366
1614
 
1615
+ // src/logger.ts
1616
+ var LOG_LEVELS = [
1617
+ `info`,
1618
+ `warn`,
1619
+ `error`
1620
+ ];
1621
+ var setLogLevel = (preferredLevel, store = IMPLICIT.STORE) => {
1622
+ const { logger__INTERNAL } = store.config;
1623
+ if (preferredLevel === null) {
1624
+ store.config.logger = null;
1625
+ } else {
1626
+ store.config.logger = __spreadValues({}, console);
1627
+ LOG_LEVELS.forEach((logLevel) => {
1628
+ if (LOG_LEVELS.indexOf(logLevel) < LOG_LEVELS.indexOf(preferredLevel)) {
1629
+ store.config.logger[logLevel] = doNothing;
1630
+ } else {
1631
+ store.config.logger[logLevel] = logger__INTERNAL[logLevel];
1632
+ }
1633
+ });
1634
+ }
1635
+ };
1636
+ var useLogger = (logger, store = IMPLICIT.STORE) => {
1637
+ var _a;
1638
+ const currentLogLevel = store.config.logger === null ? null : (_a = LOG_LEVELS.find(
1639
+ (logLevel) => {
1640
+ var _a2;
1641
+ return ((_a2 = store.config.logger) == null ? void 0 : _a2[logLevel]) !== doNothing;
1642
+ }
1643
+ )) != null ? _a : null;
1644
+ store.config.logger__INTERNAL = __spreadValues({}, logger);
1645
+ setLogLevel(currentLogLevel, store);
1646
+ };
1647
+
1367
1648
  // src/selector.ts
1368
1649
  function selector(options) {
1369
1650
  return selector__INTERNAL(options);
@@ -1372,30 +1653,13 @@ function selectorFamily(options) {
1372
1653
  return selectorFamily__INTERNAL(options);
1373
1654
  }
1374
1655
 
1375
- // src/timeline.ts
1376
- var timeline = (options) => {
1377
- return timeline__INTERNAL(options);
1378
- };
1379
- var redo = (token) => {
1380
- return redo__INTERNAL(token, IMPLICIT.STORE);
1381
- };
1382
- var undo = (token) => {
1383
- return undo__INTERNAL(token, IMPLICIT.STORE);
1384
- };
1385
-
1386
- // src/transaction.ts
1387
- function transaction(options) {
1388
- return transaction__INTERNAL(options);
1389
- }
1390
- var runTransaction = (token, store = IMPLICIT.STORE) => (...parameters) => withdraw(token, store).run(...parameters);
1391
-
1392
1656
  // src/subscribe.ts
1393
1657
  var subscribe = (token, handleUpdate, store = IMPLICIT.STORE) => {
1394
1658
  var _a;
1395
1659
  const state = withdraw(token, store);
1396
1660
  const subscription = state.subject.subscribe(handleUpdate);
1397
1661
  (_a = store.config.logger) == null ? void 0 : _a.info(`\u{1F440} subscribe to "${state.key}"`);
1398
- const dependencySubscriptions = `get` in state ? subscribeToRootAtoms(state, store) : null;
1662
+ const dependencySubscriptions = state.type !== `atom` ? subscribeToRootAtoms(state, store) : null;
1399
1663
  const unsubscribe = dependencySubscriptions === null ? () => {
1400
1664
  var _a2;
1401
1665
  (_a2 = store.config.logger) == null ? void 0 : _a2.info(`\u{1F648} unsubscribe from "${state.key}"`);
@@ -1425,19 +1689,44 @@ var subscribeToTransaction = (token, handleUpdate, store = IMPLICIT.STORE) => {
1425
1689
  return unsubscribe;
1426
1690
  };
1427
1691
 
1692
+ // src/timeline.ts
1693
+ var timeline = (options) => {
1694
+ return timeline__INTERNAL(options);
1695
+ };
1696
+ var redo = (token) => {
1697
+ return redo__INTERNAL(token, IMPLICIT.STORE);
1698
+ };
1699
+ var undo = (token) => {
1700
+ return undo__INTERNAL(token, IMPLICIT.STORE);
1701
+ };
1702
+
1703
+ // src/transaction.ts
1704
+ function transaction(options) {
1705
+ return transaction__INTERNAL(options);
1706
+ }
1707
+ var runTransaction = (token, store = IMPLICIT.STORE) => (...parameters) => withdraw(token, store).run(...parameters);
1708
+
1428
1709
  // src/index.ts
1429
1710
  var getState = (token, store = IMPLICIT.STORE) => {
1430
1711
  const state = withdraw(token, store);
1431
1712
  return getState__INTERNAL(state, store);
1432
1713
  };
1433
1714
  var setState = (token, value, store = IMPLICIT.STORE) => {
1434
- openOperation(store);
1715
+ try {
1716
+ openOperation(token, store);
1717
+ } catch (thrown) {
1718
+ if (!(typeof thrown === `symbol`)) {
1719
+ throw thrown;
1720
+ }
1721
+ return;
1722
+ }
1435
1723
  const state = withdraw(token, store);
1436
1724
  setState__INTERNAL(state, value, store);
1437
1725
  closeOperation(store);
1438
1726
  };
1439
1727
  var isDefault = (token, store = IMPLICIT.STORE) => token.type === `atom` ? isAtomDefault(token.key, store) : isSelectorDefault(token.key, store);
1440
1728
  export {
1729
+ LOG_LEVELS,
1441
1730
  internal_exports as __INTERNAL__,
1442
1731
  atom,
1443
1732
  atomFamily,