atom.io 0.12.1 → 0.13.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 (81) hide show
  1. package/dist/index.cjs.map +1 -1
  2. package/dist/index.d.cts +6 -3
  3. package/dist/index.d.ts +6 -3
  4. package/dist/index.js.map +1 -1
  5. package/dist/metafile-cjs.json +1 -1
  6. package/dist/metafile-esm.json +1 -1
  7. package/internal/dist/index.cjs +1561 -1512
  8. package/internal/dist/index.cjs.map +1 -1
  9. package/internal/dist/index.d.cts +24 -14
  10. package/internal/dist/index.d.ts +24 -14
  11. package/internal/dist/index.js +1560 -1513
  12. package/internal/dist/index.js.map +1 -1
  13. package/internal/dist/metafile-cjs.json +1 -1
  14. package/internal/dist/metafile-esm.json +1 -1
  15. package/internal/src/atom/create-atom.ts +4 -4
  16. package/internal/src/atom/delete-atom.ts +11 -11
  17. package/internal/src/atom/is-default.ts +5 -5
  18. package/internal/src/caching.ts +12 -10
  19. package/internal/src/families/create-atom-family.ts +3 -3
  20. package/internal/src/families/create-readonly-selector-family.ts +3 -3
  21. package/internal/src/families/create-selector-family.ts +4 -4
  22. package/internal/src/index.ts +1 -0
  23. package/internal/src/keys.ts +4 -4
  24. package/internal/src/lazy-map.ts +6 -2
  25. package/internal/src/lineage.ts +18 -0
  26. package/internal/src/mutable/create-mutable-atom.ts +5 -4
  27. package/internal/src/mutable/get-json-family.ts +3 -3
  28. package/internal/src/mutable/tracker.ts +13 -10
  29. package/internal/src/operation.ts +19 -19
  30. package/internal/src/selector/create-read-write-selector.ts +5 -4
  31. package/internal/src/selector/create-readonly-selector.ts +4 -3
  32. package/internal/src/selector/create-selector.ts +6 -6
  33. package/internal/src/selector/delete-selector.ts +10 -10
  34. package/internal/src/selector/get-selector-dependency-keys.ts +2 -2
  35. package/internal/src/selector/register-selector.ts +4 -4
  36. package/internal/src/selector/update-selector-atoms.ts +2 -2
  37. package/internal/src/set-state/copy-mutable-if-needed.ts +4 -3
  38. package/internal/src/set-state/copy-mutable-in-transaction.ts +10 -16
  39. package/internal/src/set-state/copy-mutable-into-new-store.ts +1 -1
  40. package/internal/src/set-state/evict-downstream.ts +5 -5
  41. package/internal/src/set-state/set-atom.ts +6 -1
  42. package/internal/src/set-state/stow-update.ts +7 -2
  43. package/internal/src/store/store.ts +31 -24
  44. package/internal/src/store/withdraw-new-family-member.ts +3 -4
  45. package/internal/src/store/withdraw.ts +58 -59
  46. package/internal/src/subject.ts +14 -0
  47. package/internal/src/subscribe/recall-state.ts +5 -5
  48. package/internal/src/timeline/add-atom-to-timeline.ts +37 -27
  49. package/internal/src/timeline/create-timeline.ts +6 -8
  50. package/internal/src/timeline/time-travel.ts +22 -4
  51. package/internal/src/transaction/abort-transaction.ts +5 -3
  52. package/internal/src/transaction/apply-transaction.ts +80 -58
  53. package/internal/src/transaction/build-transaction.ts +33 -23
  54. package/internal/src/transaction/create-transaction.ts +6 -9
  55. package/internal/src/transaction/index.ts +2 -10
  56. package/internal/src/transaction/redo-transaction.ts +15 -10
  57. package/internal/src/transaction/undo-transaction.ts +15 -16
  58. package/introspection/dist/index.cjs +2 -2
  59. package/introspection/dist/index.cjs.map +1 -1
  60. package/introspection/dist/index.js +3 -3
  61. package/introspection/dist/index.js.map +1 -1
  62. package/introspection/src/attach-atom-index.ts +2 -2
  63. package/introspection/src/attach-selector-index.ts +2 -2
  64. package/package.json +3 -3
  65. package/react-devtools/dist/index.cjs +22 -8
  66. package/react-devtools/dist/index.cjs.map +1 -1
  67. package/react-devtools/dist/index.d.cts +17 -9
  68. package/react-devtools/dist/index.d.ts +17 -9
  69. package/react-devtools/dist/index.js +22 -8
  70. package/react-devtools/dist/index.js.map +1 -1
  71. package/react-devtools/dist/metafile-cjs.json +1 -1
  72. package/react-devtools/dist/metafile-esm.json +1 -1
  73. package/react-devtools/src/Updates.tsx +22 -10
  74. package/src/transaction.ts +7 -2
  75. package/transceivers/set-rtx/dist/index.cjs.map +1 -1
  76. package/transceivers/set-rtx/dist/index.d.cts +2 -2
  77. package/transceivers/set-rtx/dist/index.d.ts +2 -2
  78. package/transceivers/set-rtx/dist/index.js.map +1 -1
  79. package/transceivers/set-rtx/dist/metafile-cjs.json +1 -1
  80. package/transceivers/set-rtx/dist/metafile-esm.json +1 -1
  81. package/transceivers/set-rtx/src/set-rtx.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  import type { AtomFamily } from "atom.io"
