atom.io 0.16.2 → 0.17.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 (108) hide show
  1. package/dist/chunk-H4Q5FTPZ.js +11 -0
  2. package/dist/chunk-H4Q5FTPZ.js.map +1 -0
  3. package/dist/index.cjs +35 -60
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +8 -8
  6. package/dist/index.js +12 -36
  7. package/dist/index.js.map +1 -1
  8. package/internal/dist/index.cjs +268 -195
  9. package/internal/dist/index.cjs.map +1 -1
  10. package/internal/dist/index.d.ts +36 -11
  11. package/internal/dist/index.js +258 -195
  12. package/internal/dist/index.js.map +1 -1
  13. package/internal/src/atom/create-regular-atom.ts +2 -3
  14. package/internal/src/families/find-in-store.ts +74 -0
  15. package/internal/src/families/index.ts +1 -0
  16. package/internal/src/get-state/get-from-store.ts +14 -0
  17. package/internal/src/get-state/index.ts +2 -0
  18. package/internal/src/{read-or-compute-value.ts → get-state/read-or-compute-value.ts} +3 -3
  19. package/internal/src/index.ts +1 -1
  20. package/internal/src/ingest-updates/ingest-atom-update.ts +2 -2
  21. package/internal/src/ingest-updates/ingest-transaction-update.ts +1 -0
  22. package/internal/src/mutable/create-mutable-atom.ts +3 -4
  23. package/internal/src/mutable/tracker.ts +43 -35
  24. package/internal/src/mutable/transceiver.ts +1 -1
  25. package/internal/src/not-found-error.ts +14 -3
  26. package/internal/src/operation.ts +2 -1
  27. package/internal/src/selector/create-writable-selector.ts +2 -1
  28. package/internal/src/selector/register-selector.ts +6 -5
  29. package/internal/src/set-state/index.ts +1 -0
  30. package/internal/src/set-state/set-atom.ts +17 -3
  31. package/internal/src/set-state/set-into-store.ts +24 -0
  32. package/internal/src/set-state/stow-update.ts +2 -4
  33. package/internal/src/store/store.ts +13 -4
  34. package/internal/src/subscribe/subscribe-to-root-atoms.ts +1 -1
  35. package/internal/src/timeline/add-atom-to-timeline.ts +5 -5
  36. package/internal/src/transaction/abort-transaction.ts +2 -1
  37. package/internal/src/transaction/apply-transaction.ts +5 -3
  38. package/internal/src/transaction/build-transaction.ts +20 -11
  39. package/internal/src/transaction/create-transaction.ts +2 -3
  40. package/internal/src/transaction/index.ts +3 -2
  41. package/internal/src/transaction/is-root-store.ts +23 -0
  42. package/package.json +10 -10
  43. package/react/dist/index.cjs +27 -21
  44. package/react/dist/index.cjs.map +1 -1
  45. package/react/dist/index.d.ts +8 -2
  46. package/react/dist/index.js +28 -22
  47. package/react/dist/index.js.map +1 -1
  48. package/react/src/index.ts +4 -1
  49. package/react/src/use-i.ts +35 -0
  50. package/react/src/use-json.ts +38 -0
  51. package/react/src/use-o.ts +33 -0
  52. package/react/src/use-tl.ts +45 -0
  53. package/realtime-client/dist/index.cjs +167 -64
  54. package/realtime-client/dist/index.cjs.map +1 -1
  55. package/realtime-client/dist/index.d.ts +10 -6
  56. package/realtime-client/dist/index.js +158 -63
  57. package/realtime-client/dist/index.js.map +1 -1
  58. package/realtime-client/src/index.ts +2 -1
  59. package/realtime-client/src/pull-family-member.ts +3 -3
  60. package/realtime-client/src/pull-mutable-family-member.ts +4 -4
  61. package/realtime-client/src/pull-mutable.ts +4 -4
  62. package/realtime-client/src/pull-state.ts +7 -6
  63. package/realtime-client/src/{realtime-client-store.ts → realtime-client-stores/client-main-store.ts} +0 -8
  64. package/realtime-client/src/realtime-client-stores/client-sync-store.ts +15 -0
  65. package/realtime-client/src/realtime-client-stores/index.ts +2 -0
  66. package/realtime-client/src/sync-server-action.ts +134 -40
  67. package/realtime-client/src/sync-state.ts +19 -0
  68. package/realtime-react/dist/index.cjs +43 -26
  69. package/realtime-react/dist/index.cjs.map +1 -1
  70. package/realtime-react/dist/index.d.ts +3 -1
  71. package/realtime-react/dist/index.js +41 -25
  72. package/realtime-react/dist/index.js.map +1 -1
  73. package/realtime-react/src/index.ts +1 -0
  74. package/realtime-react/src/on-mount.ts +3 -21
  75. package/realtime-react/src/use-realtime-service.ts +1 -1
  76. package/realtime-react/src/use-single-effect.ts +29 -0
  77. package/realtime-react/src/use-sync-server-action.ts +4 -7
  78. package/realtime-react/src/use-sync.ts +17 -0
  79. package/realtime-server/dist/index.cjs +239 -56
  80. package/realtime-server/dist/index.cjs.map +1 -1
  81. package/realtime-server/dist/index.d.ts +140 -9
  82. package/realtime-server/dist/index.js +228 -58
  83. package/realtime-server/dist/index.js.map +1 -1
  84. package/realtime-server/src/index.ts +2 -0
  85. package/realtime-server/src/realtime-action-synchronizer.ts +95 -14
  86. package/realtime-server/src/realtime-family-provider.ts +11 -6
  87. package/realtime-server/src/realtime-mutable-family-provider.ts +8 -6
  88. package/realtime-server/src/realtime-mutable-provider.ts +3 -2
  89. package/realtime-server/src/realtime-server-stores/index.ts +2 -0
  90. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +115 -0
  91. package/realtime-server/src/realtime-server-stores/server-user-store.ts +45 -0
  92. package/realtime-server/src/realtime-state-provider.ts +18 -11
  93. package/realtime-server/src/realtime-state-receiver.ts +2 -2
  94. package/realtime-server/src/realtime-state-synchronizer.ts +23 -0
  95. package/realtime-testing/dist/index.cjs +65 -26
  96. package/realtime-testing/dist/index.cjs.map +1 -1
  97. package/realtime-testing/dist/index.d.ts +11 -7
  98. package/realtime-testing/dist/index.js +64 -26
  99. package/realtime-testing/dist/index.js.map +1 -1
  100. package/realtime-testing/src/setup-realtime-test.tsx +83 -43
  101. package/src/find-state.ts +8 -16
  102. package/src/get-state.ts +2 -11
  103. package/src/logger.ts +1 -0
  104. package/src/set-state.ts +1 -13
  105. package/src/silo.ts +7 -3
  106. package/src/transaction.ts +3 -3
  107. package/react/src/store-hooks.ts +0 -87
  108. package/realtime-server/src/realtime-server-store.ts +0 -39
