atom.io 0.14.8 → 0.15.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 (76) hide show
  1. package/README.md +5 -0
  2. package/data/dist/index.cjs +200 -218
  3. package/data/dist/index.cjs.map +1 -1
  4. package/data/dist/index.d.ts +16 -7
  5. package/data/dist/index.js +202 -221
  6. package/data/dist/index.js.map +1 -1
  7. package/data/src/join.ts +295 -292
  8. package/data/src/struct-family.ts +2 -2
  9. package/data/src/struct.ts +2 -2
  10. package/dist/chunk-S7R5MU6A.js +137 -0
  11. package/dist/chunk-S7R5MU6A.js.map +1 -0
  12. package/dist/index.cjs +3 -20
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +15 -8
  15. package/dist/index.js +1 -151
  16. package/dist/index.js.map +1 -1
  17. package/internal/dist/index.cjs +275 -200
  18. package/internal/dist/index.cjs.map +1 -1
  19. package/internal/dist/index.d.ts +43 -36
  20. package/internal/dist/index.js +221 -193
  21. package/internal/dist/index.js.map +1 -1
  22. package/internal/src/atom/create-atom.ts +5 -86
  23. package/internal/src/atom/create-regular-atom.ts +92 -0
  24. package/internal/src/atom/index.ts +16 -0
  25. package/internal/src/atom/is-default.ts +0 -5
  26. package/internal/src/caching.ts +14 -16
  27. package/internal/src/families/create-atom-family.ts +20 -46
  28. package/internal/src/families/create-readonly-selector-family.ts +1 -0
  29. package/internal/src/families/create-regular-atom-family.ts +72 -0
  30. package/internal/src/families/create-selector-family.ts +2 -0
  31. package/internal/src/families/index.ts +1 -0
  32. package/internal/src/mutable/create-mutable-atom-family.ts +2 -2
  33. package/internal/src/mutable/create-mutable-atom.ts +8 -3
  34. package/internal/src/mutable/get-update-family.ts +1 -1
  35. package/internal/src/mutable/is-mutable.ts +3 -30
  36. package/internal/src/mutable/tracker-family.ts +2 -2
  37. package/internal/src/mutable/tracker.ts +5 -5
  38. package/internal/src/operation.ts +14 -18
  39. package/internal/src/selector/create-read-write-selector.ts +2 -3
  40. package/internal/src/selector/create-selector.ts +1 -1
  41. package/internal/src/selector/register-selector.ts +9 -14
  42. package/internal/src/set-state/evict-downstream.ts +3 -5
  43. package/internal/src/set-state/set-atom.ts +14 -17
  44. package/internal/src/store/store.ts +23 -19
  45. package/internal/src/store/withdraw.ts +32 -70
  46. package/internal/src/subscribe/subscribe-to-root-atoms.ts +5 -3
  47. package/internal/src/subscribe/subscribe-to-state.ts +5 -3
  48. package/internal/src/transaction/apply-transaction.ts +20 -2
  49. package/internal/src/transaction/build-transaction.ts +19 -11
  50. package/internal/src/transaction/create-transaction.ts +6 -11
  51. package/internal/src/transaction/index.ts +2 -3
  52. package/introspection/dist/index.cjs +6 -6
  53. package/introspection/dist/index.cjs.map +1 -1
  54. package/introspection/dist/index.d.ts +3 -3
  55. package/introspection/dist/index.js +7 -7
  56. package/introspection/dist/index.js.map +1 -1
  57. package/introspection/src/attach-atom-index.ts +7 -2
  58. package/introspection/src/attach-selector-index.ts +7 -2
  59. package/introspection/src/attach-timeline-family.ts +5 -2
  60. package/introspection/src/attach-timeline-index.ts +2 -2
  61. package/introspection/src/attach-transaction-index.ts +2 -2
  62. package/introspection/src/attach-transaction-logs.ts +2 -2
  63. package/package.json +10 -8
  64. package/react-devtools/dist/index.d.ts +17 -11
  65. package/src/atom.ts +8 -17
  66. package/src/selector.ts +3 -1
  67. package/src/set-state.ts +1 -3
  68. package/src/silo.ts +2 -14
  69. package/src/transaction.ts +17 -6
  70. package/transceivers/set-rtx/dist/index.cjs +2 -1
  71. package/transceivers/set-rtx/dist/index.cjs.map +1 -1
  72. package/transceivers/set-rtx/dist/index.js +2 -1
  73. package/transceivers/set-rtx/dist/index.js.map +1 -1
  74. package/transceivers/set-rtx/src/set-rtx.ts +2 -1
  75. package/internal/src/transaction/redo-transaction.ts +0 -27
  76. package/internal/src/transaction/undo-transaction.ts +0 -27