2
2
  import type { Json, JsonInterface } from "atom.io/json"
3
- import { readOrComputeValue } from ".."
4
- import type { Store, StoreCore } from ".."
3
+ import { newest } from ".."
4
+ import type { Store } from ".."
5
5
  import type { Atom } from "../atom"
6
6
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
7
7
 
@@ -10,27 +10,21 @@ export function copyMutableIfWithinTransaction<T>(
10
10
  atom: Atom<T> | (Atom<T> & JsonInterface<T, Json.Serializable>),
11
11
  store: Store,
12
12
  ): T {
13
- if (
14
- store.transactionStatus.phase === `building` ||
15
- store.transactionStatus.phase === `applying`
16
- ) {
13
+ const target = newest(store)
14
+ const parent = target.parent
15
+ if (parent !== null) {
17
16
  if (`toJson` in atom && `fromJson` in atom) {
18
- const copiedValue = copyMutableIfNeeded(
19
- atom,
20
- atom,
21
- store,
22
- store.transactionStatus.core,
23
- )
17
+ const copiedValue = copyMutableIfNeeded(atom, atom, parent, target)
24
18
  return copiedValue
25
19
  }
26
20
  if (`family` in atom) {
27
- const family = store.transactionStatus.core.families.get(atom.family.key)
21
+ const family = parent.families.get(atom.family.key)
28
22
  if (family && family.type === `atom_family`) {
29
23
  const result = copyMutableFamilyMemberWithinTransaction<T>(
30
24
  atom,
31
25
  family,
32
- store,
33
- store.transactionStatus.core,
26
+ parent,
27
+ target,
34
28
  )
35
29
  if (result) {
36
30
  return result
@@ -47,7 +41,7 @@ export function copyMutableFamilyMemberWithinTransaction<T>(
47
41
  | AtomFamily<T, any>
48
42
  | (AtomFamily<T, any> & JsonInterface<T, Json.Serializable>),
49
43
  origin: Store,
50
- target: StoreCore,
44
+ target: Store,
51
45
  ): T | null {
52
46
  if (`toJson` in family && `fromJson` in family) {
53
47
  const copyCreated = copyMutableIfNeeded(atom, family, origin, target)
@@ -1,6 +1,6 @@
1
1
  import type { AtomFamily } from "atom.io"
2
2
  import type { Json, JsonInterface } from "atom.io/json"
3
- import type { Store, StoreCore } from ".."
3
+ import type { Store } from ".."
4
4
  import type { Atom } from "../atom"
5
5
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
6
6
 
@@ -1,12 +1,12 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { evictCachedValue } from "../caching"
3
+ import { newest } from "../lineage"
3
4
  import { isDone, markDone } from "../operation"
4
5
  import type { Store } from "../store"
5
- import { target } from "../transaction"
6
6
 
7
7
  export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
8
- const core = target(store)
9
- const downstreamKeys = core.selectorAtoms.getRelatedKeys(atom.key)
8
+ const target = newest(store)
9
+ const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key)
10
10
  store.logger.info(
11
11
  `🧹`,
12
12
  atom.type,
@@ -17,12 +17,12 @@ export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
17
17
  downstreamKeys ?? `to evict`,
18
18
  )
19
19
  if (downstreamKeys) {
20
- if (core.operation.open) {
20
+ if (target.operation.open) {
21
21
  store.logger.info(
22
22
  `🧹`,
23
23
  atom.type,
24
24
  atom.key,
25
- `[ ${[...core.operation.done].join(`, `)} ] already done`,
25
+ `[ ${[...target.operation.done].join(`, `)} ] already done`,
26
26
  )
27
27
  }
28
28
  for (const key of downstreamKeys) {
@@ -1,6 +1,7 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { isAtomDefault, markAtomAsNotDefault } from "../atom"
3
3
  import { cacheValue } from "../caching"
4
+ import { newest } from "../lineage"
4
5
  import { markDone } from "../operation"
5
6
  import { readOrComputeValue } from "../read-or-compute-value"
6
7
  import type { Store } from "../store"
@@ -15,6 +16,7 @@ export const setAtom = <T>(
15
16
  next: T | ((oldValue: T) => T),
16
17
  store: Store,
17
18
  ): void => {
19
+ const target = newest(store)
18
20
  const oldValue = readOrComputeValue(atom, store)
19
21
  let newValue = copyMutableIfWithinTransaction(oldValue, atom, store)
20
22
  newValue = become(next)(newValue)
@@ -26,7 +28,10 @@ export const setAtom = <T>(
26
28
  markDone(atom.key, store)
27
29
  evictDownStream(atom, store)
28
30
  const update = { oldValue, newValue }
29
- if (store.transactionStatus.phase !== `building`) {
31
+ if (
32
+ target.transactionMeta === null ||
33
+ target.transactionMeta.phase === `applying`
34
+ ) {
30
35
  emitUpdate(atom, update, store)
31
36
  } else {
32
37
  stowUpdate(atom, update, store)
@@ -1,6 +1,7 @@
1
1
  import type { KeyedStateUpdate, StateUpdate } from "atom.io"
2
2
 
3
3
  import type { Atom } from "../atom"
4
+ import { newest } from "../lineage"
4
5
  import { isTransceiver } from "../mutable"
5
6
  import type { Store } from "../store"
6
7
 
@@ -22,7 +23,11 @@ export const stowUpdate = <T>(
22
23
  store: Store,
23
24
  ): void => {
24
25
  const { key } = state
25
- if (store.transactionStatus.phase !== `building`) {
26
+ const target = newest(store)
27
+ if (
28
+ target.transactionMeta === null ||
29
+ target.transactionMeta.phase !== `building`
30
+ ) {
26
31
  store.logger.error(
27
32
  `🐞`,
28
33
  `atom`,
@@ -39,7 +44,7 @@ export const stowUpdate = <T>(
39
44
  if (state.family) {
40
45
  atomUpdate.family = state.family
41
46
  }
42
- store.transactionStatus.atomUpdates.push(atomUpdate)
47
+ target.transactionMeta.update.updates.push(atomUpdate)
43
48
  store.logger.info(
44
49
  `📁`,
45
50
  `atom`,
@@ -1,4 +1,4 @@
1
- import { AtomIOLogger, simpleLogger } from "atom.io"
1
+ import { AtomIOLogger } from "atom.io"
2
2
  import type {
3
3
  AtomFamily,
4
4
  AtomToken,
@@ -15,31 +15,35 @@ import type {
15
15
  import { Junction } from "~/packages/rel8/junction/src"
16
16
 
17
17
  import type { Atom } from "../atom"
18
+ import type { Lineage } from "../lineage"
18
19
  import type { MutableAtom, Tracker, Transceiver } from "../mutable"
19
20
  import type { OperationProgress } from "../operation"
20
21
  import type { ReadonlySelector, Selector } from "../selector"
21
- import { Subject } from "../subject"
22
+ import { StatefulSubject, Subject } from "../subject"
22
23
  import type { Timeline } from "../timeline"
23
- import type { Transaction, TransactionStatus } from "../transaction"
24
-
25
- export type StoreCore = Pick<
26
- Store,
27
- | `atoms`
28
- | `atomsThatAreDefault`
29
- | `families`
30
- | `operation`
31
- | `readonlySelectors`
32
- | `selectorAtoms`
33
- | `selectorGraph`
34
- | `selectors`
35
- | `timelineAtoms`
36
- | `timelines`
37
- | `trackers`
38
- | `transactions`
39
- | `valueMap`
40
- >
41
-
42
- export class Store {
24
+ import type { Transaction, TransactionMeta } from "../transaction"
25
+
26
+ // export type StoreCore = Pick<
27
+ // Store,
28
+ // | `atoms`
29
+ // | `atomsThatAreDefault`
30
+ // | `families`
31
+ // | `operation`
32
+ // | `readonlySelectors`
33
+ // | `selectorAtoms`
34
+ // | `selectorGraph`
35
+ // | `selectors`
36
+ // | `timelineAtoms`
37
+ // | `timelines`
38
+ // | `trackers`
39
+ // | `transactions`
40
+ // | `valueMap`
41
+ // >
42
+
43
+ export class Store implements Lineage {
44
+ public parent: Store | null = null
45
+ public child: Store | null = null
46
+
43
47
  public valueMap = new Map<string, any>()
44
48
 
45
49
  public atoms = new Map<string, Atom<any> | MutableAtom<any>>()
@@ -88,10 +92,11 @@ export class Store {
88
92
  >(),
89
93
  transactionCreation: new Subject<TransactionToken<ƒn>>(),
90
94
  timelineCreation: new Subject<TimelineToken>(),
95
+ transactionApplying: new StatefulSubject<TransactionMeta<ƒn> | null>(null),
91
96
  operationStatus: new Subject<OperationProgress>(),
92
97
  }
93
98
  public operation: OperationProgress = { open: false }
94
- public transactionStatus: TransactionStatus<ƒn> = { phase: `idle` }
99
+ public transactionMeta: TransactionMeta<ƒn> | null = null
95
100
 
96
101
  public config: {
97
102
  name: string
@@ -118,7 +123,9 @@ export class Store {
118
123
  if (store !== null) {
119
124
  this.valueMap = new Map(store?.valueMap)
120
125
  this.operation = { ...store?.operation }
121
- this.transactionStatus = { ...store?.transactionStatus }
126
+ this.transactionMeta = store?.transactionMeta
127
+ ? { ...store?.transactionMeta }
128
+ : null
122
129
  this.config = {
123
130
  ...store?.config,
124
131
  name,
@@ -5,8 +5,7 @@ import type {
5
5
  StateToken,
6
6
  } from "atom.io"
7
7
  import type { Atom, ReadonlySelector, Selector, Store } from ".."
8
- import { withdraw } from ".."
9
- import { target } from "../transaction"
8
+ import { newest, withdraw } from ".."
10
9
 
11
10
  export function withdrawNewFamilyMember<T>(
12
11
  token: AtomToken<T>,
@@ -43,8 +42,8 @@ export function withdrawNewFamilyMember<T>(
43
42
  token.key,
44
43
  `creating new family member in store "${store.config.name}"`,
45
44
  )
46
- const core = target(store)
47
- const family = core.families.get(token.family.key)
45
+ const target = newest(store)
46
+ const family = target.families.get(token.family.key)
48
47
  if (family) {
49
48
  const jsonSubKey = JSON.parse(token.family.subKey)
50
49
  family(jsonSubKey)
@@ -9,11 +9,10 @@ import type {
9
9
  } from "atom.io"
10
10
 
11
11
  import type { Atom } from "../atom"
12
+ import { newest } from "../lineage"
12
13
  import type { ReadonlySelector, Selector } from "../selector"
13
- import { addAtomToTimeline } from "../timeline"
14
14
  import type { Timeline } from "../timeline"
15
15
  import type { Transaction } from "../transaction"
16
- import { target } from "../transaction"
17
16
  import type { Store } from "./store"
18
17
 
19
18
  export function withdraw<T>(
@@ -58,67 +57,67 @@ export function withdraw<T>(
58
57
  | Timeline
59
58
  | Transaction<T extends ƒn ? T : never>
60
59
  | undefined {
61
- let core = target(store)
62
- let state =
63
- core.atoms.get(token.key) ??
64
- core.selectors.get(token.key) ??
65
- core.readonlySelectors.get(token.key) ??
66
- core.transactions.get(token.key) ??
67
- core.timelines.get(token.key)
60
+ const target = newest(store)
61
+ const state =
62
+ target.atoms.get(token.key) ??
63
+ target.selectors.get(token.key) ??
64
+ target.readonlySelectors.get(token.key) ??
65
+ target.transactions.get(token.key) ??
66
+ target.timelines.get(token.key)
68
67
  if (state) {
69
68
  return state
70
69
  }
71
- if (store.transactionStatus.phase === `applying`) {
72
- core = store.transactionStatus.core
73
- state =
74
- core.atoms.get(token.key) ??
75
- core.selectors.get(token.key) ??
76
- core.readonlySelectors.get(token.key) ??
77
- core.transactions.get(token.key) ??
78
- core.timelines.get(token.key)
70
+ // if (target.transactionMeta?.phase === `applying`) {
79
71
 
80
- if (state) {
81
- store.logger.info(
82
- `🛠️`,
83
- token.type,
84
- token.key,
85
- `add ${token.type} "${token.key}"`,
86
- )
87
- switch (state.type) {
88
- case `atom`: {
89
- store.atoms.set(token.key, state)
90
- store.valueMap.set(token.key, state.default)
91
- const stateKey = state.key
92
- const familyKey = state.family?.key
93
- let timelineKey = core.timelineAtoms.getRelatedKey(stateKey)
94
- if (timelineKey === undefined && typeof familyKey === `string`) {
95
- timelineKey = core.timelineAtoms.getRelatedKey(familyKey)
96
- }
97
- const timeline =
98
- typeof timelineKey === `string`
99
- ? store.timelines.get(timelineKey)
100
- : undefined
72
+ // state =
73
+ // target.atoms.get(token.key) ??
74
+ // core.selectors.get(token.key) ??
75
+ // core.readonlySelectors.get(token.key) ??
76
+ // core.transactions.get(token.key) ??
77
+ // core.timelines.get(token.key)
101
78
 
102
- if (timeline) {
103
- addAtomToTimeline(state, timeline, store)
104
- }
105
- break
106
- }
107
- case `selector`:
108
- core.selectors.set(token.key, state)
109
- break
110
- case `readonly_selector`:
111
- core.readonlySelectors.set(token.key, state)
112
- break
113
- case `transaction`:
114
- core.transactions.set(token.key, state)
115
- break
116
- case `timeline`:
117
- core.timelines.set(token.key, state)
118
- break
119
- }
120
- return state
121
- }
122
- }
79
+ // if (state) {
80
+ // store.logger.info(
81
+ // `🛠️`,
82
+ // token.type,
83
+ // token.key,
84
+ // `add ${token.type} "${token.key}"`,
85
+ // )
86
+ // switch (state.type) {
87
+ // case `atom`: {
88
+ // store.atoms.set(token.key, state)
89
+ // store.valueMap.set(token.key, state.default)
90
+ // const stateKey = state.key
91
+ // const familyKey = state.family?.key
92
+ // let timelineKey = core.timelineAtoms.getRelatedKey(stateKey)
93
+ // if (timelineKey === undefined && typeof familyKey === `string`) {
94
+ // timelineKey = core.timelineAtoms.getRelatedKey(familyKey)
95
+ // }
96
+ // const timeline =
97
+ // typeof timelineKey === `string`
98
+ // ? store.timelines.get(timelineKey)
99
+ // : undefined
100
+
101
+ // if (timeline) {
102
+ // addAtomToTimeline(state, timeline, store)
103
+ // }
104
+ // break
105
+ // }
106
+ // case `selector`:
107
+ // core.selectors.set(token.key, state)
108
+ // break
109
+ // case `readonly_selector`:
110
+ // core.readonlySelectors.set(token.key, state)
111
+ // break
112
+ // case `transaction`:
113
+ // core.transactions.set(token.key, state)
114
+ // break
115
+ // case `timeline`:
116
+ // core.timelines.set(token.key, state)
117
+ // break
118
+ // }
119
+ // return state
120
+ // }
121
+ // }
123
122
  return undefined
124
123
  }
@@ -19,3 +19,17 @@ export class Subject<T> {
19
19
  }
20
20
  }
21
21
  }
22
+
23
+ export class StatefulSubject<T> extends Subject<T> {
24
+ public state: T
25
+
26
+ public constructor(initialState: T) {
27
+ super()
28
+ this.state = initialState
29
+ }
30
+
31
+ public next(value: T): void {
32
+ this.state = value
33
+ super.next(value)
34
+ }
35
+ }
@@ -1,21 +1,21 @@
1
1
  import type { Atom } from "../atom"
2
+ import { newest } from "../lineage"
2
3
  import type { ReadonlySelector, Selector } from "../selector"
3
4
  import type { Store } from "../store"
4
- import { target } from "../transaction"
5
5
 
6
6
  export const recallState = <T>(
7
7
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
8
8
  store: Store,
9
9
  ): T => {
10
- const core = target(store)
11
- if (!core.operation.open) {
10
+ const target = newest(store)
11
+ if (!target.operation.open) {
12
12
  store.logger.warn(
13
13
  `🐞`,
14
14
  state.type,
15
15
  state.key,
16
16
  `recall called outside of an operation. This is probably a bug.`,
17
17
  )
18
- return core.valueMap.get(state.key)
18
+ return target.valueMap.get(state.key)
19
19
  }
20
- return core.operation.prev.get(state.key)
20
+ return target.operation.prev.get(state.key)
21
21
  }
@@ -1,8 +1,9 @@
1
+ import type { TransactionUpdate, ƒn } from "atom.io"
1
2
  import type { AtomToken, TimelineUpdate } from "atom.io"
2
3
 
4
+ import { newest } from "../lineage"
3
5
  import type { Store } from "../store"
4
6
  import { withdraw } from "../store"
5
- import { target } from "../transaction"
6
7
  import type {
7
8
  Timeline,
8
9
  TimelineAtomUpdate,
@@ -21,6 +22,7 @@ export const addAtomToTimeline = (
21
22
  )
22
23
  }
23
24
  atom.subject.subscribe(`timeline`, (update) => {
25
+ const target = newest(store)
24
26
  const currentSelectorKey =
25
27
  store.operation.open && store.operation.token.type === `selector`
26
28
  ? store.operation.token.key
@@ -30,13 +32,8 @@ export const addAtomToTimeline = (
30
32
  ? store.operation.time
31
33
  : null
32
34
  const currentTransactionKey =
33
- store.transactionStatus.phase === `applying`
34
- ? store.transactionStatus.key
35
- : null
36
- const currentTransactionTime =
37
- store.transactionStatus.phase === `applying`
38
- ? store.transactionStatus.time
39
- : null
35
+ target.subject.transactionApplying.state?.update.key
36
+ const currentTransactionTime = target.subject.transactionApplying.state?.time
40
37
 
41
38
  store.logger.info(
42
39
  `⏳`,
@@ -54,7 +51,6 @@ export const addAtomToTimeline = (
54
51
  ? `in selector "${currentSelectorKey}"`
55
52
  : ``,
56
53
  )
57
-
58
54
  if (tl.timeTraveling === null) {
59
55
  if (tl.selectorTime && tl.selectorTime !== currentSelectorTime) {
60
56
  const mostRecentUpdate: TimelineUpdate | undefined = tl.history.at(-1)
@@ -64,10 +60,7 @@ export const addAtomToTimeline = (
64
60
  )
65
61
  }
66
62
  }
67
- if (
68
- currentTransactionKey &&
69
- store.transactionStatus.phase === `applying`
70
- ) {
63
+ if (currentTransactionKey) {
71
64
  const currentTransaction = withdraw(
72
65
  { key: currentTransactionKey, type: `transaction` },
73
66
  store,
@@ -96,26 +89,43 @@ export const addAtomToTimeline = (
96
89
  tl.history.splice(tl.at)
97
90
  }
98
91
 
99
- const atomUpdates = update.atomUpdates.filter((atomUpdate) => {
100
- const core = target(store)
101
- const atomOrFamilyKeys = core.timelineAtoms.getRelatedKeys(
102
- tl.key,
103
- )
92
+ const filterUpdates = (
93
+ updates: TransactionUpdate<ƒn>[`updates`],
94
+ ) =>
95
+ updates
96
+ .filter((updateFromTx) => {
97
+ const target = newest(store)
98
+ if (`updates` in updateFromTx) {
99
+ return true
100
+ }
101
+ const atomOrFamilyKeys =
102
+ target.timelineAtoms.getRelatedKeys(tl.key)
103
+
104
+ return atomOrFamilyKeys
105
+ ? [...atomOrFamilyKeys].some(
106
+ (key) =>
107
+ key === updateFromTx.key ||
108
+ key === updateFromTx.family?.key,
109
+ )
110
+ : false
111
+ })
112
+ .map((updateFromTx) => {
113
+ if (`updates` in updateFromTx) {
114
+ return {
115
+ ...updateFromTx,
116
+ updates: filterUpdates(updateFromTx.updates),
117
+ }
118
+ }
119
+ return updateFromTx
120
+ })
104
121
 
105
- return atomOrFamilyKeys
106
- ? [...atomOrFamilyKeys].some(
107
- (key) =>
108
- key === atomUpdate.key ||
109
- key === atomUpdate.family?.key,
110
- )
111
- : false
112
- })
122
+ const updates = filterUpdates(update.updates)
113
123
 
114
124
  const timelineTransactionUpdate: TimelineTransactionUpdate = {
115
125
  type: `transaction_update`,
116
126
  timestamp: currentTransactionTime,
117
127
  ...update,
118
- atomUpdates,
128
+ updates,
119
129
  }
120
130
  const willCapture =
121
131
  tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true
@@ -8,9 +8,9 @@ import type {
8
8
  ƒn,
9
9
  } from "atom.io"
10
10
 
11
+ import { newest } from "../lineage"
11
12
  import type { Store } from "../store"
12
13
  import { Subject } from "../subject"
13
- import { target } from "../transaction"
14
14
  import { addAtomToTimeline } from "./add-atom-to-timeline"
15
15
 
16
16
  export type TimelineAtomUpdate = StateUpdate<unknown> & {
@@ -71,9 +71,9 @@ export function createTimeline(
71
71
  tl.shouldCapture = options.shouldCapture
72
72
  }
73
73
 
74
- const core = target(store)
74
+ const target = newest(store)
75
75
  for (const tokenOrFamily of options.atoms) {
76
- const timelineKey = core.timelineAtoms.getRelatedKey(tokenOrFamily.key)
76
+ const timelineKey = target.timelineAtoms.getRelatedKey(tokenOrFamily.key)
77
77
  if (timelineKey) {
78
78
  store.logger.error(
79
79
  `❌`,
@@ -86,11 +86,9 @@ export function createTimeline(
86
86
  if (tokenOrFamily.type === `atom_family`) {
87
87
  const family = tokenOrFamily
88
88
  family.subject.subscribe(`timeline:${options.key}`, (token) => {
89
- // if (!core.atoms.has(token.key)) {
90
89
  addAtomToTimeline(token, tl, store)
91
- // }
92
90
  })
93
- for (const atom of core.atoms.values()) {
91
+ for (const atom of target.atoms.values()) {
94
92
  if (atom.family?.key === family.key) {
95
93
  addAtomToTimeline(atom, tl, store)
96
94
  }
@@ -98,7 +96,7 @@ export function createTimeline(
98
96
  } else {
99
97
  const token = tokenOrFamily
100
98
  if (`family` in token && token.family) {
101
- const familyTimelineKey = core.timelineAtoms.getRelatedKey(
99
+ const familyTimelineKey = target.timelineAtoms.getRelatedKey(
102
100
  token.family.key,
103
101
  )
104
102
  if (familyTimelineKey) {
@@ -113,7 +111,7 @@ export function createTimeline(
113
111
  }
114
112
  addAtomToTimeline(token, tl, store)
115
113
  }
116
- core.timelineAtoms = core.timelineAtoms.set({
114
+ target.timelineAtoms = target.timelineAtoms.set({
117
115
  atomKey: tokenOrFamily.key,
118
116
  timelineKey: options.key,
119
117
  })
@@ -1,4 +1,4 @@
1
- import type { TimelineToken } from "atom.io"
1
+ import type { KeyedStateUpdate, TimelineToken, TransactionUpdate } from "atom.io"
2
2
  import { setState } from "atom.io"
3
3
 
4
4
  import type { Store } from "../store"
@@ -50,19 +50,33 @@ export const timeTravel = (
50
50
  }
51
51
 
52
52
  const update = timelineData.history[timelineData.at]
53
- const updateValues = (atomUpdate: any) => {
53
+ const updateValues = (atomUpdate: KeyedStateUpdate<any>) => {
54
54
  const { key, newValue, oldValue } = atomUpdate
55
55
  const value = direction === `forward` ? newValue : oldValue
56
56
  setState({ key, type: `atom` }, value, store)
57
57
  }
58
+ const updateValuesFromTransactionUpdate = (
59
+ transactionUpdate: TransactionUpdate<any>,
60
+ ) => {
61
+ const updates =
62
+ direction === `forward`
63
+ ? transactionUpdate.updates
64
+ : [...transactionUpdate.updates].reverse()
65
+ for (const updateFromTransaction of updates) {
66
+ if (`newValue` in updateFromTransaction) {
67
+ updateValues(updateFromTransaction)
68
+ } else {
69
+ updateValuesFromTransactionUpdate(updateFromTransaction)
70
+ }
71
+ }
72
+ }
58
73
 
59
74
  switch (update.type) {
60
75
  case `atom_update`: {
61
76
  updateValues(update)
62
77
  break
63
78
  }
64
- case `selector_update`:
65
- case `transaction_update`: {
79
+ case `selector_update`: {
66
80
  const updates =
67
81
  direction === `forward`
68
82
  ? update.atomUpdates
@@ -72,6 +86,10 @@ export const timeTravel = (
72
86
  }
73
87
  break
74
88
  }
89
+ case `transaction_update`: {
90
+ updateValuesFromTransactionUpdate(update)
91
+ break
92
+ }
75
93
  }
76
94
 
77
95
  if (direction === `forward`) {