@@ -5,9 +5,8 @@ import type {
5
5
  RegularAtomToken,
6
6
  UpdateHandler,
7
7
  } from "atom.io"
8
- import { setState } from "atom.io"
9
8
 
10
- import type { RegularAtom } from ".."
9
+ import { type RegularAtom, setIntoStore } from ".."
11
10
  import { cacheValue } from "../caching"
12
11
  import { newest } from "../lineage"
13
12
  import type { Store } from "../store"
@@ -69,7 +68,7 @@ export function createRegularAtom<T>(
69
68
  const cleanupFunctions: (() => void)[] = []
70
69
  for (const effect of options.effects) {
71
70
  const cleanup = effect({
72
- setSelf: (next) => setState(token, next, store),
71
+ setSelf: (next) => setIntoStore(token, next, store),
73
72
  onSet: (handle: UpdateHandler<T>) =>
74
73
  subscribeToState(token, handle, `effect[${effectIndex}]`, store),
75
74
  })
@@ -0,0 +1,74 @@
1
+ import type { Json } from "atom.io/json"
2
+
3
+ import type {
4
+ MutableAtomFamilyToken,
5
+ MutableAtomToken,
6
+ ReadableFamilyToken,
7
+ ReadableToken,
8
+ ReadonlySelectorFamilyToken,
9
+ ReadonlySelectorToken,
10
+ RegularAtomFamilyToken,
11
+ RegularAtomToken,
12
+ WritableFamilyToken,
13
+ WritableSelectorFamilyToken,
14
+ WritableSelectorToken,
15
+ WritableToken,
16
+ } from "atom.io"
17
+ import type { Transceiver } from "../mutable"
18
+ import { NotFoundError } from "../not-found-error"
19
+ import type { Store } from "../store"
20
+
21
+ export function findInStore<
22
+ T extends Transceiver<any>,
23
+ J extends Json.Serializable,
24
+ K extends Json.Serializable,
25
+ Key extends K,
26
+ >(
27
+ token: MutableAtomFamilyToken<T, J, K>,
28
+ key: Key,
29
+ store: Store,
30
+ ): MutableAtomToken<T, J>
31
+
32
+ export function findInStore<T, K extends Json.Serializable, Key extends K>(
33
+ token: RegularAtomFamilyToken<T, K>,
34
+ key: Key,
35
+ store: Store,
36
+ ): RegularAtomToken<T>
37
+
38
+ export function findInStore<T, K extends Json.Serializable, Key extends K>(
39
+ token: WritableSelectorFamilyToken<T, K>,
40
+ key: Key,
41
+ store: Store,
42
+ ): WritableSelectorToken<T>
43
+
44
+ export function findInStore<T, K extends Json.Serializable, Key extends K>(
45
+ token: ReadonlySelectorFamilyToken<T, K>,
46
+ key: Key,
47
+ store: Store,
48
+ ): ReadonlySelectorToken<T>
49
+
50
+ export function findInStore<T, K extends Json.Serializable, Key extends K>(
51
+ token: WritableFamilyToken<T, K>,
52
+ key: Key,
53
+ store: Store,
54
+ ): WritableToken<T>
55
+
56
+ export function findInStore<T, K extends Json.Serializable, Key extends K>(
57
+ token: ReadableFamilyToken<T, K>,
58
+ key: Key,
59
+ store: Store,
60
+ ): ReadableToken<T>
61
+
62
+ export function findInStore(
63
+ token: ReadableFamilyToken<any, any>,
64
+ key: Json.Serializable,
65
+ store: Store,
66
+ ): ReadableToken<any> {
67
+ const familyKey = token.key
68
+ const family = store.families.get(familyKey)
69
+ if (family === undefined) {
70
+ throw new NotFoundError(token, store)
71
+ }
72
+ const state = family(key)
73
+ return state
74
+ }
@@ -2,3 +2,4 @@ export * from "./create-atom-family"
2
2
  export * from "./create-regular-atom-family"
3
3
  export * from "./create-readonly-selector-family"
4
4
  export * from "./create-selector-family"
5
+ export * from "./find-in-store"
@@ -0,0 +1,14 @@
1
+ import type { ReadableToken } from "atom.io"
2
+
3
+ import { NotFoundError } from "../not-found-error"
4
+ import type { Store } from "../store"
5
+ import { withdraw, withdrawNewFamilyMember } from "../store"
6
+ import { readOrComputeValue } from "./read-or-compute-value"
7
+
8
+ export function getFromStore<T>(token: ReadableToken<T>, store: Store): T {
9
+ const state = withdraw(token, store) ?? withdrawNewFamilyMember(token, store)
10
+ if (state === undefined) {
11
+ throw new NotFoundError(token, store)
12
+ }
13
+ return readOrComputeValue(state, store)
14
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./get-from-store"
2
+ export * from "./read-or-compute-value"
@@ -1,6 +1,6 @@
1
- import type { ReadableState } from "."
2
- import { readCachedValue } from "./caching"
3
- import type { Store } from "./store"
1
+ import type { ReadableState } from ".."
2
+ import { readCachedValue } from "../caching"
3
+ import type { Store } from "../store"
4
4
 
5
5
  export const readOrComputeValue = <T>(
6
6
  state: ReadableState<T>,
@@ -11,13 +11,13 @@ export * from "./lineage"
11
11
  export * from "./families"
12
12
  export * from "./future"
13
13
  export * from "./get-environment-data"
14
+ export * from "./get-state"
14
15
  export * from "./ingest-updates"
15
16
  export * from "./keys"
16
17
  export * from "./lazy-map"
17
18
  export * from "./mutable"
18
19
  export * from "./not-found-error"
19
20
  export * from "./operation"
20
- export * from "./read-or-compute-value"
21
21
  export * from "./selector"
22
22
  export * from "./set-state"
23
23
  export * from "./store"
@@ -1,6 +1,6 @@
1
1
  import type { KeyedStateUpdate } from "atom.io"
2
- import { setState } from "atom.io"
3
2
 
3
+ import { setIntoStore } from "../set-state"
4
4
  import type { Store } from "../store"
5
5
 
6
6
  export function ingestAtomUpdate(
@@ -10,5 +10,5 @@ export function ingestAtomUpdate(
10
10
  ): void {
11
11
  const { key, newValue, oldValue } = atomUpdate
12
12
  const value = applying === `newValue` ? newValue : oldValue
13
- setState({ key, type: `atom` }, value, store)
13
+ setIntoStore({ key, type: `atom` }, value, store)
14
14
  }
@@ -1,6 +1,7 @@
1
1
  import type { TransactionUpdate } from "atom.io"
2
2
 
3
3
  import type { Store } from "../store"
4
+ import { isRootStore } from "../transaction/is-root-store"
4
5
  import { ingestAtomUpdate } from "./ingest-atom-update"
5
6
 
6
7
  export function ingestTransactionUpdate(
@@ -4,12 +4,11 @@ import type {
4
4
  MutableAtomOptions,
5
5
  MutableAtomToken,
6
6
  } from "atom.io"
7
- import { setState } from "atom.io"
8
7
  import type { Json } from "atom.io/json"
9
8
  import { selectJson } from "atom.io/json"
10
9
 
11
- import { type MutableAtom, cacheValue } from ".."
12
- import { createRegularAtom, markAtomAsDefault } from "../atom"
10
+ import { type MutableAtom, cacheValue, setIntoStore } from ".."
11
+ import { markAtomAsDefault } from "../atom"
13
12
  import { newest } from "../lineage"
14
13
  import { type Store, deposit } from "../store"
15
14
  import { Subject } from "../subject"
@@ -70,7 +69,7 @@ export function createMutableAtom<
70
69
  const cleanupFunctions: (() => void)[] = []
71
70
  for (const effect of options.effects) {
72
71
  const cleanup = effect({
73
- setSelf: (next) => setState(token, next, store),
72
+ setSelf: (next) => setIntoStore(token, next, store),
74
73
  onSet: (handle: UpdateHandler<T>) =>
75
74
  subscribeToState(token, handle, `effect[${effectIndex}]`, store),
76
75
  })
@@ -1,10 +1,16 @@
1
1
  import type { FamilyMetadata, MutableAtomToken, RegularAtomToken } from "atom.io"
2
- import { getState, setState } from "atom.io"
3
2
  import type { Json } from "atom.io/json"
4
3
 
5
4
  import type { Store } from ".."
6
- import { newest, subscribeToState, subscribeToTimeline } from ".."
5
+ import {
6
+ getFromStore,
7
+ newest,
8
+ setIntoStore,
9
+ subscribeToState,
10
+ subscribeToTimeline,
11
+ } from ".."
7
12
  import { createRegularAtom } from "../atom"
13
+ import { isChildStore } from "../transaction/is-root-store"
8
14
  import type { Transceiver } from "./transceiver"
9
15
 
10
16
  /**
@@ -51,31 +57,26 @@ export class Tracker<Mutable extends Transceiver<any>> {
51
57
  private observeCore(
52
58
  mutableState: MutableAtomToken<Mutable, any>,
53
59
  latestUpdateState: RegularAtomToken<typeof this.Update | null>,
54
- store: Store,
60
+ target: Store,
55
61
  ): void {
56
- const subscriptionKey = `tracker:${store.config.name}:${
57
- store.transactionMeta === null ? `main` : store.transactionMeta.update.key
62
+ const subscriptionKey = `tracker:${target.config.name}:${
63
+ isChildStore(target) ? target.transactionMeta.update.key : `main`
58
64
  }:${mutableState.key}`
59
- const originalInnerValue = getState(mutableState, store)
60
- const target = newest(store)
65
+ const originalInnerValue = getFromStore(mutableState, target)
61
66
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
62
- `tracker:${store.config.name}:${
63
- target.transactionMeta === null
64
- ? `main`
65
- : target.transactionMeta.update.key
66
- }`,
67
+ subscriptionKey,
67
68
  (update) => {
68
69
  if (target.operation.open) {
69
70
  const unsubscribe = target.on.operationClose.subscribe(
70
71
  subscriptionKey,
71
72
  () => {
72
73
  unsubscribe()
73
- setState(latestUpdateState, update, target)
74
+ setIntoStore(latestUpdateState, update, target)
74
75
  },
75
76
  )
76
77
  } else {
77
- setState(mutableState, (current) => current, target)
78
- setState(latestUpdateState, update, target)
78
+ setIntoStore(mutableState, (current) => current, target)
79
+ setIntoStore(latestUpdateState, update, target)
79
80
  }
80
81
  },
81
82
  )
@@ -84,7 +85,6 @@ export class Tracker<Mutable extends Transceiver<any>> {
84
85
  (update) => {
85
86
  if (update.newValue !== update.oldValue) {
86
87
  this.unsubscribeFromInnerValue()
87
- const target = newest(store)
88
88
  this.unsubscribeFromInnerValue = update.newValue.subscribe(
89
89
  subscriptionKey,
90
90
  (update) => {
@@ -93,44 +93,45 @@ export class Tracker<Mutable extends Transceiver<any>> {
93
93
  subscriptionKey,
94
94
  () => {
95
95
  unsubscribe()
96
- setState(latestUpdateState, update, target)
96
+ setIntoStore(latestUpdateState, update, target)
97
97
  },
98
98
  )
99
99
  } else {
100
- setState(mutableState, (current) => current, target)
101
- setState(latestUpdateState, update, target)
100
+ setIntoStore(mutableState, (current) => current, target)
101
+ setIntoStore(latestUpdateState, update, target)
102
102
  }
103
103
  },
104
104
  )
105
105
  }
106
106
  },
107
107
  subscriptionKey,
108
- store,
108
+ target,
109
109
  )
110
110
  }
111
111
 
112
112
  private updateCore<Core extends Transceiver<any>>(
113
113
  mutableState: MutableAtomToken<Core, Json.Serializable>,
114
114
  latestUpdateState: RegularAtomToken<typeof this.Update | null>,
115
- store: Store,
115
+ target: Store,
116
116
  ): void {
117
- const subscriptionKey = `tracker:${store.config.name}:${
118
- store.transactionMeta === null ? `main` : store.transactionMeta.update.key
117
+ const subscriptionKey = `tracker:${target.config.name}:${
118
+ isChildStore(target) ? target.transactionMeta.update.key : `main`
119
119
  }:${mutableState.key}`
120
120
  subscribeToState(
121
121
  latestUpdateState,
122
122
  ({ newValue, oldValue }) => {
123
- const timelineId = store.timelineAtoms.getRelatedKey(
123
+ const timelineId = target.timelineAtoms.getRelatedKey(
124
124
  latestUpdateState.key,
125
125
  )
126
+
126
127
  if (timelineId) {
127
- const timelineData = store.timelines.get(timelineId)
128
+ const timelineData = target.timelines.get(timelineId)
128
129
  if (timelineData?.timeTraveling) {
129
130
  const unsubscribe = subscribeToTimeline(
130
131
  { key: timelineId, type: `timeline` },
131
132
  (update) => {
132
133
  unsubscribe()
133
- setState(
134
+ setIntoStore(
134
135
  mutableState,
135
136
  (transceiver) => {
136
137
  if (update === `redo` && newValue) {
@@ -140,38 +141,45 @@ export class Tracker<Mutable extends Transceiver<any>> {
140
141
  }
141
142
  return transceiver
142
143
  },
143
- store,
144
+ target,
144
145
  )
145
146
  },
146
147
  subscriptionKey,
147
- store,
148
+ target,
148
149
  )
149
150
  return
150
151
  }
151
152
  }
152
153
 
153
- const unsubscribe = store.on.operationClose.subscribe(
154
+ const unsubscribe = target.on.operationClose.subscribe(
154
155
  subscriptionKey,
155
156
  () => {
156
157
  unsubscribe()
157
- const mutable = getState(mutableState, store)
158
- // debugger
158
+ const mutable = getFromStore(mutableState, target)
159
159
  const updateNumber =
160
160
  newValue === null ? -1 : mutable.getUpdateNumber(newValue)
161
161
  const eventOffset = updateNumber - mutable.cacheUpdateNumber
162
162
  if (newValue && eventOffset === 1) {
163
- // ❗ new:"0=add:\"myHand\"",old:"0=add:\"deckId\""
164
- setState(
163
+ setIntoStore(
165
164
  mutableState,
166
165
  (transceiver) => (transceiver.do(newValue), transceiver),
167
- store,
166
+ target,
167
+ )
168
+ } else {
169
+ target.logger.info(
170
+ `❌`,
171
+ `mutable_atom`,
172
+ mutableState.key,
173
+ `could not be updated. Expected update number ${
174
+ mutable.cacheUpdateNumber + 1
175
+ }, but got ${updateNumber}`,
168
176
  )
169
177
  }
170
178
  },
171
179
  )
172
180
  },
173
181
  subscriptionKey,
174
- store,
182
+ target,
175
183
  )
176
184
  }
177
185
 
@@ -1,7 +1,7 @@
1
1
  import type { Json } from "atom.io/json"
2
2
 
3
3
  export interface Transceiver<Signal extends Json.Serializable> {
4
- do: (update: Signal) => void
4
+ do: (update: Signal) => number | `OUT_OF_RANGE` | null
5
5
  undo: (update: Signal) => void
6
6
  subscribe: (key: string, fn: (update: Signal) => void) => () => void
7
7
  cacheUpdateNumber: number
@@ -1,10 +1,21 @@
1
- import type { ReadableToken } from "atom.io"
1
+ import type {
2
+ ReadableFamilyToken,
3
+ ReadableToken,
4
+ TimelineToken,
5
+ TransactionToken,
6
+ } from "atom.io"
2
7
 
3
8
  import type { Store } from "./store"
4
9
 
5
10
  const capitalize = (str: string) => str[0].toUpperCase() + str.slice(1)
6
11
 
7
- function prettyPrintTokenType(token: ReadableToken<any>) {
12
+ type AtomIOToken =
13
+ | ReadableFamilyToken<any, any>
14
+ | ReadableToken<any>
15
+ | TimelineToken<any>
16
+ | TransactionToken<any>
17
+
18
+ function prettyPrintTokenType(token: AtomIOToken) {
8
19
  if (token.type === `readonly_selector`) {
9
20
  return `Readonly Selector`
10
21
  }
@@ -12,7 +23,7 @@ function prettyPrintTokenType(token: ReadableToken<any>) {
12
23
  }
13
24
 
14
25
  export class NotFoundError extends Error {
15
- public constructor(token: ReadableToken<any>, store: Store) {
26
+ public constructor(token: AtomIOToken, store: Store) {
16
27
  super(
17
28
  `${prettyPrintTokenType(token)} "${token.key}" not found in store "${
18
29
  store.config.name
@@ -2,6 +2,7 @@ import type { WritableToken } from "atom.io"
2
2
 
3
3
  import { newest } from "./lineage"
4
4
  import type { Store } from "./store"
5
+ import { isChildStore } from "./transaction/is-root-store"
5
6
 
6
7
  export type OperationProgress =
7
8
  | {
@@ -40,7 +41,7 @@ export const openOperation = (
40
41
  token.type,
41
42
  token.key,
42
43
  `operation start in store "${store.config.name}"${
43
- store.transactionMeta === null
44
+ !isChildStore(store)
44
45
  ? ``
45
46
  : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`
46
47
  }`,
@@ -11,6 +11,7 @@ import { markDone } from "../operation"
11
11
  import { become } from "../set-state/become"
12
12
  import type { Store } from "../store"
13
13
  import { Subject } from "../subject"
14
+ import { isRootStore } from "../transaction/is-root-store"
14
15
  import { registerSelector } from "./register-selector"
15
16
 
16
17
  export const createWritableSelector = <T>(
@@ -45,7 +46,7 @@ export const createWritableSelector = <T>(
45
46
  )
46
47
  cacheValue(options.key, newValue, subject, store)
47
48
  markDone(options.key, store)
48
- if (target.transactionMeta === null) {
49
+ if (isRootStore(target)) {
49
50
  subject.next({ newValue, oldValue })
50
51
  }
51
52
  options.set(transactors, newValue)
@@ -1,11 +1,11 @@
1
1
  import type { Transactors, findState } from "atom.io"
2
- import { findInStore } from "atom.io"
3
2
 
3
+ import { findInStore } from "../families"
4
+ import { readOrComputeValue } from "../get-state/read-or-compute-value"
4
5
  import { newest } from "../lineage"
5
- import { readOrComputeValue } from "../read-or-compute-value"
6
6
  import { setAtomOrSelector } from "../set-state"
7
7
  import type { Store } from "../store"
8
- import { withdraw } from "../store"
8
+ import { withdraw, withdrawNewFamilyMember } from "../store"
9
9
  import { updateSelectorAtoms } from "./update-selector-atoms"
10
10
 
11
11
  export const registerSelector = (
@@ -15,10 +15,11 @@ export const registerSelector = (
15
15
  get: (dependency) => {
16
16
  const target = newest(store)
17
17
 
18
- const dependencyState = withdraw(dependency, store)
18
+ const dependencyState =
19
+ withdraw(dependency, store) ?? withdrawNewFamilyMember(dependency, store)
19
20
  if (dependencyState === undefined) {
20
21
  throw new Error(
21
- `State "${dependency.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
22
+ `State "${dependency.key}" not found in store "${store.config.name}".`,
22
23
  )
23
24
  }
24
25
  const dependencyValue = readOrComputeValue(dependencyState, store)
@@ -1,2 +1,3 @@
1
1
  export * from "./become"
2
2
  export * from "./set-atom-or-selector"
3
+ export * from "./set-into-store"
@@ -1,10 +1,11 @@
1
1
  import type { Atom } from ".."
2
2
  import { isAtomDefault, markAtomAsNotDefault } from "../atom"
3
3
  import { cacheValue } from "../caching"
4
+ import { readOrComputeValue } from "../get-state/read-or-compute-value"
4
5
  import type { Transceiver } from "../mutable"
5
6
  import { markDone } from "../operation"
6
- import { readOrComputeValue } from "../read-or-compute-value"
7
7
  import type { Store } from "../store"
8
+ import { isRootStore } from "../transaction/is-root-store"
8
9
  import { become } from "./become"
9
10
  import { copyMutableIfWithinTransaction } from "./copy-mutable-in-transaction"
10
11
  import { emitUpdate } from "./emit-update"
@@ -27,7 +28,7 @@ export const setAtom = <T>(
27
28
  markDone(atom.key, target)
28
29
  evictDownStream(atom, target)
29
30
  const update = { oldValue, newValue }
30
- if (target.transactionMeta === null) {
31
+ if (isRootStore(target)) {
31
32
  emitUpdate(atom, update, target)
32
33
  } else if (target.parent) {
33
34
  if (target.on.transactionApplying.state === null) {
@@ -37,7 +38,20 @@ export const setAtom = <T>(
37
38
  const mutableAtom = target.atoms.get(mutableKey) as Atom<any>
38
39
  let mutable: Transceiver<any> = target.valueMap.get(mutableKey)
39
40
  mutable = copyMutableIfWithinTransaction(mutable, mutableAtom, target)
40
- mutable.do(update.newValue)
41
+ const output = mutable.do(update.newValue)
42
+ if (output !== null) {
43
+ target.logger.warn(
44
+ `❌`,
45
+ `mutable_atom`,
46
+ mutableKey,
47
+ `could not be updated.`,
48
+ typeof output === `number`
49
+ ? `Expected update number ${
50
+ mutable.cacheUpdateNumber + 1
51
+ }, but got ${output}`
52
+ : output,
53
+ )
54
+ }
41
55
  }
42
56
  }
43
57
  }
@@ -0,0 +1,24 @@
1
+ import type { WritableToken } from "atom.io"
2
+
3
+ import { NotFoundError } from "../not-found-error"
4
+ import { closeOperation, openOperation } from "../operation"
5
+ import type { Store } from "../store"
6
+ import { withdraw, withdrawNewFamilyMember } from "../store"
7
+ import { setAtomOrSelector } from "./set-atom-or-selector"
8
+
9
+ export function setIntoStore<T, New extends T>(
10
+ token: WritableToken<T>,
11
+ value: New | ((oldValue: T) => New),
12
+ store: Store,
13
+ ): void {
14
+ const rejection = openOperation(token, store)
15
+ if (rejection) {
16
+ return
17
+ }
18
+ const state = withdraw(token, store) ?? withdrawNewFamilyMember(token, store)
19
+ if (state === undefined) {
20
+ throw new NotFoundError(token, store)
21
+ }
22
+ setAtomOrSelector(state, value, store)
23
+ closeOperation(store)
24
+ }
@@ -4,6 +4,7 @@ import type { Atom } from ".."
4
4
  import { newest } from "../lineage"
5
5
  import { isTransceiver } from "../mutable"
6
6
  import type { Store } from "../store"
7
+ import { isChildStore } from "../transaction/is-root-store"
7
8
 
8
9
  function shouldUpdateBeStowed(key: string, update: StateUpdate<any>): boolean {
9
10
  // do not stow updates that aren't json
@@ -24,10 +25,7 @@ export const stowUpdate = <T>(
24
25
  ): void => {
25
26
  const { key } = state
26
27
  const target = newest(store)
27
- if (
28
- target.transactionMeta === null ||
29
- target.transactionMeta.phase !== `building`
30
- ) {
28
+ if (!isChildStore(target) || target.transactionMeta.phase !== `building`) {
31
29
  store.logger.error(
32
30
  `🐞`,
33
31
  `atom`,
@@ -27,7 +27,11 @@ import { getJsonToken, getUpdateToken } from "../mutable"
27
27
  import type { OperationProgress } from "../operation"
28
28
  import { StatefulSubject, Subject } from "../subject"
29
29
  import type { Timeline } from "../timeline"
30
- import type { Transaction, TransactionMeta } from "../transaction"
30
+ import type {
31
+ Transaction,
32
+ TransactionEpoch,
33
+ TransactionProgress,
34
+ } from "../transaction"
31
35
 
32
36
  export class Store implements Lineage {
33
37
  public parent: Store | null = null
@@ -82,11 +86,15 @@ export class Store implements Lineage {
82
86
  >(),
83
87
  transactionCreation: new Subject<TransactionToken<ƒn>>(),
84
88
  timelineCreation: new Subject<TimelineToken<unknown>>(),
85
- transactionApplying: new StatefulSubject<TransactionMeta<ƒn> | null>(null),
89
+ transactionApplying: new StatefulSubject<TransactionProgress<ƒn> | null>(
90
+ null,
91
+ ),
86
92
  operationClose: new Subject<OperationProgress>(),
87
93
  }
88
94
  public operation: OperationProgress = { open: false }
89
- public transactionMeta: TransactionMeta<ƒn> | null = null
95
+ public transactionMeta: TransactionEpoch | TransactionProgress<ƒn> = {
96
+ epoch: -1,
97
+ }
90
98
 
91
99
  public config: {
92
100
  name: string
@@ -113,7 +121,8 @@ export class Store implements Lineage {
113
121
  if (store !== null) {
114
122
  this.valueMap = new Map(store?.valueMap)
115
123
  this.operation = { ...store?.operation }
116
- this.transactionMeta = null
124
+ this.transactionMeta = { ...store?.transactionMeta }
125
+
117
126
  this.config = {
118
127
  ...store?.config,
119
128
  name,
@@ -1,6 +1,6 @@
1
1
  import type { Selector } from ".."
2
+ import { readOrComputeValue } from "../get-state/read-or-compute-value"
2
3
  import { newest } from "../lineage"
3
- import { readOrComputeValue } from "../read-or-compute-value"
4
4
  import { traceAllSelectorAtoms } from "../selector"
5
5
  import type { Store } from "../store"
6
6
  import { recallState } from "./recall-state"
@@ -30,7 +30,6 @@ export const addAtomToTimeline = (
30
30
  store.timelineAtoms.set({ atomKey: atom.key, timelineKey: tl.key })
31
31
 
32
32
  atom.subject.subscribe(`timeline`, (update) => {
33
- // debugger
34
33
  const target = newest(store)
35
34
  const currentSelectorKey =
36
35
  store.operation.open && store.operation.token.type === `selector`
@@ -40,8 +39,9 @@ export const addAtomToTimeline = (
40
39
  store.operation.open && store.operation.token.type === `selector`
41
40
  ? store.operation.time
42
41
  : null
43
- const currentTransactionKey = target.on.transactionApplying.state?.update.key
44
- const currentTransactionTime = target.on.transactionApplying.state?.time
42
+ const { transactionApplying } = target.on
43
+ const currentTransactionKey = transactionApplying.state?.update.key
44
+ const currentTransactionInstanceId = transactionApplying.state?.update.id
45
45
 
46
46
  store.logger.info(
47
47
  `⏳`,
@@ -93,7 +93,7 @@ export const addAtomToTimeline = (
93
93
  `timeline:${tl.key}`,
94
94
  (update) => {
95
95
  unsubscribe()
96
- if (tl.timeTraveling === null && currentTransactionTime) {
96
+ if (tl.timeTraveling === null && currentTransactionInstanceId) {
97
97
  if (tl.at !== tl.history.length) {
98
98
  tl.history.splice(tl.at)
99
99
  }
@@ -132,7 +132,7 @@ export const addAtomToTimeline = (
132
132
 
133
133
  const timelineTransactionUpdate: TimelineTransactionUpdate = {
134
134
  type: `transaction_update`,
135
- timestamp: currentTransactionTime,
135
+ timestamp: Date.now(),
136
136
  ...update,
137
137
  updates,
138
138
  }