@@ -19,17 +19,16 @@ export const openOperation = (
19
19
  token: StateToken<any>,
20
20
  store: Store,
21
21
  ): `rejection` | undefined => {
22
- const target = newest(store)
23
- if (target.operation.open) {
22
+ if (store.operation.open) {
24
23
  store.logger.error(
25
24
  `❌`,
26
25
  token.type,
27
26
  token.key,
28
- `failed to setState during a setState for "${target.operation.token.key}"`,
27
+ `failed to setState during a setState for "${store.operation.token.key}"`,
29
28
  )
30
29
  return `rejection`
31
30
  }
32
- target.operation = {
31
+ store.operation = {
33
32
  open: true,
34
33
  done: new Set(),
35
34
  prev: new Map(),
@@ -41,29 +40,27 @@ export const openOperation = (
41
40
  token.type,
42
41
  token.key,
43
42
  `operation start in store "${store.config.name}"${
44
- target.transactionMeta === null
43
+ store.transactionMeta === null
45
44
  ? ``
46
- : ` ${target.transactionMeta.phase} "${target.transactionMeta.update.key}"`
45
+ : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`
47
46
  }`,
48
47
  )
49
48
  }
50
49
  export const closeOperation = (store: Store): void => {
51
- const target = newest(store)
52
- if (target.operation.open) {
50
+ if (store.operation.open) {
53
51
  store.logger.info(
54
52
  `🔴`,
55
- target.operation.token.type,
56
- target.operation.token.key,
53
+ store.operation.token.type,
54
+ store.operation.token.key,
57
55
  `operation done in store "${store.config.name}"`,
58
56
  )
59
57
  }
60
- target.operation = { open: false }
61
- store.subject.operationStatus.next(target.operation)
58
+ store.operation = { open: false }
59
+ store.subject.operationStatus.next(store.operation)
62
60
  }
63
61
 
64
62
  export const isDone = (key: string, store: Store): boolean => {
65
- const target = newest(store)
66
- if (!target.operation.open) {
63
+ if (!store.operation.open) {
67
64
  store.logger.warn(
68
65
  `🐞`,
69
66
  `unknown`,
@@ -72,11 +69,10 @@ export const isDone = (key: string, store: Store): boolean => {
72
69
  )
73
70
  return true
74
71
  }
75
- return target.operation.done.has(key)
72
+ return store.operation.done.has(key)
76
73
  }
77
74
  export const markDone = (key: string, store: Store): void => {
78
- const target = newest(store)
79
- if (!target.operation.open) {
75
+ if (!store.operation.open) {
80
76
  store.logger.warn(
81
77
  `🐞`,
82
78
  `unknown`,
@@ -85,5 +81,5 @@ export const markDone = (key: string, store: Store): void => {
85
81
  )
86
82
  return
87
83
  }
88
- target.operation.done.add(key)
84
+ store.operation.done.add(key)
89
85
  }
@@ -21,14 +21,13 @@ export const createReadWriteSelector = <T>(
21
21
  const { get, set } = registerSelector(options.key, store)
22
22
  const getSelf = () => {
23
23
  const value = options.get({ get })
24
- cacheValue(options.key, value, subject, store)
24
+ cacheValue(options.key, value, subject, newest(store))
25
25
  return value
26
26
  }
27
27
 
28
28
  const setSelf = (next: T | ((oldValue: T) => T)): void => {
29
29
  const oldValue = getSelf()
30
30
  const newValue = become(next)(oldValue)
31
- // store.logger.info(`📝 set "${options.key}" (`, oldValue, `->`, newValue, `)`)
32
31
  store.logger.info(
33
32
  `📝`,
34
33
  `selector`,
@@ -55,7 +54,7 @@ export const createReadWriteSelector = <T>(
55
54
  type: `selector`,
56
55
  ...(family && { family }),
57
56
  }
58
- target.selectors.set(options.key, mySelector) // ❓
57
+ target.selectors.set(options.key, mySelector)
59
58
  const initialValue = getSelf()
60
59
  store.logger.info(`✨`, mySelector.type, mySelector.key, `=`, initialValue)
61
60
  const token: SelectorToken<T> = {
@@ -54,7 +54,7 @@ export function createSelector<T>(
54
54
  `❌`,
55
55
  existingReadonly ? `readonly_selector` : `selector`,
56
56
  options.key,
57
- `Tried to create selector, but it already exists in the store. (Ignore if you are in development using hot module replacement.)`,
57
+ `Tried to create selector, but it already exists in the store.`,
58
58
  )
59
59
  }
60
60
 
@@ -13,9 +13,6 @@ export const registerSelector = (
13
13
  ): Transactors => ({
14
14
  get: (dependency) => {
15
15
  const target = newest(store)
16
- const alreadyRegistered = target.selectorGraph
17
- .getRelationEntries({ downstreamSelectorKey: selectorKey })
18
- .some(([_, { source }]) => source === dependency.key)
19
16
 
20
17
  const dependencyState = withdraw(dependency, store)
21
18
  if (dependencyState === undefined) {
@@ -34,17 +31,15 @@ export const registerSelector = (
34
31
  `)`,
35
32
  )
36
33
 
37
- if (!alreadyRegistered) {
38
- target.selectorGraph.set(
39
- {
40
- upstreamSelectorKey: dependency.key,
41
- downstreamSelectorKey: selectorKey,
42
- },
43
- {
44
- source: dependency.key,
45
- },
46
- )
47
- }
34
+ target.selectorGraph.set(
35
+ {
36
+ upstreamSelectorKey: dependency.key,
37
+ downstreamSelectorKey: selectorKey,
38
+ },
39
+ {
40
+ source: dependency.key,
41
+ },
42
+ )
48
43
  updateSelectorAtoms(selectorKey, dependency, store)
49
44
  return dependencyValue
50
45
  },
@@ -1,12 +1,10 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { evictCachedValue } from "../caching"
3
- import { newest } from "../lineage"
4
3
  import { isDone, markDone } from "../operation"
5
4
  import type { Store } from "../store"
6
5
 
7
6
  export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
8
- const target = newest(store)
9
- const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key)
7
+ const downstreamKeys = store.selectorAtoms.getRelatedKeys(atom.key)
10
8
  store.logger.info(
11
9
  `🧹`,
12
10
  atom.type,
@@ -17,12 +15,12 @@ export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
17
15
  downstreamKeys ?? `to evict`,
18
16
  )
19
17
  if (downstreamKeys) {
20
- if (target.operation.open) {
18
+ if (store.operation.open) {
21
19
  store.logger.info(
22
20
  `🧹`,
23
21
  atom.type,
24
22
  atom.key,
25
- `[ ${[...target.operation.done].join(`, `)} ] already done`,
23
+ `[ ${[...store.operation.done].join(`, `)} ] already done`,
26
24
  )
27
25
  }
28
26
  for (const key of downstreamKeys) {
@@ -1,7 +1,6 @@
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"
5
4
  import { markDone } from "../operation"
6
5
  import { readOrComputeValue } from "../read-or-compute-value"
7
6
  import type { Store } from "../store"
@@ -14,26 +13,24 @@ import { stowUpdate } from "./stow-update"
14
13
  export const setAtom = <T>(
15
14
  atom: Atom<T>,
16
15
  next: T | ((oldValue: T) => T),
17
- store: Store,
16
+ target: Store,
18
17
  ): void => {
19
- const target = newest(store)
20
- const oldValue = readOrComputeValue(atom, store)
21
- let newValue = copyMutableIfWithinTransaction(oldValue, atom, store)
18
+ const oldValue = readOrComputeValue(atom, target)
19
+ let newValue = copyMutableIfWithinTransaction(oldValue, atom, target)
22
20
  newValue = become(next)(newValue)
23
- store.logger.info(`📝`, `atom`, atom.key, `set to`, newValue)
24
- newValue = cacheValue(atom.key, newValue, atom.subject, store)
25
- if (isAtomDefault(atom.key, store)) {
26
- markAtomAsNotDefault(atom.key, store)
21
+ target.logger.info(`📝`, `atom`, atom.key, `set to`, newValue)
22
+ newValue = cacheValue(atom.key, newValue, atom.subject, target)
23
+ if (isAtomDefault(atom.key, target)) {
24
+ markAtomAsNotDefault(atom.key, target)
27
25
  }
28
- markDone(atom.key, store)
29
- evictDownStream(atom, store)
26
+ markDone(atom.key, target)
27
+ evictDownStream(atom, target)
30
28
  const update = { oldValue, newValue }
31
- if (
32
- target.transactionMeta === null ||
33
- target.transactionMeta.phase === `applying`
34
- ) {
35
- emitUpdate(atom, update, store)
29
+ if (target.transactionMeta === null) {
30
+ emitUpdate(atom, update, target)
31
+ } else if (target.transactionMeta.phase === `applying` && target.parent) {
32
+ emitUpdate(atom, update, target.parent)
36
33
  } else {
37
- stowUpdate(atom, update, store)
34
+ stowUpdate(atom, update, target)
38
35
  }
39
36
  }
@@ -16,30 +16,19 @@ import { Junction } from "~/packages/rel8/junction/src"
16
16
 
17
17
  import type { Atom } from "../atom"
18
18
  import type { Lineage } from "../lineage"
19
- import type { MutableAtom, Tracker, Transceiver } from "../mutable"
19
+ import {
20
+ type MutableAtom,
21
+ type Tracker,
22
+ type Transceiver,
23
+ getJsonToken,
24
+ getUpdateToken,
25
+ } from "../mutable"
20
26
  import type { OperationProgress } from "../operation"
21
27
  import type { ReadonlySelector, Selector } from "../selector"
22
28
  import { StatefulSubject, Subject } from "../subject"
23
29
  import type { Timeline } from "../timeline"
24
30
  import type { Transaction, TransactionMeta } from "../transaction"
25
31
 
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
32
  export class Store implements Lineage {
44
33
  public parent: Store | null = null
45
34
  public child: Store | null = null
@@ -130,14 +119,29 @@ export class Store implements Lineage {
130
119
  ...store?.config,
131
120
  name,
132
121
  }
133
-
122
+ for (const [, family] of store.families) {
123
+ family.install(this)
124
+ }
125
+ const mutableHelpers = new Set<string>()
134
126
  for (const [, atom] of store.atoms) {
127
+ if (mutableHelpers.has(atom.key)) {
128
+ continue
129
+ }
135
130
  atom.install(this)
131
+ if (`mutable` in atom) {
132
+ const originalJsonToken = getJsonToken(atom)
133
+ const originalUpdateToken = getUpdateToken(atom)
134
+ mutableHelpers.add(originalJsonToken.key)
135
+ mutableHelpers.add(originalUpdateToken.key)
136
+ }
136
137
  }
137
138
  for (const [, selector] of store.readonlySelectors) {
138
139
  selector.install(this)
139
140
  }
140
141
  for (const [, selector] of store.selectors) {
142
+ if (mutableHelpers.has(selector.key)) {
143
+ continue
144
+ }
141
145
  selector.install(this)
142
146
  }
143
147
  for (const [, tx] of store.transactions) {
@@ -9,12 +9,18 @@ import type {
9
9
  } from "atom.io"
10
10
 
11
11
  import type { Atom } from "../atom"
12
- import { newest } from "../lineage"
13
12
  import type { ReadonlySelector, Selector } from "../selector"
14
13
  import type { Timeline } from "../timeline"
15
14
  import type { Transaction } from "../transaction"
16
15
  import type { Store } from "./store"
17
16
 
17
+ type Withdrawable<T> =
18
+ | Atom<T>
19
+ | ReadonlySelector<T>
20
+ | Selector<T>
21
+ | Timeline
22
+ | Transaction<T extends ƒn ? T : never>
23
+
18
24
  export function withdraw<T>(
19
25
  token: AtomToken<T>,
20
26
  store: Store,
@@ -50,74 +56,30 @@ export function withdraw<T>(
50
56
  | TimelineToken
51
57
  | TransactionToken<T>,
52
58
  store: Store,
53
- ):
54
- | Atom<T>
55
- | ReadonlySelector<T>
56
- | Selector<T>
57
- | Timeline
58
- | Transaction<T extends ƒn ? T : never>
59
- | undefined {
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)
67
- if (state) {
68
- return state
59
+ ): Withdrawable<T> | undefined {
60
+ let withdrawn: Withdrawable<T> | undefined
61
+ let target: Store | null = store
62
+ while (target !== null) {
63
+ switch (token.type) {
64
+ case `atom`:
65
+ withdrawn = target.atoms.get(token.key)
66
+ break
67
+ case `selector`:
68
+ withdrawn = target.selectors.get(token.key)
69
+ break
70
+ case `readonly_selector`:
71
+ withdrawn = target.readonlySelectors.get(token.key)
72
+ break
73
+ case `timeline`:
74
+ withdrawn = target.timelines.get(token.key)
75
+ break
76
+ case `transaction`:
77
+ withdrawn = target.transactions.get(token.key)
78
+ break
79
+ }
80
+ if (withdrawn) {
81
+ return withdrawn
82
+ }
83
+ target = target.child
69
84
  }
70
- // if (target.transactionMeta?.phase === `applying`) {
71
-
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)
78
-
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
- // }
122
- return undefined
123
85
  }
@@ -1,3 +1,4 @@
1
+ import { newest } from "../lineage"
1
2
  import { readOrComputeValue } from "../read-or-compute-value"
2
3
  import type { ReadonlySelector, Selector } from "../selector"
3
4
  import { traceAllSelectorAtoms } from "../selector"
@@ -8,11 +9,12 @@ export const subscribeToRootAtoms = <T>(
8
9
  state: ReadonlySelector<T> | Selector<T>,
9
10
  store: Store,
10
11
  ): (() => void)[] | null => {
12
+ const target = newest(store)
11
13
  const dependencySubscriptions =
12
14
  `default` in state
13
15
  ? null
14
16
  : traceAllSelectorAtoms(state.key, store).map((atomKey) => {
15
- const atom = store.atoms.get(atomKey)
17
+ const atom = target.atoms.get(atomKey)
16
18
  if (atom === undefined) {
17
19
  throw new Error(
18
20
  `Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`,
@@ -32,9 +34,9 @@ export const subscribeToRootAtoms = <T>(
32
34
  `->`,
33
35
  atomChange.newValue,
34
36
  )
35
- const oldValue = recallState(state, store)
37
+ const oldValue = recallState(state, target)
36
38
  // ❌ this retrieves a stale cached value when applying a transaction on the server
37
- const newValue = readOrComputeValue(state, store)
39
+ const newValue = readOrComputeValue(state, target)
38
40
  store.logger.info(
39
41
  `✨`,
40
42
  state.type,
@@ -1,6 +1,7 @@
1
1
  import type { ReadonlySelectorToken, StateToken, UpdateHandler } from "atom.io"
2
- import type { Store } from "atom.io/internal"
3
- import { subscribeToRootAtoms, withdraw } from "atom.io/internal"
2
+ import type { Store } from "../store"
3
+ import { withdraw, withdrawNewFamilyMember } from "../store"
4
+ import { subscribeToRootAtoms } from "./subscribe-to-root-atoms"
4
5
 
5
6
  export function subscribeToState<T>(
6
7
  token: ReadonlySelectorToken<T> | StateToken<T>,
@@ -8,7 +9,8 @@ export function subscribeToState<T>(
8
9
  key: string,
9
10
  store: Store,
10
11
  ): () => void {
11
- const state = withdraw<T>(token, store)
12
+ const state =
13
+ withdraw<T>(token, store) ?? withdrawNewFamilyMember(token, store)
12
14
  if (state === undefined) {
13
15
  throw new Error(
14
16
  `State "${token.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
@@ -82,8 +82,27 @@ export const applyTransaction = <ƒ extends ƒn>(
82
82
  `Applying transaction with ${updates.length} updates:`,
83
83
  updates,
84
84
  )
85
+ for (const tracker of child.trackers.values()) {
86
+ const mutableKey = tracker.mutableState.key
87
+ if (!parent.atoms.has(mutableKey)) {
88
+ const atom = child.atoms.get(mutableKey)
89
+ atom?.install(parent)
90
+ }
91
+ }
92
+ for (const atom of child.atoms.values()) {
93
+ if (!parent.atoms.has(atom.key)) {
94
+ parent.atoms.set(atom.key, atom)
95
+ parent.valueMap.set(atom.key, atom.default)
96
+ parent.logger.info(
97
+ `🔨`,
98
+ `transaction`,
99
+ child.transactionMeta.update.key,
100
+ `Adding atom "${atom.key}"`,
101
+ )
102
+ }
103
+ }
104
+ ingestTransactionUpdate(child.transactionMeta.update, parent, child)
85
105
  if (parent.transactionMeta === null) {
86
- ingestTransactionUpdate(child.transactionMeta.update, parent, child)
87
106
  const myTransaction = withdraw<ƒ>(
88
107
  { key: child.transactionMeta.update.key, type: `transaction` },
89
108
  store,
@@ -96,7 +115,6 @@ export const applyTransaction = <ƒ extends ƒn>(
96
115
  `Finished applying transaction.`,
97
116
  )
98
117
  } else {
99
- ingestTransactionUpdate(child.transactionMeta.update, parent, child)
100
118
  parent.transactionMeta.update.updates.push(child.transactionMeta.update)
101
119
  }
102
120
  parent.subject.transactionApplying.next(null)
@@ -1,5 +1,6 @@
1
1
  import { Junction } from "~/packages/rel8/junction/src"
2
2
 
3
+ import { getState, runTransaction, setState } from "~/packages/atom.io/src"
3
4
  import { LazyMap } from "../lazy-map"
4
5
  import { newest } from "../lineage"
5
6
  import type { Store } from "../store"
@@ -10,23 +11,14 @@ export const buildTransaction = (
10
11
  store: Store,
11
12
  ): void => {
12
13
  const parent = newest(store)
13
- parent.child = {
14
+ const child: Store = {
14
15
  parent,
15
16
  child: null,
16
17
  subject: parent.subject,
17
18
  loggers: parent.loggers,
18
19
  logger: parent.logger,
19
20
  config: parent.config,
20
- transactionMeta: {
21
- phase: `building`,
22
- time: Date.now(),
23
- update: {
24
- key,
25
- updates: [],
26
- params,
27
- output: undefined,
28
- },
29
- },
21
+ transactionMeta: null,
30
22
  atoms: new LazyMap(parent.atoms),
31
23
  atomsThatAreDefault: new Set(parent.atomsThatAreDefault),
32
24
  families: new LazyMap(parent.families),
@@ -43,6 +35,22 @@ export const buildTransaction = (
43
35
  selectors: new LazyMap(parent.selectors),
44
36
  valueMap: new LazyMap(parent.valueMap),
45
37
  }
38
+ child.transactionMeta = {
39
+ phase: `building`,
40
+ time: Date.now(),
41
+ update: {
42
+ key,
43
+ updates: [],
44
+ params,
45
+ output: undefined,
46
+ },
47
+ transactors: {
48
+ get: (token) => getState(token, child),
49
+ set: (token, value) => setState(token, value, child),
50
+ run: (token) => runTransaction(token, child),
51
+ },
52
+ }
53
+ parent.child = child
46
54
  store.logger.info(
47
55
  `🛫`,
48
56
  `transaction`,
@@ -4,7 +4,6 @@ import type {
4
4
  TransactionUpdate,
5
5
  ƒn,
6
6
  } from "atom.io"
7
- import { getState, runTransaction, setState } from "atom.io"
8
7
 
9
8
  import { newest } from "../lineage"
10
9
  import { deposit } from "../store"
@@ -32,18 +31,14 @@ export function createTransaction<ƒ extends ƒn>(
32
31
  run: (...params: Parameters<ƒ>) => {
33
32
  buildTransaction(options.key, params, store)
34
33
  try {
35
- const output = options.do(
36
- {
37
- get: (token) => getState(token, store),
38
- set: (token, value) => setState(token, value, store),
39
- run: (token) => runTransaction(token, store),
40
- },
41
- ...params,
42
- )
43
- applyTransaction(output, store)
34
+ const target = newest(store)
35
+ // biome-ignore lint/style/noNonNullAssertion: this happens right above
36
+ const { transactors } = target.transactionMeta!
37
+ const output = options.do(transactors, ...params)
38
+ applyTransaction(output, target)
44
39
  return output
45
40
  } catch (thrown) {
46
- abortTransaction(store)
41
+ abortTransaction(target)
47
42
  store.logger.warn(`💥`, `transaction`, options.key, `caught:`, thrown)
48
43
  throw thrown
49
44
  }
@@ -1,11 +1,9 @@
1
- import type { TransactionUpdate, ƒn } from "atom.io"
1
+ import type { TransactionUpdate, TransactorsWithRun, ƒn } from "atom.io"
2
2
 
3
3
  export * from "./abort-transaction"
4
4
  export * from "./apply-transaction"
5
5
  export * from "./build-transaction"
6
6
  export * from "./create-transaction"
7
- export * from "./redo-transaction"
8
- export * from "./undo-transaction"
9
7
 
10
8
  export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
11
9
  export type TransactionPhase = (typeof TRANSACTION_PHASES)[number]
@@ -14,4 +12,5 @@ export type TransactionMeta<ƒ extends ƒn> = {
14
12
  phase: `applying` | `building`
15
13
  time: number
16
14
  update: TransactionUpdate<ƒ>
15
+ transactors: TransactorsWithRun
17
16
  }
@@ -42,7 +42,7 @@ var __spreadValues = (a, b) => {
42
42
  };
43
43
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
44
44
  var attachAtomIndex = (store = Internal.IMPLICIT.STORE) => {
45
- const atomTokenIndexState__INTERNAL = Internal.createAtom(
45
+ const atomTokenIndexState__INTERNAL = Internal.createRegularAtom(
46
46
  {
47
47
  key: `\u{1F441}\u200D\u{1F5E8} Atom Token Index (Internal)`,
48
48
  default: () => {
@@ -109,7 +109,7 @@ var attachAtomIndex = (store = Internal.IMPLICIT.STORE) => {
109
109
  );
110
110
  };
111
111
  var attachSelectorIndex = (store = Internal.IMPLICIT.STORE) => {
112
- const readonlySelectorTokenIndexState__INTERNAL = Internal.createAtom(
112
+ const readonlySelectorTokenIndexState__INTERNAL = Internal.createRegularAtom(
113
113
  {
114
114
  key: `\u{1F441}\u200D\u{1F5E8} Selector Token Index (Internal)`,
115
115
  default: () => Object.assign(
@@ -182,7 +182,7 @@ var attachSelectorIndex = (store = Internal.IMPLICIT.STORE) => {
182
182
  );
183
183
  };
184
184
  var attachTimelineFamily = (store = Internal.IMPLICIT.STORE) => {
185
- const findTimelineLogState__INTERNAL = Internal.createAtomFamily(
185
+ const findTimelineLogState__INTERNAL = Internal.createRegularAtomFamily(
186
186
  {
187
187
  key: `\u{1F441}\u200D\u{1F5E8} Timeline Update Log (Internal)`,
188
188
  default: (key) => {
@@ -233,7 +233,7 @@ var attachTimelineFamily = (store = Internal.IMPLICIT.STORE) => {
233
233
  return findTimelineLogState;
234
234
  };
235
235
  var attachTimelineIndex = (store = Internal.IMPLICIT.STORE) => {
236
- const timelineTokenIndexState__INTERNAL = Internal.createAtom(
236
+ const timelineTokenIndexState__INTERNAL = Internal.createRegularAtom(
237
237
  {
238
238
  key: `\u{1F441}\u200D\u{1F5E8} Timeline Token Index (Internal)`,
239
239
  default: () => [...store.timelines].map(([key]) => {
@@ -264,7 +264,7 @@ var attachTimelineIndex = (store = Internal.IMPLICIT.STORE) => {
264
264
  return timelineTokenIndex;
265
265
  };
266
266
  var attachTransactionIndex = (store = Internal.IMPLICIT.STORE) => {
267
- const transactionTokenIndexState__INTERNAL = Internal.createAtom(
267
+ const transactionTokenIndexState__INTERNAL = Internal.createRegularAtom(
268
268
  {
269
269
  key: `\u{1F441}\u200D\u{1F5E8} Transaction Token Index (Internal)`,
270
270
  default: () => [...store.transactions].map(([key]) => {
@@ -295,7 +295,7 @@ var attachTransactionIndex = (store = Internal.IMPLICIT.STORE) => {
295
295
  return transactionTokenIndex;
296
296
  };
297
297
  var attachTransactionLogs = (store = Internal.IMPLICIT.STORE) => {
298
- const findTransactionUpdateLog = Internal.createAtomFamily(
298
+ const findTransactionUpdateLog = Internal.createRegularAtomFamily(
299
299
  {
300
300
  key: `\u{1F441}\u200D\u{1F5E8} Transaction Update Log (Internal)`,
301
301
  default: () => [],