atom.io 0.36.3 → 0.37.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.
Files changed (121) hide show
  1. package/dist/data/index.d.ts.map +1 -1
  2. package/dist/data/index.js.map +1 -1
  3. package/dist/eslint-plugin/index.js +1 -2
  4. package/dist/eslint-plugin/index.js.map +1 -1
  5. package/dist/internal/index.d.ts +71 -102
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +566 -515
  8. package/dist/internal/index.js.map +1 -1
  9. package/dist/introspection/index.d.ts +2 -2
  10. package/dist/introspection/index.d.ts.map +1 -1
  11. package/dist/introspection/index.js +1 -1
  12. package/dist/introspection/index.js.map +1 -1
  13. package/dist/json/index.d.ts +2 -1
  14. package/dist/json/index.d.ts.map +1 -1
  15. package/dist/json/index.js.map +1 -1
  16. package/dist/main/index.d.ts +154 -139
  17. package/dist/main/index.d.ts.map +1 -1
  18. package/dist/main/index.js.map +1 -1
  19. package/dist/react/index.d.ts.map +1 -1
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/react-devtools/index.d.ts.map +1 -1
  22. package/dist/react-devtools/index.js +54 -56
  23. package/dist/react-devtools/index.js.map +1 -1
  24. package/dist/realtime/index.d.ts.map +1 -1
  25. package/dist/realtime/index.js.map +1 -1
  26. package/dist/realtime-client/index.d.ts +3 -3
  27. package/dist/realtime-client/index.d.ts.map +1 -1
  28. package/dist/realtime-client/index.js +6 -6
  29. package/dist/realtime-client/index.js.map +1 -1
  30. package/dist/realtime-react/index.d.ts.map +1 -1
  31. package/dist/realtime-react/index.js.map +1 -1
  32. package/dist/realtime-server/index.d.ts +5 -5
  33. package/dist/realtime-server/index.d.ts.map +1 -1
  34. package/dist/realtime-server/index.js +10 -12
  35. package/dist/realtime-server/index.js.map +1 -1
  36. package/dist/realtime-testing/index.d.ts.map +1 -1
  37. package/dist/realtime-testing/index.js.map +1 -1
  38. package/dist/transceivers/set-rtx/index.d.ts +1 -1
  39. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  40. package/dist/transceivers/set-rtx/index.js +1 -3
  41. package/dist/transceivers/set-rtx/index.js.map +1 -1
  42. package/dist/use-o-DXPncKmZ.js.map +1 -1
  43. package/dist/web/index.d.ts +2 -2
  44. package/dist/web/index.d.ts.map +1 -1
  45. package/dist/web/index.js.map +1 -1
  46. package/package.json +6 -6
  47. package/src/internal/atom/dispose-atom.ts +16 -9
  48. package/src/internal/caching.ts +1 -1
  49. package/src/internal/families/create-readonly-held-selector-family.ts +3 -5
  50. package/src/internal/families/create-readonly-pure-selector-family.ts +3 -5
  51. package/src/internal/families/create-regular-atom-family.ts +7 -7
  52. package/src/internal/families/create-writable-held-selector-family.ts +3 -5
  53. package/src/internal/families/create-writable-pure-selector-family.ts +3 -5
  54. package/src/internal/families/find-in-store.ts +17 -34
  55. package/src/internal/families/init-family-member.ts +5 -87
  56. package/src/internal/families/mint-in-store.ts +74 -0
  57. package/src/internal/get-state/get-from-store.ts +19 -6
  58. package/src/internal/get-state/read-or-compute-value.ts +4 -2
  59. package/src/internal/index.ts +25 -36
  60. package/src/internal/ingest-updates/ingest-atom-update.ts +7 -7
  61. package/src/internal/ingest-updates/ingest-creation-disposal.ts +11 -11
  62. package/src/internal/ingest-updates/ingest-selector-update.ts +8 -4
  63. package/src/internal/ingest-updates/ingest-transaction-update.ts +5 -6
  64. package/src/internal/install-into-store.ts +2 -2
  65. package/src/internal/join/join-internal.ts +1 -1
  66. package/src/internal/molecule.ts +12 -9
  67. package/src/internal/mutable/create-mutable-atom-family.ts +4 -6
  68. package/src/internal/mutable/tracker.ts +2 -2
  69. package/src/internal/mutable/transceiver.ts +6 -4
  70. package/src/internal/operation.ts +17 -14
  71. package/src/internal/selector/create-readonly-held-selector.ts +9 -7
  72. package/src/internal/selector/create-readonly-pure-selector.ts +8 -5
  73. package/src/internal/selector/create-writable-held-selector.ts +12 -21
  74. package/src/internal/selector/create-writable-pure-selector.ts +15 -28
  75. package/src/internal/selector/dispose-selector.ts +6 -1
  76. package/src/internal/selector/get-selector-dependency-keys.ts +2 -6
  77. package/src/internal/selector/register-selector.ts +64 -74
  78. package/src/internal/selector/trace-selector-atoms.ts +2 -2
  79. package/src/internal/selector/update-selector-atoms.ts +2 -2
  80. package/src/internal/set-state/dispatch-state-update.ts +101 -0
  81. package/src/internal/set-state/operate-on-store.ts +126 -0
  82. package/src/internal/set-state/reset-atom-or-selector.ts +24 -15
  83. package/src/internal/set-state/set-atom-or-selector.ts +9 -4
  84. package/src/internal/set-state/set-atom.ts +4 -49
  85. package/src/internal/set-state/set-into-store.ts +11 -77
  86. package/src/internal/set-state/set-selector.ts +35 -0
  87. package/src/internal/store/store.ts +4 -4
  88. package/src/internal/subscribe/subscribe-in-store.ts +3 -3
  89. package/src/internal/subscribe/subscribe-to-timeline.ts +2 -2
  90. package/src/internal/timeline/create-timeline.ts +57 -101
  91. package/src/internal/timeline/time-travel.ts +1 -1
  92. package/src/internal/transaction/abort-transaction.ts +1 -1
  93. package/src/internal/transaction/apply-transaction.ts +7 -7
  94. package/src/internal/transaction/build-transaction.ts +10 -9
  95. package/src/internal/transaction/create-transaction.ts +4 -3
  96. package/src/internal/transaction/index.ts +6 -2
  97. package/src/introspection/attach-introspection-states.ts +2 -2
  98. package/src/introspection/attach-transaction-logs.ts +13 -6
  99. package/src/json/index.ts +3 -1
  100. package/src/main/atom.ts +2 -1
  101. package/src/main/events.ts +109 -0
  102. package/src/main/get-state.ts +1 -1
  103. package/src/main/index.ts +3 -0
  104. package/src/main/subscribe.ts +9 -19
  105. package/src/main/timeline.ts +3 -21
  106. package/src/main/transaction.ts +0 -65
  107. package/src/main/validators.ts +8 -2
  108. package/src/react-devtools/TimelineIndex.tsx +1 -1
  109. package/src/react-devtools/TransactionIndex.tsx +5 -3
  110. package/src/react-devtools/Updates.tsx +54 -46
  111. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +20 -10
  112. package/src/realtime-client/realtime-client-stores/client-sync-store.ts +4 -4
  113. package/src/realtime-client/sync-continuity.ts +1 -1
  114. package/src/realtime-server/continuity/prepare-to-serve-transaction-request.ts +14 -8
  115. package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +5 -2
  116. package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
  117. package/src/realtime-server/realtime-action-receiver.ts +6 -3
  118. package/src/realtime-server/realtime-server-stores/server-sync-store.ts +13 -16
  119. package/src/transceivers/set-rtx/set-rtx.ts +1 -3
  120. package/src/web/persist-sync.ts +2 -2
  121. package/src/internal/set-state/emit-update.ts +0 -40
