atom.io 0.12.1 → 0.14.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 (120) hide show
  1. package/dist/index.cjs +9 -74
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +9 -6
  4. package/dist/index.d.ts +9 -6
  5. package/dist/index.js +11 -74
  6. package/dist/index.js.map +1 -1
  7. package/dist/metafile-cjs.json +1 -1
  8. package/dist/metafile-esm.json +1 -1
  9. package/internal/dist/index.cjs +1700 -1579
  10. package/internal/dist/index.cjs.map +1 -1
  11. package/internal/dist/index.d.cts +32 -15
  12. package/internal/dist/index.d.ts +32 -15
  13. package/internal/dist/index.js +1695 -1579
  14. package/internal/dist/index.js.map +1 -1
  15. package/internal/dist/metafile-cjs.json +1 -1
  16. package/internal/dist/metafile-esm.json +1 -1
  17. package/internal/src/atom/create-atom.ts +7 -6
  18. package/internal/src/atom/delete-atom.ts +11 -11
  19. package/internal/src/atom/is-default.ts +5 -5
  20. package/internal/src/caching.ts +12 -10
  21. package/internal/src/families/create-atom-family.ts +3 -3
  22. package/internal/src/families/create-readonly-selector-family.ts +3 -3
  23. package/internal/src/families/create-selector-family.ts +4 -4
  24. package/internal/src/index.ts +1 -0
  25. package/internal/src/keys.ts +4 -4
  26. package/internal/src/lazy-map.ts +6 -2
  27. package/internal/src/lineage.ts +18 -0
  28. package/internal/src/mutable/create-mutable-atom.ts +8 -6
  29. package/internal/src/mutable/get-json-family.ts +3 -3
  30. package/internal/src/mutable/tracker.ts +18 -13
  31. package/internal/src/operation.ts +19 -19
  32. package/internal/src/selector/create-read-write-selector.ts +5 -4
  33. package/internal/src/selector/create-readonly-selector.ts +4 -3
  34. package/internal/src/selector/create-selector.ts +6 -6
  35. package/internal/src/selector/delete-selector.ts +10 -10
  36. package/internal/src/selector/get-selector-dependency-keys.ts +2 -2
  37. package/internal/src/selector/register-selector.ts +4 -4
  38. package/internal/src/selector/update-selector-atoms.ts +4 -4
  39. package/internal/src/set-state/copy-mutable-if-needed.ts +4 -3
  40. package/internal/src/set-state/copy-mutable-in-transaction.ts +10 -16
  41. package/internal/src/set-state/copy-mutable-into-new-store.ts +1 -1
  42. package/internal/src/set-state/evict-downstream.ts +5 -5
  43. package/internal/src/set-state/set-atom.ts +6 -1
  44. package/internal/src/set-state/stow-update.ts +7 -2
  45. package/internal/src/store/store.ts +31 -24
  46. package/internal/src/store/withdraw-new-family-member.ts +3 -4
  47. package/internal/src/store/withdraw.ts +58 -59
  48. package/internal/src/subject.ts +14 -0
  49. package/internal/src/subscribe/index.ts +3 -0
  50. package/internal/src/subscribe/recall-state.ts +5 -11
  51. package/internal/src/subscribe/subscribe-to-state.ts +47 -0
  52. package/internal/src/subscribe/subscribe-to-timeline.ts +28 -0
  53. package/internal/src/subscribe/subscribe-to-transaction.ts +33 -0
  54. package/internal/src/timeline/add-atom-to-timeline.ts +37 -27
  55. package/internal/src/timeline/create-timeline.ts +6 -8
  56. package/internal/src/timeline/time-travel.ts +22 -4
  57. package/internal/src/transaction/abort-transaction.ts +5 -3
  58. package/internal/src/transaction/apply-transaction.ts +80 -58
  59. package/internal/src/transaction/build-transaction.ts +33 -23
  60. package/internal/src/transaction/create-transaction.ts +6 -9
  61. package/internal/src/transaction/index.ts +2 -10
  62. package/internal/src/transaction/redo-transaction.ts +15 -10
  63. package/internal/src/transaction/undo-transaction.ts +15 -16
  64. package/introspection/dist/index.cjs +2 -2
  65. package/introspection/dist/index.cjs.map +1 -1
  66. package/introspection/dist/index.js +3 -3
  67. package/introspection/dist/index.js.map +1 -1
  68. package/introspection/src/attach-atom-index.ts +2 -2
  69. package/introspection/src/attach-selector-index.ts +2 -2
  70. package/package.json +8 -8
  71. package/react/dist/index.cjs +39 -1
  72. package/react/dist/index.cjs.map +1 -1
  73. package/react/dist/index.d.cts +9 -2
  74. package/react/dist/index.d.ts +9 -2
  75. package/react/dist/index.js +41 -4
  76. package/react/dist/index.js.map +1 -1
  77. package/react/dist/metafile-cjs.json +1 -1
  78. package/react/dist/metafile-esm.json +1 -1
  79. package/react/src/store-hooks.ts +52 -3
  80. package/react-devtools/dist/index.cjs +22 -8
  81. package/react-devtools/dist/index.cjs.map +1 -1
  82. package/react-devtools/dist/index.d.cts +17 -9
  83. package/react-devtools/dist/index.d.ts +17 -9
  84. package/react-devtools/dist/index.js +22 -8
  85. package/react-devtools/dist/index.js.map +1 -1
  86. package/react-devtools/dist/metafile-cjs.json +1 -1
  87. package/react-devtools/dist/metafile-esm.json +1 -1
  88. package/react-devtools/src/Updates.tsx +22 -10
  89. package/realtime-client/dist/index.cjs +8 -7
  90. package/realtime-client/dist/index.cjs.map +1 -1
  91. package/realtime-client/dist/index.d.cts +3 -2
  92. package/realtime-client/dist/index.d.ts +3 -2
  93. package/realtime-client/dist/index.js +3 -2
  94. package/realtime-client/dist/index.js.map +1 -1
  95. package/realtime-client/dist/metafile-cjs.json +1 -1
  96. package/realtime-client/dist/metafile-esm.json +1 -1
  97. package/realtime-client/src/use-push.ts +4 -4
  98. package/realtime-client/src/use-server-action.ts +4 -4
  99. package/realtime-server/dist/index.cjs +46 -25
  100. package/realtime-server/dist/index.cjs.map +1 -1
  101. package/realtime-server/dist/index.d.cts +5 -5
  102. package/realtime-server/dist/index.d.ts +5 -5
  103. package/realtime-server/dist/index.js +38 -17
  104. package/realtime-server/dist/index.js.map +1 -1
  105. package/realtime-server/dist/metafile-cjs.json +1 -1
  106. package/realtime-server/dist/metafile-esm.json +1 -1
  107. package/realtime-server/src/hook-composition/expose-family.ts +7 -3
  108. package/realtime-server/src/hook-composition/expose-mutable-family.ts +13 -5
  109. package/realtime-server/src/hook-composition/expose-mutable.ts +11 -3
  110. package/realtime-server/src/hook-composition/expose-single.ts +6 -2
  111. package/realtime-server/src/hook-composition/receive-transaction.ts +14 -5
  112. package/src/subscribe.ts +37 -91
  113. package/src/transaction.ts +7 -2
  114. package/transceivers/set-rtx/dist/index.cjs.map +1 -1
  115. package/transceivers/set-rtx/dist/index.d.cts +2 -2
  116. package/transceivers/set-rtx/dist/index.d.ts +2 -2
  117. package/transceivers/set-rtx/dist/index.js.map +1 -1
  118. package/transceivers/set-rtx/dist/metafile-cjs.json +1 -1
  119. package/transceivers/set-rtx/dist/metafile-esm.json +1 -1
  120. package/transceivers/set-rtx/src/set-rtx.ts +3 -3
