atom.io 0.11.0 → 0.12.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 (172) hide show
  1. package/data/dist/index.cjs +614 -0
  2. package/data/dist/index.cjs.map +1 -0
  3. package/data/dist/index.d.cts +158 -0
  4. package/data/dist/index.d.ts +118 -1
  5. package/data/dist/index.js +551 -30
  6. package/data/dist/index.js.map +1 -1
  7. package/data/dist/metafile-cjs.json +1 -0
  8. package/data/dist/metafile-esm.json +1 -0
  9. package/data/package.json +4 -3
  10. package/data/src/index.ts +1 -0
  11. package/data/src/join.ts +450 -0
  12. package/data/src/struct-family.ts +34 -24
  13. package/data/src/struct.ts +6 -8
  14. package/dist/index.cjs +257 -0
  15. package/dist/index.cjs.map +1 -0
  16. package/dist/{index.d.mts → index.d.cts} +10 -11
  17. package/dist/index.d.ts +10 -11
  18. package/dist/index.js +63 -104
  19. package/dist/index.js.map +1 -1
  20. package/dist/metafile-cjs.json +1 -0
  21. package/dist/metafile-esm.json +1 -0
  22. package/internal/dist/{index.mjs → index.cjs} +692 -503
  23. package/internal/dist/index.cjs.map +1 -0
  24. package/internal/dist/{index.d.mts → index.d.cts} +114 -105
  25. package/internal/dist/index.d.ts +114 -105
  26. package/internal/dist/index.js +628 -563
  27. package/internal/dist/index.js.map +1 -1
  28. package/internal/dist/metafile-cjs.json +1 -0
  29. package/internal/dist/metafile-esm.json +1 -0
  30. package/internal/package.json +4 -3
  31. package/internal/src/atom/create-atom.ts +29 -16
  32. package/internal/src/atom/delete-atom.ts +25 -6
  33. package/internal/src/atom/is-default.ts +4 -17
  34. package/internal/src/caching.ts +28 -23
  35. package/internal/src/families/create-atom-family.ts +3 -2
  36. package/internal/src/families/create-readonly-selector-family.ts +1 -1
  37. package/internal/src/families/create-selector-family.ts +4 -4
  38. package/internal/src/index.ts +2 -1
  39. package/internal/src/mutable/create-mutable-atom-family.ts +2 -2
  40. package/internal/src/mutable/create-mutable-atom.ts +1 -2
  41. package/internal/src/mutable/get-json-family.ts +22 -0
  42. package/internal/src/mutable/get-json-token.ts +1 -0
  43. package/internal/src/mutable/index.ts +1 -0
  44. package/internal/src/mutable/tracker-family.ts +1 -2
  45. package/internal/src/mutable/tracker.ts +8 -6
  46. package/internal/src/mutable/transceiver.ts +2 -0
  47. package/internal/src/not-found-error.ts +27 -0
  48. package/internal/src/operation.ts +2 -3
  49. package/internal/src/{get-state-internal.ts → read-or-compute-value.ts} +13 -6
  50. package/internal/src/selector/create-selector.ts +6 -7
  51. package/internal/src/selector/delete-selector.ts +37 -0
  52. package/internal/src/selector/index.ts +2 -1
  53. package/internal/src/selector/register-selector.ts +7 -7
  54. package/internal/src/set-state/copy-mutable-in-transaction.ts +3 -2
  55. package/internal/src/set-state/emit-update.ts +1 -3
  56. package/internal/src/set-state/evict-downstream.ts +6 -8
  57. package/internal/src/set-state/index.ts +1 -1
  58. package/internal/src/set-state/{set-state-internal.ts → set-atom-or-selector.ts} +2 -3
  59. package/internal/src/set-state/set-atom.ts +5 -6
  60. package/internal/src/store/store.ts +1 -1
  61. package/internal/src/store/withdraw-new-family-member.ts +6 -6
  62. package/internal/src/subscribe/recall-state.ts +1 -2
  63. package/internal/src/subscribe/subscribe-to-root-atoms.ts +2 -2
  64. package/internal/src/timeline/add-atom-to-timeline.ts +5 -16
  65. package/internal/src/timeline/{timeline-internal.ts → create-timeline.ts} +4 -5
  66. package/internal/src/timeline/index.ts +2 -2
  67. package/internal/src/timeline/time-travel.ts +89 -0
  68. package/internal/src/transaction/{transaction-internal.ts → create-transaction.ts} +6 -5
  69. package/internal/src/transaction/index.ts +2 -3
  70. package/introspection/dist/{index.mjs → index.cjs} +54 -29
  71. package/introspection/dist/index.cjs.map +1 -0
  72. package/introspection/dist/{index.d.mts → index.d.cts} +2 -2
  73. package/introspection/dist/index.d.ts +2 -2
  74. package/introspection/dist/index.js +32 -49
  75. package/introspection/dist/index.js.map +1 -1
  76. package/introspection/dist/metafile-cjs.json +1 -0
  77. package/introspection/dist/metafile-esm.json +1 -0
  78. package/introspection/package.json +4 -3
  79. package/introspection/src/attach-introspection-states.ts +2 -2
  80. package/introspection/src/attach-selector-index.ts +8 -4
  81. package/json/dist/{index.mjs → index.cjs} +20 -7
  82. package/json/dist/{index.mjs.map → index.cjs.map} +1 -1
  83. package/json/dist/{index.d.mts → index.d.cts} +1 -1
  84. package/json/dist/index.d.ts +1 -1
  85. package/json/dist/index.js +6 -19
  86. package/json/dist/index.js.map +1 -1
  87. package/json/dist/metafile-cjs.json +1 -0
  88. package/json/dist/metafile-esm.json +1 -0
  89. package/json/package.json +4 -3
  90. package/package.json +48 -47
  91. package/react/dist/index.cjs +59 -0
  92. package/react/dist/index.cjs.map +1 -0
  93. package/react/dist/index.js +20 -42
  94. package/react/dist/index.js.map +1 -1
  95. package/react/dist/metafile-cjs.json +1 -0
  96. package/react/dist/metafile-esm.json +1 -0
  97. package/react/package.json +4 -3
  98. package/react/src/store-hooks.ts +8 -2
  99. package/react-devtools/dist/{index.mjs → index.cjs} +286 -240
  100. package/react-devtools/dist/index.cjs.map +1 -0
  101. package/react-devtools/dist/{index.d.mts → index.d.cts} +29 -17
  102. package/react-devtools/dist/index.d.ts +29 -17
  103. package/react-devtools/dist/index.js +251 -273
  104. package/react-devtools/dist/index.js.map +1 -1
  105. package/react-devtools/dist/metafile-cjs.json +1 -0
  106. package/react-devtools/dist/metafile-esm.json +1 -0
  107. package/react-devtools/package.json +4 -3
  108. package/react-devtools/src/StateEditor.tsx +8 -8
  109. package/realtime-client/dist/{index.mjs → index.cjs} +50 -21
  110. package/realtime-client/dist/index.js +20 -49
  111. package/realtime-client/dist/metafile-cjs.json +1 -0
  112. package/realtime-client/dist/metafile-esm.json +1 -0
  113. package/realtime-client/package.json +4 -3
  114. package/realtime-react/dist/index.cjs +99 -0
  115. package/realtime-react/dist/index.js +35 -66
  116. package/realtime-react/dist/metafile-cjs.json +1 -0
  117. package/realtime-react/dist/metafile-esm.json +1 -0
  118. package/realtime-react/package.json +4 -3
  119. package/realtime-server/dist/{index.mjs → index.cjs} +67 -40
  120. package/realtime-server/dist/index.js +39 -66
  121. package/realtime-server/dist/metafile-cjs.json +1 -0
  122. package/realtime-server/dist/metafile-esm.json +1 -0
  123. package/realtime-server/package.json +4 -3
  124. package/realtime-testing/dist/{index.mjs → index.cjs} +54 -23
  125. package/realtime-testing/dist/index.js +22 -53
  126. package/realtime-testing/dist/metafile-cjs.json +1 -0
  127. package/realtime-testing/dist/metafile-esm.json +1 -0
  128. package/realtime-testing/package.json +4 -3
  129. package/src/atom.ts +6 -8
  130. package/src/dispose.ts +18 -0
  131. package/src/get-state.ts +16 -0
  132. package/src/index.ts +3 -1
  133. package/src/logger.ts +1 -1
  134. package/src/selector.ts +3 -3
  135. package/src/set-state.ts +22 -0
  136. package/src/silo.ts +7 -8
  137. package/src/timeline.ts +6 -11
  138. package/src/transaction.ts +2 -2
  139. package/transceivers/set-rtx/dist/{index.mjs → index.cjs} +40 -36
  140. package/transceivers/set-rtx/dist/index.cjs.map +1 -0
  141. package/transceivers/set-rtx/dist/{index.d.mts → index.d.cts} +2 -1
  142. package/transceivers/set-rtx/dist/index.d.ts +2 -1
  143. package/transceivers/set-rtx/dist/index.js +37 -37
  144. package/transceivers/set-rtx/dist/index.js.map +1 -1
  145. package/transceivers/set-rtx/dist/metafile-cjs.json +1 -0
  146. package/transceivers/set-rtx/dist/metafile-esm.json +1 -0
  147. package/transceivers/set-rtx/package.json +4 -3
  148. package/transceivers/set-rtx/src/set-rtx.ts +29 -26
  149. package/data/dist/index.d.mts +0 -41
  150. package/data/dist/index.mjs +0 -82
  151. package/data/dist/index.mjs.map +0 -1
  152. package/dist/index.mjs +0 -215
  153. package/dist/index.mjs.map +0 -1
  154. package/internal/dist/index.mjs.map +0 -1
  155. package/internal/src/set-state/set-selector-state.ts +0 -8
  156. package/internal/src/timeline/time-travel-internal.ts +0 -109
  157. package/introspection/dist/index.mjs.map +0 -1
  158. package/react/dist/index.mjs +0 -29
  159. package/react/dist/index.mjs.map +0 -1
  160. package/react-devtools/dist/index.mjs.map +0 -1
  161. package/realtime-react/dist/index.mjs +0 -68
  162. package/src/get-set.ts +0 -48
  163. package/transceivers/set-rtx/dist/index.mjs.map +0 -1
  164. /package/react/dist/{index.d.mts → index.d.cts} +0 -0
  165. /package/realtime-client/dist/{index.mjs.map → index.cjs.map} +0 -0
  166. /package/realtime-client/dist/{index.d.mts → index.d.cts} +0 -0
  167. /package/realtime-react/dist/{index.mjs.map → index.cjs.map} +0 -0
  168. /package/realtime-react/dist/{index.d.mts → index.d.cts} +0 -0
  169. /package/realtime-server/dist/{index.mjs.map → index.cjs.map} +0 -0
  170. /package/realtime-server/dist/{index.d.mts → index.d.cts} +0 -0
  171. /package/realtime-testing/dist/{index.mjs.map → index.cjs.map} +0 -0
  172. /package/realtime-testing/dist/{index.d.mts → index.d.cts} +0 -0