@@ -1,40 +1,49 @@
1
- import type { Atom, WritableState } from ".."
1
+ import type { Atom, OpenOperation, Store, WritableState } from ".."
2
2
  import { traceRootSelectorAtoms } from ".."
3
- import type { Store } from "../store"
3
+ import { dispatchOrDeferStateUpdate } from "./dispatch-state-update"
4
4
  import { setAtom } from "./set-atom"
5
5
 
6
- function resetAtom(store: Store, state: Atom<any>) {
7
- switch (state.type) {
6
+ function resetAtom<T>(
7
+ target: Store & { operation: OpenOperation },
8
+ atom: Atom<T>,
9
+ ): [oldValue: T, newValue: T] {
10
+ switch (atom.type) {
8
11
  case `mutable_atom`:
9
- setAtom(store, state, new state.class())
10
- return
12
+ return setAtom(target, atom, new atom.class())
11
13
  case `atom`: {
12
- let def = state.default
14
+ let def = atom.default
13
15
  if (def instanceof Function) {
14
16
  def = def()
15
17
  }
16
- setAtom(store, state, def)
18
+ return setAtom(target, atom, def)
17
19
  }
18
20
  }
19
21
  }
20
22
 
21
- export function resetAtomOrSelector(
22
- store: Store,
23
- state: WritableState<any>,
24
- ): void {
23
+ export function resetAtomOrSelector<T>(
24
+ target: Store & { operation: OpenOperation },
25
+ state: WritableState<T>,
26
+ ): [oldValue: T, newValue: T] {
27
+ let protoUpdate: [T, T]
25
28
  switch (state.type) {
26
29
  case `atom`:
27
30
  case `mutable_atom`:
28
- resetAtom(store, state)
31
+ protoUpdate = resetAtom(target, state)
29
32
  break
30
33
  case `writable_pure_selector`:
31
34
  case `writable_held_selector`:
32
35
  {
33
- const atoms = traceRootSelectorAtoms(store, state.key)
36
+ const oldValue = state.getFrom(target)
37
+ const atoms = traceRootSelectorAtoms(target, state.key)
34
38
  for (const atom of atoms.values()) {
35
- resetAtom(store, atom)
39
+ const rootProtoUpdate = resetAtom(target, atom)
40
+ dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false)
36
41
  }
42
+ const newValue = state.getFrom(target)
43
+ protoUpdate = [oldValue, newValue]
37
44
  }
38
45
  break
39
46
  }
47
+
48
+ return protoUpdate
40
49
  }
@@ -1,20 +1,25 @@
1
1
  import type { WritableState } from ".."
2
+ import type { OpenOperation } from "../operation"
2
3
  import type { Store } from "../store"
3
4
  import { setAtom } from "./set-atom"
5
+ import { setSelector } from "./set-selector"
4
6
 
5
7
  export const setAtomOrSelector = <T>(
6
- store: Store,
8
+ target: Store & { operation: OpenOperation },
7
9
  state: WritableState<T>,
8
10
  value: T | ((oldValue: T) => T),
9
- ): void => {
11
+ ): [oldValue: T, newValue: T] => {
12
+ let protoUpdate: [T, T]
10
13
  switch (state.type) {
11
14
  case `atom`:
12
15
  case `mutable_atom`:
13
- setAtom(store, state, value)
16
+ protoUpdate = setAtom(target, state, value)
14
17
  break
15
18
  case `writable_pure_selector`:
16
19
  case `writable_held_selector`:
17
- state.set(value)
20
+ protoUpdate = setSelector(target, state, value)
18
21
  break
19
22
  }
23
+
24
+ return protoUpdate
20
25
  }
@@ -1,65 +1,20 @@
1
- import type { KeyedStateUpdate } from "atom.io"
2
-
3
- import type { Atom, MutableAtom, Store } from ".."
4
- import { hasRole } from "../atom/has-role"
1
+ import type { Atom, OpenOperation, Store } from ".."
5
2
  import { writeToCache } from "../caching"
6
3
  import { readOrComputeValue } from "../get-state/read-or-compute-value"
7
- import { isTransceiver, type Transceiver } from "../mutable"
8
4
  import { markDone } from "../operation"
9
- import { isChildStore } from "../transaction/is-root-store"
10
5
  import { become } from "./become"
11
- import { emitUpdate } from "./emit-update"
12
6
  import { evictDownstreamFromAtom } from "./evict-downstream"
13
7
 
14
8
  export const setAtom = <T>(
15
- target: Store,
9
+ target: Store & { operation: OpenOperation<any> },
16
10
  atom: Atom<T>,
17
11
  next: T | ((oldValue: T) => T),
18
- ): void => {
12
+ ): [oldValue: T, newValue: T] => {
19
13
  const oldValue = readOrComputeValue(target, atom, `mut`)
20
14
  let newValue = become(next)(oldValue)
21
15
  target.logger.info(`📝`, `atom`, atom.key, `set to`, newValue)
22
16
  newValue = writeToCache(target, atom, newValue)
23
17
  markDone(target, atom.key)
24
18
  evictDownstreamFromAtom(target, atom)
25
- const update = { oldValue, newValue }
26
- if (!isChildStore(target)) {
27
- emitUpdate(target, atom, update)
28
- return
29
- }
30
- if (target.on.transactionApplying.state === null) {
31
- const { key } = atom
32
- if (isTransceiver(update.newValue)) {
33
- return
34
- }
35
- const atomUpdate: KeyedStateUpdate<T> = {
36
- type: `atom_update`,
37
- key,
38
- ...update,
39
- }
40
- if (atom.family) {
41
- atomUpdate.family = atom.family
42
- }
43
- target.transactionMeta.update.updates.push(atomUpdate)
44
- target.logger.info(
45
- `📁`,
46
- `atom`,
47
- key,
48
- `stowed (`,
49
- update.oldValue,
50
- `->`,
51
- update.newValue,
52
- `)`,
53
- )
54
- } else if (hasRole(atom, `tracker:signal`)) {
55
- const key = atom.key.slice(1)
56
- const mutable = target.atoms.get(key) as MutableAtom<
57
- Transceiver<unknown, any, any>
58
- >
59
- const transceiver = readOrComputeValue(target, mutable, `mut`)
60
- const accepted = transceiver.do(update.newValue) === null
61
- if (accepted === true) {
62
- evictDownstreamFromAtom(target, mutable)
63
- }
64
- }
19
+ return [oldValue, newValue]
65
20
  }
@@ -1,14 +1,9 @@
1
1
  import type { WritableFamilyToken, WritableToken } from "atom.io"
2
- import { type Canonical, parseJson } from "atom.io/json"
2
+ import type { Canonical } from "atom.io/json"
3
3
 
4
- import { findInStore } from "../families"
5
- import { getFamilyOfToken } from "../families/get-family-of-token"
6
- import { closeOperation, openOperation } from "../operation"
7
4
  import type { Store } from "../store"
8
- import { withdraw } from "../store"
9
- import { resetAtomOrSelector } from "./reset-atom-or-selector"
10
- import { RESET_STATE } from "./reset-in-store"
11
- import { setAtomOrSelector } from "./set-atom-or-selector"
5
+ import { operateOnStore } from "./operate-on-store"
6
+ import type { RESET_STATE } from "./reset-in-store"
12
7
 
13
8
  export function setIntoStore<T, New extends T>(
14
9
  store: Store,
@@ -16,10 +11,15 @@ export function setIntoStore<T, New extends T>(
16
11
  value: New | typeof RESET_STATE | ((oldValue: T) => New),
17
12
  ): void
18
13
 
19
- export function setIntoStore<T, K extends Canonical, New extends T>(
14
+ export function setIntoStore<
15
+ T,
16
+ K extends Canonical,
17
+ New extends T,
18
+ Key extends K,
19
+ >(
20
20
  store: Store,
21
21
  token: WritableFamilyToken<T, K>,
22
- key: K,
22
+ key: Key,
23
23
  value: New | typeof RESET_STATE | ((oldValue: T) => New),
24
24
  ): void
25
25
 
@@ -36,71 +36,5 @@ export function setIntoStore<T, New extends T>(
36
36
  value: New | typeof RESET_STATE | ((oldValue: T) => New),
37
37
  ]
38
38
  ): void {
39
- let token: WritableToken<T>
40
- let family: WritableFamilyToken<T, Canonical> | null
41
- let key: Canonical | null
42
- let value: New | typeof RESET_STATE | ((oldValue: T) => New)
43
- if (params.length === 2) {
44
- token = params[0]
45
- value = params[1]
46
- if (token.family) {
47
- // biome-ignore lint/style/noNonNullAssertion: this token belongs to a family
48
- family = getFamilyOfToken(store, token)!
49
- key = parseJson(token.family.subKey)
50
- token = findInStore(store, family, key)
51
- }
52
- } else {
53
- family = params[0]
54
- key = params[1]
55
- value = params[2]
56
- token = findInStore(store, family, key)
57
- }
58
-
59
- const action = value === RESET_STATE ? `reset` : `set`
60
-
61
- if (`counterfeit` in token && `family` in token) {
62
- const subKey = token.family.subKey
63
- const disposal = store.disposalTraces.buffer.find(
64
- (item) => item?.key === subKey,
65
- )
66
- store.logger.error(
67
- `❌`,
68
- token.type,
69
- token.key,
70
- `could not be`,
71
- action,
72
- `because it was not found in the store "${store.config.name}".`,
73
- disposal
74
- ? `This state was previously disposed:\n${disposal.trace}`
75
- : `No previous disposal trace was found.`,
76
- )
77
- return
78
- }
79
-
80
- const rejectionTime = openOperation(store, token)
81
- if (rejectionTime) {
82
- const unsubscribe = store.on.operationClose.subscribe(
83
- `waiting to ${action} "${token.key}" at T-${rejectionTime}`,
84
- function waitUntilOperationCloseToSetState() {
85
- unsubscribe()
86
- store.logger.info(
87
- `🟢`,
88
- token.type,
89
- token.key,
90
- `resuming deferred`,
91
- action,
92
- `from T-${rejectionTime}`,
93
- )
94
- setIntoStore(store, token, value)
95
- },
96
- )
97
- return
98
- }
99
- const state = withdraw(store, token)
100
- if (value === RESET_STATE) {
101
- resetAtomOrSelector(store, state)
102
- } else {
103
- setAtomOrSelector(store, state, value)
104
- }
105
- closeOperation(store)
39
+ operateOnStore(store, true, ...params)
106
40
  }
@@ -0,0 +1,35 @@
1
+ import type { WritableSelector } from ".."
2
+ import { writeToCache } from "../caching"
3
+ import { markDone, type OpenOperation } from "../operation"
4
+ import type { Store } from "../store"
5
+ import { become } from "./become"
6
+
7
+ export function setSelector<T>(
8
+ target: Store & { operation: OpenOperation<any> },
9
+ selector: WritableSelector<T>,
10
+ next: T | ((oldValue: T) => T),
11
+ ): [oldValue: T, newValue: T] {
12
+ let oldValue: T
13
+ let newValue: T
14
+ let constant: T
15
+
16
+ const { type, key } = selector
17
+
18
+ switch (selector.type) {
19
+ case `writable_pure_selector`:
20
+ oldValue = selector.getFrom(target)
21
+ newValue = become(next)(oldValue)
22
+ writeToCache(target, selector, newValue)
23
+ break
24
+ case `writable_held_selector`:
25
+ constant = selector.const
26
+ become(next)(constant)
27
+ oldValue = constant
28
+ newValue = constant
29
+ }
30
+
31
+ target.logger.info(`📝`, type, key, `setting to`, newValue)
32
+ markDone(target, key)
33
+ selector.setSelf(newValue)
34
+ return [oldValue, newValue]
35
+ }
@@ -1,8 +1,8 @@
1
1
  import type {
2
2
  AtomToken,
3
3
  Logger,
4
- MoleculeCreation,
5
- MoleculeDisposal,
4
+ MoleculeCreationEvent,
5
+ MoleculeDisposalEvent,
6
6
  SelectorToken,
7
7
  TimelineToken,
8
8
  TransactionToken,
@@ -253,8 +253,8 @@ export type StoreEventCarrier = {
253
253
  transactionCreation: Subject<TransactionToken<Fn>>
254
254
  transactionApplying: StatefulSubject<TransactionProgress<Fn> | null>
255
255
  operationClose: Subject<OperationProgress>
256
- moleculeCreation: Subject<MoleculeCreation>
257
- moleculeDisposal: Subject<MoleculeDisposal>
256
+ moleculeCreation: Subject<MoleculeCreationEvent>
257
+ moleculeDisposal: Subject<MoleculeDisposalEvent>
258
258
  }
259
259
 
260
260
  declare global {
@@ -1,8 +1,8 @@
1
1
  import type {
2
2
  ReadableToken,
3
+ TimelineEvent,
3
4
  TimelineManageable,
4
5
  TimelineToken,
5
- TimelineUpdate,
6
6
  TransactionToken,
7
7
  TransactionUpdateHandler,
8
8
  UpdateHandler,
@@ -30,7 +30,7 @@ export function subscribeInStore<F extends Fn>(
30
30
  export function subscribeInStore<M extends TimelineManageable>(
31
31
  store: Store,
32
32
  token: TimelineToken<M>,
33
- handleUpdate: (update: TimelineUpdate<M> | `redo` | `undo`) => void,
33
+ handleUpdate: (update: TimelineEvent<M> | `redo` | `undo`) => void,
34
34
  key?: string,
35
35
  ): () => void
36
36
  export function subscribeInStore<M extends TimelineManageable>(
@@ -39,7 +39,7 @@ export function subscribeInStore<M extends TimelineManageable>(
39
39
  handleUpdate:
40
40
  | TransactionUpdateHandler<any>
41
41
  | UpdateHandler<any>
42
- | ((update: TimelineUpdate<M> | `redo` | `undo`) => void),
42
+ | ((update: TimelineEvent<M> | `redo` | `undo`) => void),
43
43
  key?: string,
44
44
  ): () => void
45
45
  export function subscribeInStore(
@@ -1,4 +1,4 @@
1
- import type { TimelineManageable, TimelineToken, TimelineUpdate } from "atom.io"
1
+ import type { TimelineEvent, TimelineManageable, TimelineToken } from "atom.io"
2
2
 
3
3
  import type { Store } from "../store/store"
4
4
  import { withdraw } from "../store/withdraw"
@@ -7,7 +7,7 @@ export const subscribeToTimeline = <ManagedAtom extends TimelineManageable>(
7
7
  store: Store,
8
8
  token: TimelineToken<ManagedAtom>,
9
9
  key: string,
10
- handleUpdate: (update: TimelineUpdate<any> | `redo` | `undo`) => void,
10
+ handleUpdate: (update: TimelineEvent<any> | `redo` | `undo`) => void,
11
11
  ): (() => void) => {
12
12
  const tl = withdraw(store, token)
13
13
  store.logger.info(`👀`, `timeline`, token.key, `Adding subscription "${key}"`)
@@ -1,78 +1,38 @@
1
1
  import type {
2
2
  AtomFamilyToken,
3
3
  AtomToken,
4
- FamilyMetadata,
5
- MoleculeCreation,
6
- MoleculeDisposal,
7
- ReadableToken,
8
- StateCreation,
9
- StateDisposal,
10
- StateUpdate,
4
+ AtomUpdateEvent,
5
+ StateCreationEvent,
6
+ StateDisposalEvent,
7
+ TimelineEvent,
11
8
  TimelineManageable,
12
9
  TimelineOptions,
13
10
  TimelineToken,
14
- TimelineUpdate,
15
- TokenType,
11
+ TransactionOutcomeEvent,
12
+ TransactionSubEvent,
16
13
  TransactionToken,
17
- TransactionUpdate,
18
- TransactionUpdateContent,
19
14
  } from "atom.io"
20
15
 
21
16
  import { newest } from "../lineage"
22
17
  import { getUpdateToken } from "../mutable"
23
- import { type Store, withdraw } from "../store"
18
+ import { deposit, type Store, withdraw } from "../store"
24
19
  import { Subject } from "../subject"
25
20
  import { isChildStore } from "../transaction"
26
- import type { Flat, Fn } from "../utility-types"
27
-
28
- export type TimelineAtomUpdate<ManagedAtom extends TimelineManageable> = Flat<
29
- StateUpdate<TokenType<ManagedAtom>> & {
30
- key: string
31
- type: `atom_update`
32
- timestamp: number
33
- family?: FamilyMetadata
34
- }
35
- >
36
- export type TimelineSelectorUpdate<ManagedAtom extends TimelineManageable> = {
37
- key: string
38
- type: `selector_update`
39
- timestamp: number
40
- atomUpdates: Omit<TimelineAtomUpdate<ManagedAtom>, `timestamp`>[]
41
- }
42
- export type TimelineTransactionUpdate = Flat<
43
- TransactionUpdate<Fn> & {
44
- key: string
45
- type: `transaction_update`
46
- timestamp: number
47
- }
48
- >
49
- export type TimelineStateCreation<T extends ReadableToken<any>> = Flat<
50
- StateCreation<T> & { timestamp: number }
51
- >
52
- export type TimelineStateDisposal<T extends ReadableToken<any>> = Flat<
53
- StateDisposal<T> & { timestamp: number }
54
- >
55
- export type TimelineMoleculeCreation = Flat<
56
- MoleculeCreation & { timestamp: number }
57
- >
58
- export type TimelineMoleculeDisposal = Flat<
59
- MoleculeDisposal & { timestamp: number }
60
- >
61
21
 
62
22
  export type Timeline<ManagedAtom extends TimelineManageable> = {
63
23
  type: `timeline`
64
24
  key: string
65
25
  at: number
66
26
  shouldCapture?: (
67
- update: TimelineUpdate<ManagedAtom>,
27
+ update: TimelineEvent<ManagedAtom>,
68
28
  timeline: Timeline<ManagedAtom>,
69
29
  ) => boolean
70
30
  timeTraveling: `into_future` | `into_past` | null
71
- history: TimelineUpdate<ManagedAtom>[]
31
+ history: TimelineEvent<ManagedAtom>[]
72
32
  selectorTime: number | null
73
33
  transactionKey: string | null
74
34
  install: (store: Store) => void
75
- subject: Subject<TimelineUpdate<ManagedAtom> | `redo` | `undo`>
35
+ subject: Subject<TimelineEvent<ManagedAtom> | `redo` | `undo`>
76
36
  subscriptions: Map<string, () => void>
77
37
  }
78
38
 
@@ -187,15 +147,15 @@ function addAtomToTimeline(
187
147
  `timeline`,
188
148
  function timelineCapturesAtomUpdate(update) {
189
149
  const target = newest(store)
190
- const currentSelectorKey =
150
+ const currentSelectorToken =
191
151
  store.operation.open &&
192
152
  store.operation.token.type === `writable_pure_selector`
193
- ? store.operation.token.key
153
+ ? store.operation.token
194
154
  : null
195
155
  const currentSelectorTime =
196
156
  store.operation.open &&
197
157
  store.operation.token.type === `writable_pure_selector`
198
- ? store.operation.time
158
+ ? store.operation.timestamp
199
159
  : null
200
160
 
201
161
  const txUpdateInProgress = target.on.transactionApplying.state?.update
@@ -211,28 +171,30 @@ function addAtomToTimeline(
211
171
  `->`,
212
172
  update.newValue,
213
173
  txUpdateInProgress
214
- ? `in transaction "${txUpdateInProgress.key}"`
215
- : currentSelectorKey
216
- ? `in selector "${currentSelectorKey}"`
174
+ ? `in transaction "${txUpdateInProgress.token.key}"`
175
+ : currentSelectorToken
176
+ ? `in selector "${currentSelectorToken.key}"`
217
177
  : ``,
218
178
  )
219
179
  if (tl.timeTraveling === null) {
220
180
  if (txUpdateInProgress) {
221
181
  joinTransaction(store, tl, txUpdateInProgress)
222
- } else if (currentSelectorKey && currentSelectorTime) {
223
- let latestUpdate: TimelineUpdate<any> | undefined = tl.history.at(-1)
182
+ } else if (currentSelectorToken && currentSelectorTime) {
183
+ let latestUpdate: TimelineEvent<any> | undefined = tl.history.at(-1)
224
184
 
225
185
  if (currentSelectorTime !== tl.selectorTime) {
226
186
  latestUpdate = {
227
187
  type: `selector_update`,
228
188
  timestamp: currentSelectorTime,
229
- key: currentSelectorKey,
189
+ // key: currentSelectorKey,
190
+ token: currentSelectorToken,
230
191
  atomUpdates: [],
231
192
  }
232
193
  latestUpdate.atomUpdates.push({
233
- key: atom.key,
234
194
  type: `atom_update`,
235
- ...update,
195
+ token: atomToken,
196
+ update,
197
+ timestamp: Date.now(), // 👺 use store operation
236
198
  })
237
199
  if (tl.at !== tl.history.length) {
238
200
  tl.history.splice(tl.at)
@@ -244,8 +206,10 @@ function addAtomToTimeline(
244
206
  `⌛`,
245
207
  `timeline`,
246
208
  tl.key,
247
- `got a selector_update "${currentSelectorKey}" with`,
248
- latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key),
209
+ `got a selector_update "${currentSelectorToken.key}" with`,
210
+ latestUpdate.atomUpdates.map(
211
+ (atomUpdate) => atomUpdate.token.key,
212
+ ),
249
213
  )
250
214
 
251
215
  tl.at = tl.history.length
@@ -253,16 +217,19 @@ function addAtomToTimeline(
253
217
  } else {
254
218
  if (latestUpdate?.type === `selector_update`) {
255
219
  latestUpdate.atomUpdates.push({
256
- key: atom.key,
257
220
  type: `atom_update`,
258
- ...update,
221
+ token: atomToken,
222
+ update,
223
+ timestamp: Date.now(), // 👺 use store operation
259
224
  })
260
225
  store.logger.info(
261
226
  `⌛`,
262
227
  `timeline`,
263
228
  tl.key,
264
- `set selector_update "${currentSelectorKey}" to`,
265
- latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key),
229
+ `set selector_update "${currentSelectorToken.key}" to`,
230
+ latestUpdate?.atomUpdates.map(
231
+ (atomUpdate) => atomUpdate.token.key,
232
+ ),
266
233
  )
267
234
  }
268
235
  }
@@ -282,15 +249,11 @@ function addAtomToTimeline(
282
249
  if (tl.at !== tl.history.length) {
283
250
  tl.history.splice(tl.at)
284
251
  }
285
- const atomUpdate: TimelineAtomUpdate<any> = {
252
+ const atomUpdate: AtomUpdateEvent<any> = {
286
253
  type: `atom_update`,
254
+ token: deposit(atom),
255
+ update,
287
256
  timestamp,
288
- key: atom.key,
289
- oldValue: update.oldValue,
290
- newValue: update.newValue,
291
- }
292
- if (atom.family) {
293
- atomUpdate.family = atom.family
294
257
  }
295
258
  const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true
296
259
  store.logger.info(
@@ -340,9 +303,9 @@ function addAtomFamilyToTimeline(
340
303
  function joinTransaction(
341
304
  store: Store,
342
305
  tl: Timeline<any>,
343
- txUpdateInProgress: TransactionUpdate<Fn>,
306
+ txUpdateInProgress: TransactionOutcomeEvent<TransactionToken<any>>,
344
307
  ) {
345
- const currentTxKey = txUpdateInProgress.key
308
+ const currentTxKey = txUpdateInProgress.token.key
346
309
  const currentTxInstanceId = txUpdateInProgress.id
347
310
  const currentTxToken: TransactionToken<any> = {
348
311
  key: currentTxKey,
@@ -364,15 +327,16 @@ function joinTransaction(
364
327
  // biome-ignore lint/style/noNonNullAssertion: we are in the context of this timeline
365
328
  const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key)!
366
329
 
367
- const updates = filterTransactionUpdates(
368
- transactionUpdate.updates,
330
+ const subEventsFiltered = filterTransactionSubEvents(
331
+ transactionUpdate.subEvents,
369
332
  timelineTopics,
370
333
  )
371
334
 
372
- const timelineTransactionUpdate: TimelineTransactionUpdate = {
373
- timestamp: Date.now(),
335
+ const timelineTransactionUpdate: TransactionOutcomeEvent<
336
+ TransactionToken<any>
337
+ > = {
374
338
  ...transactionUpdate,
375
- updates,
339
+ subEvents: subEventsFiltered,
376
340
  }
377
341
  const willCapture =
378
342
  tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true
@@ -387,19 +351,20 @@ function joinTransaction(
387
351
  }
388
352
  }
389
353
 
390
- function filterTransactionUpdates(
391
- updates: TransactionUpdateContent[],
354
+ function filterTransactionSubEvents(
355
+ updates: TransactionSubEvent[],
392
356
  timelineTopics: Set<string>,
393
- ): TransactionUpdateContent[] {
357
+ ): TransactionSubEvent[] {
394
358
  return updates
395
359
  .filter((updateFromTx) => {
396
- if (updateFromTx.type === `transaction_update`) {
360
+ if (updateFromTx.type === `transaction_outcome`) {
397
361
  return true
398
362
  }
399
363
 
400
364
  let key: string
401
365
  let familyKey: string | undefined
402
366
  switch (updateFromTx.type) {
367
+ case `atom_update`:
403
368
  case `state_creation`:
404
369
  case `state_disposal`:
405
370
  key = updateFromTx.token.key
@@ -409,11 +374,6 @@ function filterTransactionUpdates(
409
374
  case `molecule_disposal`:
410
375
  case `molecule_transfer`:
411
376
  return true // always include
412
- case `atom_update`:
413
- case `selector_update`:
414
- key = updateFromTx.key
415
- familyKey = updateFromTx.family?.key
416
- break
417
377
  }
418
378
  timelineTopics.has(key)
419
379
  if (familyKey && timelineTopics.has(familyKey)) {
@@ -421,12 +381,12 @@ function filterTransactionUpdates(
421
381
  }
422
382
  return timelineTopics.has(key)
423
383
  })
424
- .map((updateFromTx) => {
425
- if (`updates` in updateFromTx) {
384
+ .map((updateFromTx): TransactionSubEvent => {
385
+ if (`subEvents` in updateFromTx) {
426
386
  return {
427
387
  ...updateFromTx,
428
- updates: filterTransactionUpdates(
429
- updateFromTx.updates,
388
+ subEvents: filterTransactionSubEvents(
389
+ updateFromTx.subEvents,
430
390
  timelineTopics,
431
391
  ),
432
392
  }
@@ -437,13 +397,9 @@ function filterTransactionUpdates(
437
397
 
438
398
  function handleStateLifecycleEvent(
439
399
  store: Store,
440
- event: StateCreation<any> | StateDisposal<any>,
400
+ event: StateCreationEvent<any> | StateDisposalEvent<any>,
441
401
  tl: Timeline<any>,
442
402
  ): void {
443
- const timestamp = Date.now()
444
- const timelineEvent = Object.assign(event, {
445
- timestamp,
446
- }) as TimelineUpdate<any>
447
403
  if (!tl.timeTraveling) {
448
404
  const target = newest(store)
449
405
  if (isChildStore(target)) {
@@ -453,9 +409,9 @@ function handleStateLifecycleEvent(
453
409
  if (txUpdateInProgress) {
454
410
  joinTransaction(store, tl, txUpdateInProgress.update)
455
411
  } else {
456
- tl.history.push(timelineEvent)
412
+ tl.history.push(event)
457
413
  tl.at = tl.history.length
458
- tl.subject.next(timelineEvent)
414
+ tl.subject.next(event)
459
415
  }
460
416
  }
461
417
  }