@@ -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`) {
@@ -1,7 +1,9 @@
1
+ import { newest } from "../lineage"
1
2
  import type { Store } from "../store"
2
3
 
3
4
  export const abortTransaction = (store: Store): void => {
4
- if (store.transactionStatus.phase === `idle`) {
5
+ const target = newest(store)
6
+ if (target.transactionMeta === null || target.parent === null) {
5
7
  store.logger.warn(
6
8
  `🐞`,
7
9
  `transaction`,
@@ -13,8 +15,8 @@ export const abortTransaction = (store: Store): void => {
13
15
  store.logger.info(
14
16
  `🪂`,
15
17
  `transaction`,
16
- store.transactionStatus.key,
18
+ target.transactionMeta.update.key,
17
19
  `Aborting transaction`,
18
20
  )
19
- store.transactionStatus = { phase: `idle` }
21
+ target.parent.child = null
20
22
  }
@@ -1,14 +1,67 @@
1
- import type { AtomToken, ƒn } from "atom.io"
2
- import { setState, transaction } from "atom.io"
1
+ import type { AtomToken, KeyedStateUpdate, TransactionUpdate, ƒn } from "atom.io"
2
+ import { setState } from "atom.io"
3
3
 
4
+ import { newest } from "../lineage"
4
5
  import { withdraw } from "../store"
5
6
  import type { Store } from "../store"
6
7
 
8
+ function ingestAtomUpdate(
9
+ update: KeyedStateUpdate<any>,
10
+ parent: Store,
11
+ child: Store,
12
+ ): void {
13
+ const { key, newValue } = update
14
+ const token: AtomToken<unknown> = { key, type: `atom` }
15
+ if (!parent.valueMap.has(token.key)) {
16
+ if (token.family) {
17
+ const family = parent.families.get(token.family.key)
18
+ if (family) {
19
+ family(token.family.subKey)
20
+ }
21
+ } else {
22
+ const newAtom = child.atoms.get(token.key)
23
+ if (!newAtom) {
24
+ throw new Error(
25
+ `Absurd Error: Atom "${token.key}" not found while copying updates from transaction "${child.transactionMeta?.update.key}" to store "${parent.config.name}"`,
26
+ )
27
+ }
28
+ parent.atoms.set(newAtom.key, newAtom)
29
+ parent.valueMap.set(newAtom.key, newAtom.default)
30
+ parent.logger.info(
31
+ `🔨`,
32
+ `transaction`,
33
+ child.transactionMeta?.update.key ?? `???`,
34
+ `Adding atom "${newAtom.key}"`,
35
+ )
36
+ }
37
+ }
38
+ setState(token, newValue, parent)
39
+ }
40
+ function ingestTransactionUpdate(
41
+ transactionUpdate: TransactionUpdate<any>,
42
+ parent: Store,
43
+ child: Store,
44
+ ): void {
45
+ for (const update of transactionUpdate.updates) {
46
+ if (`newValue` in update) {
47
+ ingestAtomUpdate(update, parent, child)
48
+ } else {
49
+ ingestTransactionUpdate(update, parent, child)
50
+ }
51
+ }
52
+ }
53
+
7
54
  export const applyTransaction = <ƒ extends ƒn>(
8
55
  output: ReturnType<ƒ>,
9
56
  store: Store,
10
57
  ): void => {
11
- if (store.transactionStatus.phase !== `building`) {
58
+ const child = newest(store)
59
+ const { parent } = child
60
+ if (
61
+ parent === null ||
62
+ child.transactionMeta === null ||
63
+ child.transactionMeta?.phase !== `building`
64
+ ) {
12
65
  store.logger.warn(
13
66
  `🐞`,
14
67
  `transaction`,
@@ -17,65 +70,34 @@ export const applyTransaction = <ƒ extends ƒn>(
17
70
  )
18
71
  return
19
72
  }
20
- store.transactionStatus.phase = `applying`
21
- store.transactionStatus.output = output
22
- const { atomUpdates } = store.transactionStatus
73
+ child.transactionMeta.phase = `applying`
74
+ child.transactionMeta.update.output = output
75
+ parent.child = null
76
+ parent.subject.transactionApplying.next(child.transactionMeta)
77
+ const { updates } = child.transactionMeta.update
23
78
  store.logger.info(
24
79
  `🛄`,
25
80
  `transaction`,
26
- store.transactionStatus.key,
27
- `Applying transaction with ${atomUpdates.length} updates:`,
28
- atomUpdates,
81
+ child.transactionMeta.update.key,
82
+ `Applying transaction with ${updates.length} updates:`,
83
+ updates,
29
84
  )
30
-
31
- for (const { key, newValue } of atomUpdates) {
32
- const token: AtomToken<unknown> = { key, type: `atom` }
33
- if (!store.valueMap.has(token.key)) {
34
- if (token.family) {
35
- const family = store.families.get(token.family.key)
36
- if (family) {
37
- family(token.family.subKey)
38
- }
39
- } else {
40
- const newAtom = store.transactionStatus.core.atoms.get(token.key)
41
- if (!newAtom) {
42
- throw new Error(
43
- `Absurd Error: Atom "${token.key}" not found while copying updates from transaction "${store.transactionStatus.key}" to store "${store.config.name}"`,
44
- )
45
- }
46
- store.atoms.set(newAtom.key, newAtom)
47
- store.valueMap.set(newAtom.key, newAtom.default)
48
- store.logger.info(
49
- `🔨`,
50
- `transaction`,
51
- store.transactionStatus.key,
52
- `Adding atom "${newAtom.key}"`,
53
- )
54
- }
55
- }
56
- // if (store.transactionStatus.key === `dealCards`) debugger
57
- setState(token, newValue, store)
58
- }
59
- const myTransaction = withdraw<ƒ>(
60
- { key: store.transactionStatus.key, type: `transaction` },
61
- store,
62
- )
63
- if (myTransaction === undefined) {
64
- throw new Error(
65
- `Transaction "${store.transactionStatus.key}" not found. Absurd. How is this running?`,
85
+ if (parent.transactionMeta === null) {
86
+ ingestTransactionUpdate(child.transactionMeta.update, parent, child)
87
+ const myTransaction = withdraw<ƒ>(
88
+ { key: child.transactionMeta.update.key, type: `transaction` },
89
+ store,
66
90
  )
91
+ myTransaction?.subject.next(child.transactionMeta.update)
92
+ store.logger.info(
93
+ `🛬`,
94
+ `transaction`,
95
+ child.transactionMeta.update.key,
96
+ `Finished applying transaction.`,
97
+ )
98
+ } else {
99
+ ingestTransactionUpdate(child.transactionMeta.update, parent, child)
100
+ parent.transactionMeta.update.updates.push(child.transactionMeta.update)
67
101
  }
68
- myTransaction.subject.next({
69
- key: store.transactionStatus.key,
70
- atomUpdates,
71
- output,
72
- params: store.transactionStatus.params as Parameters<ƒ>,
73
- })
74
- store.logger.info(
75
- `🛬`,
76
- `transaction`,
77
- store.transactionStatus.key,
78
- `Finished applying transaction.`,
79
- )
80
- store.transactionStatus = { phase: `idle` }
102
+ parent.subject.transactionApplying.next(null)
81
103
  }
@@ -1,6 +1,7 @@
1
1
  import { Junction } from "~/packages/rel8/junction/src"
2
2
 
3
3
  import { LazyMap } from "../lazy-map"
4
+ import { newest } from "../lineage"
4
5
  import type { Store } from "../store"
5
6
 
6
7
  export const buildTransaction = (
@@ -8,30 +9,39 @@ export const buildTransaction = (
8
9
  params: any[],
9
10
  store: Store,
10
11
  ): void => {
11
- store.transactionStatus = {
12
- key,
13
- phase: `building`,
14
- time: Date.now(),
15
- core: {
16
- atoms: new LazyMap(store.atoms),
17
- atomsThatAreDefault: new Set(store.atomsThatAreDefault),
18
- families: new LazyMap(store.families),
19
- operation: { open: false },
20
- readonlySelectors: new LazyMap(store.readonlySelectors),
21
- timelines: new LazyMap(store.timelines),
22
- timelineAtoms: new Junction(store.timelineAtoms.toJSON()),
23
- trackers: new Map(),
24
- transactions: new LazyMap(store.transactions),
25
- selectorAtoms: new Junction(store.selectorAtoms.toJSON()),
26
- selectorGraph: new Junction(store.selectorGraph.toJSON(), {
27
- makeContentKey: (...keys) => keys.sort().join(`:`),
28
- }),
29
- selectors: new LazyMap(store.selectors),
30
- valueMap: new LazyMap(store.valueMap),
12
+ const parent = newest(store)
13
+ parent.child = {
14
+ parent,
15
+ child: null,
16
+ subject: parent.subject,
17
+ loggers: parent.loggers,
18
+ logger: parent.logger,
19
+ config: parent.config,
20
+ transactionMeta: {
21
+ phase: `building`,
22
+ time: Date.now(),
23
+ update: {
24
+ key,
25
+ updates: [],
26
+ params,
27
+ output: undefined,
28
+ },
31
29
  },
32
- atomUpdates: [],
33
- params,
34
- output: undefined,
30
+ atoms: new LazyMap(parent.atoms),
31
+ atomsThatAreDefault: new Set(parent.atomsThatAreDefault),
32
+ families: new LazyMap(parent.families),
33
+ operation: { open: false },
34
+ readonlySelectors: new LazyMap(parent.readonlySelectors),
35
+ timelines: new LazyMap(parent.timelines),
36
+ timelineAtoms: new Junction(parent.timelineAtoms.toJSON()),
37
+ trackers: new Map(),
38
+ transactions: new LazyMap(parent.transactions),
39
+ selectorAtoms: new Junction(parent.selectorAtoms.toJSON()),
40
+ selectorGraph: new Junction(parent.selectorGraph.toJSON(), {
41
+ makeContentKey: (...keys) => keys.sort().join(`:`),
42
+ }),
43
+ selectors: new LazyMap(parent.selectors),
44
+ valueMap: new LazyMap(parent.valueMap),
35
45
  }
36
46
  store.logger.info(
37
47
  `🛫`,
@@ -4,10 +4,11 @@ import type {
4
4
  TransactionUpdate,
5
5
  ƒn,
6
6
  } from "atom.io"
7
- import { getState, setState } from "atom.io"
7
+ import { getState, runTransaction, setState } from "atom.io"
8
8
 
9
+ import { newest } from "../lineage"
9
10
  import { deposit } from "../store"
10
- import type { Store, StoreCore } from "../store"
11
+ import type { Store } from "../store"
11
12
  import { Subject } from "../subject"
12
13
  import { abortTransaction } from "./abort-transaction"
13
14
  import { applyTransaction } from "./apply-transaction"
@@ -35,6 +36,7 @@ export function createTransaction<ƒ extends ƒn>(
35
36
  {
36
37
  get: (token) => getState(token, store),
37
38
  set: (token, value) => setState(token, value, store),
39
+ run: (token) => runTransaction(token, store),
38
40
  },
39
41
  ...params,
40
42
  )
@@ -49,14 +51,9 @@ export function createTransaction<ƒ extends ƒn>(
49
51
  install: (store) => createTransaction(options, store),
50
52
  subject: new Subject(),
51
53
  }
52
- const core = target(store)
53
- core.transactions.set(newTransaction.key, newTransaction)
54
+ const target = newest(store)
55
+ target.transactions.set(newTransaction.key, newTransaction)
54
56
  const token = deposit(newTransaction)
55
57
  store.subject.transactionCreation.next(token)
56
58
  return token
57
59
  }
58
-
59
- export const target = (store: Store): StoreCore =>
60
- store.transactionStatus.phase === `building`
61
- ? store.transactionStatus.core
62
- : store
@@ -1,7 +1,5 @@
1
1
  import type { TransactionUpdate, ƒn } from "atom.io"
2
2
 
3
- import type { StoreCore } from ".."
4
-
5
3
  export * from "./abort-transaction"
6
4
  export * from "./apply-transaction"
7
5
  export * from "./build-transaction"
@@ -12,14 +10,8 @@ export * from "./undo-transaction"
12
10
  export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
13
11
  export type TransactionPhase = (typeof TRANSACTION_PHASES)[number]
14
12
 
15
- export type TransactionUpdateInProgress<ƒ extends ƒn> = TransactionUpdate<ƒ> & {
13
+ export type TransactionMeta<ƒ extends ƒn> = {
16
14
  phase: `applying` | `building`
17
15
  time: number
18
- core: StoreCore
19
- }
20
- export type TransactionIdle = {
21
- phase: `idle`
16
+ update: TransactionUpdate<ƒ>
22
17
  }
23
- export type TransactionStatus<ƒ extends ƒn> =
24
- | TransactionIdle
25
- | TransactionUpdateInProgress<ƒ>
@@ -5,18 +5,23 @@ import { withdraw } from "../store"
5
5
  import type { Store } from "../store"
6
6
 
7
7
  export const redoTransactionUpdate = <ƒ extends ƒn>(
8
- update: TransactionUpdate<ƒ>,
8
+ transactionUpdate: TransactionUpdate<ƒ>,
9
9
  store: Store,
10
10
  ): void => {
11
- store.logger.info(`⏭️`, `transaction`, update.key, `Redo`)
12
- for (const { key, newValue } of update.atomUpdates) {
13
- const token: AtomToken<unknown> = { key, type: `atom` }
14
- const state = withdraw(token, store)
15
- if (state === undefined) {
16
- throw new Error(
17
- `State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
18
- )
11
+ store.logger.info(`⏭️`, `transaction`, transactionUpdate.key, `Redo`)
12
+ for (const update of transactionUpdate.updates) {
13
+ if (`newValue` in update) {
14
+ const { key, newValue } = update
15
+ const token: AtomToken<unknown> = { key, type: `atom` }
16
+ const state = withdraw(token, store)
17
+ if (state === undefined) {
18
+ throw new Error(
19
+ `State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
20
+ )
21
+ }
22
+ setState(state, newValue, store)
23
+ } else {
24
+ redoTransactionUpdate(update, store)
19
25
  }
20
- setState(state, newValue, store)
21
26
  }
22
27
  }
@@ -5,24 +5,23 @@ import { withdraw } from "../store"
5
5
  import type { Store } from "../store"
6
6
 
7
7
  export const undoTransactionUpdate = <ƒ extends ƒn>(
8
- update: TransactionUpdate<ƒ>,
8
+ transactionUpdate: TransactionUpdate<ƒ>,
9
9
  store: Store,
10
10
  ): void => {
11
- store.logger.info(
12
- `⏮️`,
13
- `transaction`,
14
- update.key,
15
- `Undoing transaction update`,
16
- update,
17
- )
18
- for (const { key, oldValue } of update.atomUpdates) {
19
- const token: AtomToken<unknown> = { key, type: `atom` }
20
- const state = withdraw(token, store)
21
- if (state === undefined) {
22
- throw new Error(
23
- `State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
24
- )
11
+ store.logger.info(`⏮️`, `transaction`, transactionUpdate.key, `Undo`)
12
+ for (const update of transactionUpdate.updates.reverse()) {
13
+ if (`newValue` in update) {
14
+ const { key, newValue } = update
15
+ const token: AtomToken<unknown> = { key, type: `atom` }
16
+ const state = withdraw(token, store)
17
+ if (state === undefined) {
18
+ throw new Error(
19
+ `State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
20
+ )
21
+ }
22
+ setState(state, newValue, store)
23
+ } else {
24
+ undoTransactionUpdate(update, store)
25
25
  }
26
- setState(state, oldValue, store)
27
26
  }
28
27
  }
@@ -81,7 +81,7 @@ var attachAtomIndex = (store = Internal.IMPLICIT.STORE) => {
81
81
  [key]: atomToken
82
82
  });
83
83
  });
84
- if (Internal.target(store).operation.open) {
84
+ if (Internal.newest(store).operation.open) {
85
85
  const unsubscribe = store.subject.operationStatus.subscribe(
86
86
  `introspection: waiting to update atom index`,
87
87
  () => {
@@ -153,7 +153,7 @@ var attachSelectorIndex = (store = Internal.IMPLICIT.STORE) => {
153
153
  [key]: selectorToken
154
154
  });
155
155
  });
156
- if (Internal.target(store).operation.open) {
156
+ if (Internal.newest(store).operation.open) {
157
157
  const unsubscribe = store.subject.operationStatus.subscribe(
158
158
  `introspection: waiting to update selector index`,
159
159
  () => {