@@ -4,7 +4,6 @@ import { parseJson } from "atom.io/json"
4
4
 
5
5
  import { createAtomFamily } from "../families"
6
6
  import type { Store } from "../store"
7
- import { IMPLICIT } from "../store"
8
7
  import { Tracker } from "./tracker"
9
8
  import type { Transceiver } from "./transceiver"
10
9
 
@@ -24,7 +23,7 @@ export class FamilyTracker<
24
23
 
25
24
  public constructor(
26
25
  findMutableState: AtomFamily<Core, FamilyMemberKey>,
27
- store: Store = IMPLICIT.STORE,
26
+ store: Store,
28
27
  ) {
29
28
  this.findLatestUpdateState = createAtomFamily<
30
29
  typeof this.Update | null,
@@ -3,7 +3,6 @@ import { getState, setState, subscribe, subscribeToTimeline } from "atom.io"
3
3
  import type { Json } from "atom.io/json"
4
4
 
5
5
  import type { Store } from ".."
6
- import { IMPLICIT } from ".."
7
6
  import { createAtom, deleteAtom } from "../atom"
8
7
  import { target } from "../transaction"
9
8
  import type { Transceiver } from "./transceiver"
@@ -18,7 +17,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
18
17
 
19
18
  private initializeState(
20
19
  mutableState: MutableAtomToken<Mutable, Json.Serializable>,
21
- store: Store = IMPLICIT.STORE,
20
+ store: Store,
22
21
  ): AtomToken<typeof this.Update | null> {
23
22
  const latestUpdateStateKey = `*${mutableState.key}`
24
23
  deleteAtom({ type: `atom`, key: latestUpdateStateKey }, store)
@@ -46,7 +45,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
46
45
  private observeCore(
47
46
  mutableState: MutableAtomToken<Mutable, Json.Serializable>,
48
47
  latestUpdateState: AtomToken<typeof this.Update | null>,
49
- store: Store = IMPLICIT.STORE,
48
+ store: Store,
50
49
  ): void {
51
50
  const originalInnerValue = getState(mutableState, store)
52
51
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
@@ -96,7 +95,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
96
95
  private updateCore<Core extends Transceiver<any>>(
97
96
  mutableState: MutableAtomToken<Core, Json.Serializable>,
98
97
  latestUpdateState: AtomToken<typeof this.Update | null>,
99
- store: Store = IMPLICIT.STORE,
98
+ store: Store,
100
99
  ): void {
101
100
  subscribe(
102
101
  latestUpdateState,
@@ -133,7 +132,10 @@ export class Tracker<Mutable extends Transceiver<any>> {
133
132
  latestUpdateState.key,
134
133
  () => {
135
134
  unsubscribe()
136
- if (newValue) {
135
+ const mutable = getState(mutableState, store)
136
+ const updateNumber = mutable.getUpdateNumber(newValue)
137
+ const eventOffset = updateNumber - mutable.cacheUpdateNumber
138
+ if (newValue && eventOffset === 1) {
137
139
  setState(
138
140
  mutableState,
139
141
  (transceiver) => (transceiver.do(newValue), transceiver),
@@ -153,7 +155,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
153
155
 
154
156
  public constructor(
155
157
  mutableState: MutableAtomToken<Mutable, Json.Serializable>,
156
- store: Store = IMPLICIT.STORE,
158
+ store: Store,
157
159
  ) {
158
160
  this.mutableState = mutableState
159
161
  this.latestUpdateState = this.initializeState(mutableState, store)
@@ -4,6 +4,8 @@ export interface Transceiver<Signal extends Json.Serializable> {
4
4
  do: (update: Signal) => void
5
5
  undo: (update: Signal) => void
6
6
  subscribe: (key: string, fn: (update: Signal) => void) => () => void
7
+ cacheUpdateNumber: number
8
+ getUpdateNumber: (update: Signal) => number
7
9
  }
8
10
 
9
11
  export function isTransceiver(
@@ -0,0 +1,27 @@
1
+ import type { ReadonlySelectorToken, StateToken } from "atom.io"
2
+
3
+ import type { Store } from "./store"
4
+
5
+ const capitalize = (str: string) => str[0].toUpperCase() + str.slice(1)
6
+
7
+ function prettyPrintTokenType(
8
+ token: ReadonlySelectorToken<any> | StateToken<any>,
9
+ ) {
10
+ if (token.type === `readonly_selector`) {
11
+ return `Readonly Selector`
12
+ }
13
+ return capitalize(token.type)
14
+ }
15
+
16
+ export class NotFoundError extends Error {
17
+ public constructor(
18
+ token: ReadonlySelectorToken<any> | StateToken<any>,
19
+ store: Store,
20
+ ) {
21
+ super(
22
+ `${prettyPrintTokenType(token)} "${token.key}" not found in store "${
23
+ store.config.name
24
+ }".`,
25
+ )
26
+ }
27
+ }
@@ -1,7 +1,6 @@
1
1
  import type { StateToken } from "atom.io"
2
2
 
3
3
  import type { Store } from "./store"
4
- import { IMPLICIT } from "./store"
5
4
  import { target } from "./transaction"
6
5
 
7
6
  export type OperationProgress =
@@ -62,7 +61,7 @@ export const closeOperation = (store: Store): void => {
62
61
  store.subject.operationStatus.next(core.operation)
63
62
  }
64
63
 
65
- export const isDone = (key: string, store: Store = IMPLICIT.STORE): boolean => {
64
+ export const isDone = (key: string, store: Store): boolean => {
66
65
  const core = target(store)
67
66
  if (!core.operation.open) {
68
67
  store.logger.warn(
@@ -75,7 +74,7 @@ export const isDone = (key: string, store: Store = IMPLICIT.STORE): boolean => {
75
74
  }
76
75
  return core.operation.done.has(key)
77
76
  }
78
- export const markDone = (key: string, store: Store = IMPLICIT.STORE): void => {
77
+ export const markDone = (key: string, store: Store): void => {
79
78
  const core = target(store)
80
79
  if (!core.operation.open) {
81
80
  store.logger.warn(
@@ -2,20 +2,27 @@ import type { Atom } from "./atom"
2
2
  import { isValueCached, readCachedValue } from "./caching"
3
3
  import type { ReadonlySelector, Selector } from "./selector"
4
4
  import type { Store } from "./store"
5
- import { IMPLICIT } from "./store"
6
5
 
7
- export const getState__INTERNAL = <T>(
6
+ export const readOrComputeValue = <T>(
8
7
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
9
- store: Store = IMPLICIT.STORE,
8
+ store: Store,
10
9
  ): T => {
11
10
  if (isValueCached(state.key, store)) {
12
11
  store.logger.info(`📖`, state.type, state.key, `reading cached value`)
13
12
  return readCachedValue(state.key, store)
14
13
  }
15
14
  if (state.type !== `atom`) {
16
- store.logger.info(`🧮`, state.type, state.key, `calculating value`)
15
+ store.logger.info(`🧮`, state.type, state.key, `computing value`)
17
16
  return state.get()
18
17
  }
19
- store.logger.error(`🐞`, `atom`, state.key, `could not find cached value`)
20
- return state.default
18
+ const fallback =
19
+ state.default instanceof Function ? state.default() : state.default
20
+ store.logger.info(
21
+ `💁`,
22
+ `atom`,
23
+ state.key,
24
+ `could not find cached value; using default`,
25
+ fallback,
26
+ )
27
+ return state.default instanceof Function ? state.default() : state.default
21
28
  }
@@ -7,7 +7,6 @@ import type {
7
7
  } from "atom.io"
8
8
 
9
9
  import type { Store } from "../store"
10
- import { IMPLICIT } from "../store"
11
10
  import type { Subject } from "../subject"
12
11
  import { target } from "../transaction"
13
12
  import { createReadWriteSelector } from "./create-read-write-selector"
@@ -33,18 +32,18 @@ export type ReadonlySelector<T> = {
33
32
 
34
33
  export function createSelector<T>(
35
34
  options: SelectorOptions<T>,
36
- family?: FamilyMetadata,
37
- store?: Store,
35
+ family: FamilyMetadata | undefined,
36
+ store: Store,
38
37
  ): SelectorToken<T>
39
38
  export function createSelector<T>(
40
39
  options: ReadonlySelectorOptions<T>,
41
- family?: FamilyMetadata,
42
- store?: Store,
40
+ family: FamilyMetadata | undefined,
41
+ store: Store,
43
42
  ): ReadonlySelectorToken<T>
44
43
  export function createSelector<T>(
45
44
  options: ReadonlySelectorOptions<T> | SelectorOptions<T>,
46
- family?: FamilyMetadata,
47
- store: Store = IMPLICIT.STORE,
45
+ family: FamilyMetadata | undefined,
46
+ store: Store,
48
47
  ): ReadonlySelectorToken<T> | SelectorToken<T> {
49
48
  const core = target(store)
50
49
  const existingWritable = core.selectors.get(options.key)
@@ -0,0 +1,37 @@
1
+ import type { ReadonlySelectorToken, SelectorToken } from "atom.io"
2
+
3
+ import type { Store } from ".."
4
+ import { target } from ".."
5
+
6
+ export function deleteSelector(
7
+ selectorToken: ReadonlySelectorToken<unknown> | SelectorToken<unknown>,
8
+ store: Store,
9
+ ): void {
10
+ const core = target(store)
11
+ const { key } = selectorToken
12
+ switch (selectorToken.type) {
13
+ case `selector`:
14
+ core.selectors.delete(key)
15
+ break
16
+ case `readonly_selector`:
17
+ core.readonlySelectors.delete(key)
18
+ break
19
+ }
20
+ core.valueMap.delete(key)
21
+ core.selectorAtoms.delete(key)
22
+ const downstreamTokens = core.selectorGraph
23
+ .getRelationEntries({ upstreamSelectorKey: key })
24
+ .filter(([_, { source }]) => source === key)
25
+ .map(
26
+ ([downstreamSelectorKey]) =>
27
+ core.selectors.get(downstreamSelectorKey) ??
28
+ core.readonlySelectors.get(downstreamSelectorKey),
29
+ )
30
+ for (const downstreamToken of downstreamTokens) {
31
+ if (downstreamToken) {
32
+ deleteSelector(downstreamToken, store)
33
+ }
34
+ }
35
+ core.selectorGraph.delete(key)
36
+ store.logger.info(`🔥`, selectorToken.type, `${key}`, `deleted`)
37
+ }
@@ -1,5 +1,6 @@
1
+ export * from "./create-selector"
2
+ export * from "./delete-selector"
1
3
  export * from "./get-selector-dependency-keys"
2
4
  export * from "./register-selector"
3
- export * from "./create-selector"
4
5
  export * from "./trace-selector-atoms"
5
6
  export * from "./update-selector-atoms"
@@ -1,15 +1,15 @@
1
1
  import type { Transactors } from "atom.io"
2
2
 
3
- import { getState__INTERNAL } from "../get-state-internal"
4
- import { setState__INTERNAL } from "../set-state"
3
+ import { readOrComputeValue } from "../read-or-compute-value"
4
+ import { setAtomOrSelector } from "../set-state"
5
5
  import type { Store } from "../store"
6
- import { IMPLICIT, withdraw } from "../store"
7
- import { target } from "../transaction/transaction-internal"
6
+ import { withdraw } from "../store"
7
+ import { target } from "../transaction/create-transaction"
8
8
  import { updateSelectorAtoms } from "./update-selector-atoms"
9
9
 
10
10
  export const registerSelector = (
11
11
  selectorKey: string,
12
- store: Store = IMPLICIT.STORE,
12
+ store: Store,
13
13
  ): Transactors => ({
14
14
  get: (dependency) => {
15
15
  const core = target(store)
@@ -23,7 +23,7 @@ export const registerSelector = (
23
23
  `State "${dependency.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
24
24
  )
25
25
  }
26
- const dependencyValue = getState__INTERNAL(dependencyState, store)
26
+ const dependencyValue = readOrComputeValue(dependencyState, store)
27
27
 
28
28
  store.logger.info(
29
29
  `🔌`,
@@ -55,6 +55,6 @@ export const registerSelector = (
55
55
  `State "${stateToken.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
56
56
  )
57
57
  }
58
- setState__INTERNAL(state, newValue, store)
58
+ setAtomOrSelector(state, newValue, store)
59
59
  },
60
60
  })
@@ -1,11 +1,12 @@
1
1
  import type { AtomFamily } from "atom.io"
2
2
  import type { Json, JsonInterface } from "atom.io/json"
3
- import { getState__INTERNAL } from ".."
3
+ import { readOrComputeValue } from ".."
4
4
  import type { Store, StoreCore } from ".."
5
5
  import type { Atom } from "../atom"
6
6
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
7
7
 
8
8
  export function copyMutableIfWithinTransaction<T>(
9
+ oldValue: T,
9
10
  atom: Atom<T> | (Atom<T> & JsonInterface<T, Json.Serializable>),
10
11
  store: Store,
11
12
  ): T {
@@ -37,7 +38,7 @@ export function copyMutableIfWithinTransaction<T>(
37
38
  }
38
39
  }
39
40
  }
40
- return getState__INTERNAL(atom, store)
41
+ return oldValue
41
42
  }
42
43
 
43
44
  export function copyMutableFamilyMemberWithinTransaction<T>(
@@ -9,9 +9,7 @@ export const emitUpdate = <T>(
9
9
  update: StateUpdate<T>,
10
10
  store: Store,
11
11
  ): void => {
12
- const { key } = state
13
- const { logger } = store
14
- logger.info(
12
+ store.logger.info(
15
13
  `📢`,
16
14
  state.type,
17
15
  state.key,
@@ -2,23 +2,21 @@ import type { Atom } from "../atom"
2
2
  import { evictCachedValue } from "../caching"
3
3
  import { isDone, markDone } from "../operation"
4
4
  import type { Store } from "../store"
5
- import { IMPLICIT } from "../store"
6
5
  import { target } from "../transaction"
7
6
 
8
- export const evictDownStream = <T>(
9
- atom: Atom<T>,
10
- store: Store = IMPLICIT.STORE,
11
- ): void => {
7
+ export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
12
8
  const core = target(store)
13
9
  const downstreamKeys = core.selectorAtoms.getRelatedKeys(atom.key)
14
10
  store.logger.info(
15
11
  `🧹`,
16
12
  atom.type,
17
13
  atom.key,
18
- `evicting ${downstreamKeys?.size ?? 0} states downstream:`,
19
- downstreamKeys,
14
+ downstreamKeys
15
+ ? `evicting ${downstreamKeys.size} states downstream:`
16
+ : `no downstream states`,
17
+ downstreamKeys ?? `to evict`,
20
18
  )
21
- if (downstreamKeys !== undefined) {
19
+ if (downstreamKeys) {
22
20
  if (core.operation.open) {
23
21
  store.logger.info(
24
22
  `🧹`,
@@ -1,2 +1,2 @@
1
1
  export * from "./become"
2
- export * from "./set-state-internal"
2
+ export * from "./set-atom-or-selector"
@@ -1,13 +1,12 @@
1
1
  import type { Atom } from "../atom"
2
2
  import type { Selector } from "../selector"
3
3
  import type { Store } from "../store"
4
- import { IMPLICIT } from "../store"
5
4
  import { setAtom } from "./set-atom"
6
5
 
7
- export const setState__INTERNAL = <T>(
6
+ export const setAtomOrSelector = <T>(
8
7
  state: Atom<T> | Selector<T>,
9
8
  value: T | ((oldValue: T) => T),
10
- store: Store = IMPLICIT.STORE,
9
+ store: Store,
11
10
  ): void => {
12
11
  if (state.type === `selector`) {
13
12
  state.set(value)
@@ -1,10 +1,9 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { isAtomDefault, markAtomAsNotDefault } from "../atom"
3
3
  import { cacheValue } from "../caching"
4
- import { getState__INTERNAL } from "../get-state-internal"
5
4
  import { markDone } from "../operation"
5
+ import { readOrComputeValue } from "../read-or-compute-value"
6
6
  import type { Store } from "../store"
7
- import { IMPLICIT } from "../store"
8
7
  import { become } from "./become"
9
8
  import { copyMutableIfWithinTransaction } from "./copy-mutable-in-transaction"
10
9
  import { emitUpdate } from "./emit-update"
@@ -14,13 +13,13 @@ 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 = IMPLICIT.STORE,
16
+ store: Store,
18
17
  ): void => {
19
- const oldValue = getState__INTERNAL(atom, store)
20
- let newValue = copyMutableIfWithinTransaction(atom, store)
18
+ const oldValue = readOrComputeValue(atom, store)
19
+ let newValue = copyMutableIfWithinTransaction(oldValue, atom, store)
21
20
  newValue = become(next)(newValue)
22
21
  store.logger.info(`📝`, `atom`, atom.key, `set to`, newValue)
23
- cacheValue(atom.key, newValue, atom.subject, store)
22
+ newValue = cacheValue(atom.key, newValue, atom.subject, store)
24
23
  if (isAtomDefault(atom.key, store)) {
25
24
  markAtomAsNotDefault(atom.key, store)
26
25
  }
@@ -152,7 +152,7 @@ export const IMPLICIT = {
152
152
  },
153
153
  }
154
154
 
155
- export const clearStore = (store: Store = IMPLICIT.STORE): void => {
155
+ export const clearStore = (store: Store): void => {
156
156
  const { config } = store
157
157
  Object.assign(store, new Store(config.name))
158
158
  store.config = config
@@ -36,13 +36,13 @@ export function withdrawNewFamilyMember<T>(
36
36
  | StateToken<T>,
37
37
  store: Store,
38
38
  ): Atom<T> | ReadonlySelector<T> | Selector<T> | undefined {
39
- store.logger.info(
40
- `👪`,
41
- token.type,
42
- token.key,
43
- `creating new family member in store "${store.config.name}"`,
44
- )
45
39
  if (token.family) {
40
+ store.logger.info(
41
+ `👪`,
42
+ token.type,
43
+ token.key,
44
+ `creating new family member in store "${store.config.name}"`,
45
+ )
46
46
  const core = target(store)
47
47
  const family = core.families.get(token.family.key)
48
48
  if (family) {
@@ -1,12 +1,11 @@
1
1
  import type { Atom } from "../atom"
2
2
  import type { ReadonlySelector, Selector } from "../selector"
3
3
  import type { Store } from "../store"
4
- import { IMPLICIT } from "../store"
5
4
  import { target } from "../transaction"
6
5
 
7
6
  export const recallState = <T>(
8
7
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
9
- store: Store = IMPLICIT.STORE,
8
+ store: Store,
10
9
  ): T => {
11
10
  const core = target(store)
12
11
  if (!core.operation.open) {
@@ -1,4 +1,4 @@
1
- import { getState__INTERNAL } from "../get-state-internal"
1
+ import { readOrComputeValue } from "../read-or-compute-value"
2
2
  import type { ReadonlySelector, Selector } from "../selector"
3
3
  import { traceAllSelectorAtoms } from "../selector"
4
4
  import type { Store } from "../store"
@@ -34,7 +34,7 @@ export const subscribeToRootAtoms = <T>(
34
34
  )
35
35
  const oldValue = recallState(state, store)
36
36
  // ❌ this retrieves a stale cached value when applying a transaction on the server
37
- const newValue = getState__INTERNAL(state, store)
37
+ const newValue = readOrComputeValue(state, store)
38
38
  store.logger.info(
39
39
  `✨`,
40
40
  state.type,
@@ -1,18 +1,18 @@
1
1
  import type { AtomToken, TimelineUpdate } from "atom.io"
2
2
 
3
3
  import type { Store } from "../store"
4
- import { IMPLICIT, withdraw } from "../store"
4
+ import { withdraw } from "../store"
5
5
  import { target } from "../transaction"
6
6
  import type {
7
7
  Timeline,
8
8
  TimelineAtomUpdate,
9
9
  TimelineTransactionUpdate,
10
- } from "./timeline-internal"
10
+ } from "./create-timeline"
11
11
 
12
12
  export const addAtomToTimeline = (
13
13
  atomToken: AtomToken<any>,
14
14
  tl: Timeline,
15
- store: Store = IMPLICIT.STORE,
15
+ store: Store,
16
16
  ): void => {
17
17
  const atom = withdraw(atomToken, store)
18
18
  if (atom === undefined) {
@@ -38,17 +38,6 @@ export const addAtomToTimeline = (
38
38
  ? store.transactionStatus.time
39
39
  : null
40
40
 
41
- // store.logger.info(
42
- // `⏳ timeline "${tl.key}" saw atom "${atomToken.key}" go (`,
43
- // update.oldValue,
44
- // `->`,
45
- // update.newValue,
46
- // currentTransactionKey
47
- // ? `) in transaction "${currentTransactionKey}"`
48
- // : currentSelectorKey
49
- // ? `) in selector "${currentSelectorKey}"`
50
- // : `)`,
51
- // )
52
41
  store.logger.info(
53
42
  `⏳`,
54
43
  `timeline`,
@@ -62,8 +51,8 @@ export const addAtomToTimeline = (
62
51
  currentTransactionKey
63
52
  ? `in transaction "${currentTransactionKey}"`
64
53
  : currentSelectorKey
65
- ? `in selector "${currentSelectorKey}"`
66
- : ``,
54
+ ? `in selector "${currentSelectorKey}"`
55
+ : ``,
67
56
  )
68
57
 
69
58
  if (tl.timeTraveling === null) {
@@ -9,7 +9,6 @@ import type {
9
9
  } from "atom.io"
10
10
 
11
11
  import type { Store } from "../store"
12
- import { IMPLICIT } from "../store"
13
12
  import { Subject } from "../subject"
14
13
  import { target } from "../transaction"
15
14
  import { addAtomToTimeline } from "./add-atom-to-timeline"
@@ -51,10 +50,10 @@ export type Timeline = {
51
50
  >
52
51
  }
53
52
 
54
- export function timeline__INTERNAL(
53
+ export function createTimeline(
55
54
  options: TimelineOptions,
56
- store: Store = IMPLICIT.STORE,
57
- data: Timeline | null = null,
55
+ store: Store,
56
+ data?: Timeline,
58
57
  ): TimelineToken {
59
58
  const tl: Timeline = {
60
59
  type: `timeline`,
@@ -65,7 +64,7 @@ export function timeline__INTERNAL(
65
64
  transactionKey: null,
66
65
  ...data,
67
66
  history: data?.history.map((update) => ({ ...update })) ?? [],
68
- install: (store) => timeline__INTERNAL(options, store, tl),
67
+ install: (store) => createTimeline(options, store, tl),
69
68
  subject: new Subject(),
70
69
  }
71
70
  if (options.shouldCapture) {
@@ -1,3 +1,3 @@
1
1
  export * from "./add-atom-to-timeline"
2
- export * from "./time-travel-internal"
3
- export * from "./timeline-internal"
2
+ export * from "./create-timeline"
3
+ export * from "./time-travel"
@@ -0,0 +1,89 @@
1
+ import type { TimelineToken } from "atom.io"
2
+ import { setState } from "atom.io"
3
+
4
+ import type { Store } from "../store"
5
+
6
+ export const timeTravel = (
7
+ direction: `backward` | `forward`,
8
+ token: TimelineToken,
9
+ store: Store,
10
+ ): void => {
11
+ const action = direction === `forward` ? `redo` : `undo`
12
+ store.logger.info(
13
+ direction === `forward` ? `⏩` : `⏪`,
14
+ `timeline`,
15
+ token.key,
16
+ action,
17
+ )
18
+
19
+ const timelineData = store.timelines.get(token.key)
20
+ if (!timelineData) {
21
+ store.logger.error(
22
+ `🐞`,
23
+ `timeline`,
24
+ token.key,
25
+ `Failed to ${action}. This timeline has not been initialized.`,
26
+ )
27
+ return
28
+ }
29
+
30
+ if (
31
+ (direction === `forward` &&
32
+ timelineData.at === timelineData.history.length) ||
33
+ (direction === `backward` && timelineData.at === 0)
34
+ ) {
35
+ store.logger.warn(
36
+ `💁`,
37
+ `timeline`,
38
+ token.key,
39
+ `Failed to ${action} at the ${
40
+ direction === `forward` ? `end` : `beginning`
41
+ } of timeline "${token.key}". There is nothing to ${action}.`,
42
+ )
43
+ return
44
+ }
45
+
46
+ timelineData.timeTraveling =
47
+ direction === `forward` ? `into_future` : `into_past`
48
+ if (direction === `backward`) {
49
+ --timelineData.at
50
+ }
51
+
52
+ const update = timelineData.history[timelineData.at]
53
+ const updateValues = (atomUpdate: any) => {
54
+ const { key, newValue, oldValue } = atomUpdate
55
+ const value = direction === `forward` ? newValue : oldValue
56
+ setState({ key, type: `atom` }, value, store)
57
+ }
58
+
59
+ switch (update.type) {
60
+ case `atom_update`: {
61
+ updateValues(update)
62
+ break
63
+ }
64
+ case `selector_update`:
65
+ case `transaction_update`: {
66
+ const updates =
67
+ direction === `forward`
68
+ ? update.atomUpdates
69
+ : [...update.atomUpdates].reverse()
70
+ for (const atomUpdate of updates) {
71
+ updateValues(atomUpdate)
72
+ }
73
+ break
74
+ }
75
+ }
76
+
77
+ if (direction === `forward`) {
78
+ ++timelineData.at
79
+ }
80
+
81
+ timelineData.subject.next(action)
82
+ timelineData.timeTraveling = null
83
+ store.logger.info(
84
+ `⏹️`,
85
+ `timeline`,
86
+ token.key,
87
+ `"${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
88
+ )
89
+ }