atom.io 0.6.8 → 0.7.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 (214) hide show
  1. package/README.md +21 -2
  2. package/dist/index.d.mts +42 -461
  3. package/dist/index.d.ts +42 -461
  4. package/dist/index.js +128 -1792
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +75 -1742
  7. package/dist/index.mjs.map +1 -1
  8. package/internal/dist/index.d.mts +342 -0
  9. package/internal/dist/index.d.ts +342 -0
  10. package/internal/dist/index.js +1873 -0
  11. package/internal/dist/index.js.map +1 -0
  12. package/internal/dist/index.mjs +1798 -0
  13. package/internal/dist/index.mjs.map +1 -0
  14. package/internal/package.json +15 -0
  15. package/internal/src/atom/create-atom.ts +75 -0
  16. package/internal/src/atom/delete-atom.ts +10 -0
  17. package/internal/src/atom/index.ts +3 -0
  18. package/{src/internal → internal/src/atom}/is-default.ts +4 -2
  19. package/internal/src/caching.ts +21 -0
  20. package/internal/src/families/create-atom-family.ts +59 -0
  21. package/internal/src/families/create-readonly-selector-family.ts +45 -0
  22. package/internal/src/families/create-selector-family.ts +67 -0
  23. package/internal/src/families/index.ts +3 -0
  24. package/internal/src/get-state-internal.ts +23 -0
  25. package/internal/src/index.ts +13 -0
  26. package/internal/src/mutable/create-mutable-atom-family.ts +25 -0
  27. package/internal/src/mutable/create-mutable-atom.ts +49 -0
  28. package/internal/src/mutable/get-json-token.ts +22 -0
  29. package/internal/src/mutable/get-update-token.ts +20 -0
  30. package/internal/src/mutable/index.ts +17 -0
  31. package/internal/src/mutable/is-atom-token-mutable.ts +7 -0
  32. package/internal/src/mutable/tracker-family.ts +61 -0
  33. package/internal/src/mutable/tracker.ts +164 -0
  34. package/internal/src/mutable/transceiver.ts +110 -0
  35. package/internal/src/operation.ts +68 -0
  36. package/{src/internal → internal/src}/selector/create-read-write-selector.ts +10 -13
  37. package/{src/internal → internal/src}/selector/create-readonly-selector.ts +9 -8
  38. package/internal/src/selector/create-selector.ts +65 -0
  39. package/{src/internal → internal/src}/selector/index.ts +1 -0
  40. package/internal/src/selector/lookup-selector-sources.ts +20 -0
  41. package/{src/internal → internal/src}/selector/register-selector.ts +13 -9
  42. package/{src/internal → internal/src}/selector/trace-selector-atoms.ts +4 -2
  43. package/{src/internal → internal/src}/selector/update-selector-atoms.ts +4 -3
  44. package/internal/src/set-state/become.ts +10 -0
  45. package/internal/src/set-state/copy-mutable-if-needed.ts +23 -0
  46. package/internal/src/set-state/copy-mutable-in-transaction.ts +59 -0
  47. package/internal/src/set-state/copy-mutable-into-new-store.ts +34 -0
  48. package/internal/src/set-state/emit-update.ts +23 -0
  49. package/internal/src/set-state/evict-downstream.ts +39 -0
  50. package/internal/src/set-state/index.ts +2 -0
  51. package/internal/src/set-state/set-atom-state.ts +38 -0
  52. package/internal/src/set-state/set-selector-state.ts +19 -0
  53. package/internal/src/set-state/set-state-internal.ts +18 -0
  54. package/internal/src/set-state/stow-update.ts +42 -0
  55. package/internal/src/store/deposit.ts +43 -0
  56. package/internal/src/store/index.ts +5 -0
  57. package/internal/src/store/lookup.ts +26 -0
  58. package/internal/src/store/store.ts +154 -0
  59. package/internal/src/store/withdraw-new-family-member.ts +53 -0
  60. package/internal/src/store/withdraw.ts +113 -0
  61. package/internal/src/subject.ts +21 -0
  62. package/internal/src/subscribe/index.ts +1 -0
  63. package/internal/src/subscribe/recall-state.ts +19 -0
  64. package/internal/src/subscribe/subscribe-to-root-atoms.ts +47 -0
  65. package/{src/internal → internal/src}/timeline/add-atom-to-timeline.ts +50 -29
  66. package/internal/src/timeline/index.ts +3 -0
  67. package/{src/internal → internal/src/timeline}/time-travel-internal.ts +6 -6
  68. package/{src/internal → internal/src/timeline}/timeline-internal.ts +20 -12
  69. package/{src/internal → internal/src}/transaction/abort-transaction.ts +1 -1
  70. package/{src/internal → internal/src}/transaction/apply-transaction.ts +25 -18
  71. package/{src/internal → internal/src}/transaction/build-transaction.ts +12 -6
  72. package/{src/internal → internal/src}/transaction/index.ts +3 -2
  73. package/{src/internal → internal/src}/transaction/redo-transaction.ts +4 -5
  74. package/{src/internal → internal/src/transaction}/transaction-internal.ts +16 -13
  75. package/{src/internal → internal/src}/transaction/undo-transaction.ts +4 -5
  76. package/introspection/dist/index.d.mts +12 -260
  77. package/introspection/dist/index.d.ts +12 -260
  78. package/introspection/dist/index.js +125 -140
  79. package/introspection/dist/index.js.map +1 -1
  80. package/introspection/dist/index.mjs +103 -116
  81. package/introspection/dist/index.mjs.map +1 -1
  82. package/{src/introspection → introspection/src}/attach-atom-index.ts +41 -30
  83. package/{src/introspection → introspection/src}/attach-introspection-states.ts +6 -10
  84. package/introspection/src/attach-selector-index.ts +90 -0
  85. package/{src/introspection → introspection/src}/attach-timeline-family.ts +16 -16
  86. package/introspection/src/attach-timeline-index.ts +38 -0
  87. package/introspection/src/attach-transaction-index.ts +40 -0
  88. package/{src/introspection → introspection/src}/attach-transaction-logs.ts +11 -8
  89. package/json/dist/index.d.mts +41 -2
  90. package/json/dist/index.d.ts +41 -2
  91. package/json/dist/index.js +88 -48
  92. package/json/dist/index.js.map +1 -1
  93. package/json/dist/index.mjs +76 -13
  94. package/json/dist/index.mjs.map +1 -1
  95. package/json/src/index.ts +5 -0
  96. package/json/src/select-json-family.ts +35 -0
  97. package/json/src/select-json.ts +22 -0
  98. package/package.json +105 -57
  99. package/react/dist/index.d.mts +9 -17
  100. package/react/dist/index.d.ts +9 -17
  101. package/react/dist/index.js +45 -77
  102. package/react/dist/index.js.map +1 -1
  103. package/react/dist/index.mjs +18 -34
  104. package/react/dist/index.mjs.map +1 -1
  105. package/react/src/store-context.tsx +12 -0
  106. package/react/src/store-hooks.ts +36 -0
  107. package/react-devtools/dist/index.css +1 -1
  108. package/react-devtools/dist/index.css.map +1 -1
  109. package/react-devtools/dist/index.d.mts +199 -230
  110. package/react-devtools/dist/index.d.ts +199 -230
  111. package/react-devtools/dist/index.js +610 -2466
  112. package/react-devtools/dist/index.js.map +1 -1
  113. package/react-devtools/dist/index.mjs +543 -2401
  114. package/react-devtools/dist/index.mjs.map +1 -1
  115. package/{src/react-devtools → react-devtools/src}/AtomIODevtools.tsx +5 -3
  116. package/{src/react-devtools → react-devtools/src}/Button.tsx +2 -3
  117. package/{src/react-devtools → react-devtools/src}/StateEditor.tsx +3 -2
  118. package/{src/react-devtools → react-devtools/src}/StateIndex.tsx +7 -4
  119. package/{src/react-devtools → react-devtools/src}/TimelineIndex.tsx +7 -11
  120. package/{src/react-devtools → react-devtools/src}/TransactionIndex.tsx +4 -4
  121. package/{src/react-devtools → react-devtools/src}/Updates.tsx +9 -4
  122. package/{src/react-devtools → react-devtools/src}/index.ts +5 -5
  123. package/realtime-react/dist/index.d.mts +9 -25
  124. package/realtime-react/dist/index.d.ts +9 -25
  125. package/realtime-react/dist/index.js +75 -193
  126. package/realtime-react/dist/index.js.map +1 -1
  127. package/realtime-react/dist/index.mjs +44 -148
  128. package/realtime-react/dist/index.mjs.map +1 -1
  129. package/realtime-react/src/index.ts +7 -0
  130. package/{src/realtime-react → realtime-react/src}/realtime-context.tsx +3 -4
  131. package/realtime-react/src/use-pull-family-member.ts +15 -0
  132. package/realtime-react/src/use-pull-mutable-family-member.ts +20 -0
  133. package/realtime-react/src/use-pull-mutable.ts +17 -0
  134. package/realtime-react/src/use-pull.ts +15 -0
  135. package/realtime-react/src/use-push.ts +19 -0
  136. package/realtime-react/src/use-server-action.ts +18 -0
  137. package/realtime-testing/dist/index.d.mts +49 -0
  138. package/realtime-testing/dist/index.d.ts +49 -0
  139. package/realtime-testing/dist/index.js +147 -0
  140. package/realtime-testing/dist/index.js.map +1 -0
  141. package/realtime-testing/dist/index.mjs +116 -0
  142. package/realtime-testing/dist/index.mjs.map +1 -0
  143. package/{src/realtime-testing → realtime-testing/src}/setup-realtime-test.tsx +10 -8
  144. package/src/atom.ts +64 -8
  145. package/src/index.ts +36 -29
  146. package/src/logger.ts +7 -7
  147. package/src/selector.ts +5 -5
  148. package/src/silo.ts +49 -43
  149. package/src/subscribe.ts +27 -22
  150. package/src/timeline.ts +9 -4
  151. package/src/transaction.ts +3 -4
  152. package/transceivers/set-rtx/dist/index.d.mts +39 -0
  153. package/transceivers/set-rtx/dist/index.d.ts +39 -0
  154. package/transceivers/set-rtx/dist/index.js +213 -0
  155. package/transceivers/set-rtx/dist/index.js.map +1 -0
  156. package/transceivers/set-rtx/dist/index.mjs +211 -0
  157. package/transceivers/set-rtx/dist/index.mjs.map +1 -0
  158. package/{realtime → transceivers/set-rtx}/package.json +1 -1
  159. package/transceivers/set-rtx/src/index.ts +1 -0
  160. package/transceivers/set-rtx/src/set-rtx.ts +242 -0
  161. package/realtime/dist/index.d.mts +0 -25
  162. package/realtime/dist/index.d.ts +0 -25
  163. package/realtime/dist/index.js +0 -190
  164. package/realtime/dist/index.js.map +0 -1
  165. package/realtime/dist/index.mjs +0 -151
  166. package/realtime/dist/index.mjs.map +0 -1
  167. package/src/internal/atom-internal.ts +0 -54
  168. package/src/internal/families-internal.ts +0 -144
  169. package/src/internal/get.ts +0 -129
  170. package/src/internal/index.ts +0 -15
  171. package/src/internal/operation.ts +0 -139
  172. package/src/internal/selector/lookup-selector-sources.ts +0 -16
  173. package/src/internal/selector-internal.ts +0 -58
  174. package/src/internal/set.ts +0 -99
  175. package/src/internal/store.ts +0 -151
  176. package/src/internal/subscribe-internal.ts +0 -88
  177. package/src/internal/timeline/index.ts +0 -1
  178. package/src/introspection/attach-selector-index.ts +0 -77
  179. package/src/introspection/attach-timeline-index.ts +0 -36
  180. package/src/introspection/attach-transaction-index.ts +0 -38
  181. package/src/json/index.ts +0 -1
  182. package/src/json/select-json.ts +0 -18
  183. package/src/react/store-context.tsx +0 -13
  184. package/src/react/store-hooks.ts +0 -47
  185. package/src/react-explorer/AtomIOExplorer.tsx +0 -218
  186. package/src/react-explorer/explorer-effects.ts +0 -20
  187. package/src/react-explorer/explorer-states.ts +0 -217
  188. package/src/react-explorer/index.ts +0 -23
  189. package/src/react-explorer/space-states.ts +0 -72
  190. package/src/react-explorer/view-states.ts +0 -41
  191. package/src/realtime/README.md +0 -33
  192. package/src/realtime/hook-composition/expose-family.ts +0 -101
  193. package/src/realtime/hook-composition/expose-single.ts +0 -38
  194. package/src/realtime/hook-composition/expose-timeline.ts +0 -60
  195. package/src/realtime/hook-composition/index.ts +0 -12
  196. package/src/realtime/hook-composition/receive-state.ts +0 -29
  197. package/src/realtime/hook-composition/receive-transaction.ts +0 -18
  198. package/src/realtime/index.ts +0 -1
  199. package/src/realtime-react/index.ts +0 -3
  200. package/src/realtime-react/realtime-hooks.ts +0 -39
  201. package/src/realtime-react/realtime-state.ts +0 -10
  202. package/src/realtime-react/use-pull-family-member.ts +0 -26
  203. package/src/realtime-react/use-pull-family.ts +0 -24
  204. package/src/realtime-react/use-pull.ts +0 -24
  205. package/src/realtime-react/use-push.ts +0 -27
  206. package/src/realtime-react/use-server-action.ts +0 -33
  207. package/src/tracker/index.ts +0 -3
  208. package/src/tracker/tracker.ts +0 -61
  209. package/src/web-effects/index.ts +0 -1
  210. package/src/web-effects/storage.ts +0 -30
  211. /package/{src/introspection → introspection/src}/index.ts +0 -0
  212. /package/{src/react → react/src}/index.ts +0 -0
  213. /package/{src/react-devtools → react-devtools/src}/devtools.scss +0 -0
  214. /package/{src/realtime-testing → realtime-testing/src}/index.ts +0 -0
@@ -0,0 +1,154 @@
1
+ import type {
2
+ AtomFamily,
3
+ AtomToken,
4
+ Logger,
5
+ ReadonlySelectorFamily,
6
+ ReadonlySelectorToken,
7
+ SelectorFamily,
8
+ SelectorToken,
9
+ TimelineToken,
10
+ TransactionToken,
11
+ ƒn,
12
+ } from "atom.io"
13
+
14
+ import { Junction } from "~/packages/rel8/junction/src"
15
+
16
+ import type { Atom } from "../atom"
17
+ import type { MutableAtom, Tracker, Transceiver } from "../mutable"
18
+ import type { OperationProgress } from "../operation"
19
+ import type { ReadonlySelector, Selector } from "../selector"
20
+ import { Subject } from "../subject"
21
+ import type { Timeline } from "../timeline"
22
+ import type { Transaction, TransactionStatus } from "../transaction"
23
+
24
+ export type StoreCore = Pick<
25
+ Store,
26
+ | `atoms`
27
+ | `atomsThatAreDefault`
28
+ | `families`
29
+ | `operation`
30
+ | `readonlySelectors`
31
+ | `selectorAtoms`
32
+ | `selectorGraph`
33
+ | `selectors`
34
+ | `timelineAtoms`
35
+ | `timelines`
36
+ | `trackers`
37
+ | `transactions`
38
+ | `valueMap`
39
+ >
40
+
41
+ export class Store {
42
+ public valueMap = new Map<string, any>()
43
+
44
+ public atoms = new Map<string, Atom<any> | MutableAtom<any>>()
45
+ public selectors = new Map<string, Selector<any>>()
46
+ public readonlySelectors = new Map<string, ReadonlySelector<any>>()
47
+
48
+ public trackers = new Map<string, Tracker<Transceiver<any>>>()
49
+ public families = new Map<
50
+ string,
51
+ | AtomFamily<any, any>
52
+ | ReadonlySelectorFamily<any, any>
53
+ | SelectorFamily<any, any>
54
+ >()
55
+
56
+ public timelines = new Map<string, Timeline>()
57
+ public transactions = new Map<string, Transaction<ƒn>>()
58
+
59
+ public atomsThatAreDefault = new Set<string>()
60
+
61
+ public timelineAtoms = new Junction({
62
+ between: [`timelineKey`, `atomKey`],
63
+ cardinality: `1:n`,
64
+ })
65
+ public selectorAtoms = new Junction({
66
+ between: [`selectorKey`, `atomKey`],
67
+ cardinality: `n:n`,
68
+ })
69
+ public selectorGraph = new Junction<
70
+ `upstreamSelectorKey`,
71
+ `downstreamSelectorKey`,
72
+ { source: string }
73
+ >(
74
+ {
75
+ between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
76
+ cardinality: `n:n`,
77
+ },
78
+ {
79
+ makeContentKey: (...keys) => keys.sort().join(`:`),
80
+ },
81
+ )
82
+
83
+ public subject = {
84
+ atomCreation: new Subject<AtomToken<unknown>>(),
85
+ selectorCreation: new Subject<
86
+ ReadonlySelectorToken<unknown> | SelectorToken<unknown>
87
+ >(),
88
+ transactionCreation: new Subject<TransactionToken<ƒn>>(),
89
+ timelineCreation: new Subject<TimelineToken>(),
90
+ operationStatus: new Subject<OperationProgress>(),
91
+ }
92
+ public operation: OperationProgress = { open: false }
93
+ public transactionStatus: TransactionStatus<ƒn> = { phase: `idle` }
94
+
95
+ public config: {
96
+ name: string
97
+ logger: Logger | null
98
+ logger__INTERNAL: Logger
99
+ } = {
100
+ name: `IMPLICIT_STORE`,
101
+ logger: { ...console, info: () => undefined },
102
+ logger__INTERNAL: console,
103
+ }
104
+
105
+ public constructor(name: string, store: Store | null = null) {
106
+ if (store !== null) {
107
+ this.valueMap = new Map(store?.valueMap)
108
+
109
+ this.operation = { ...store?.operation }
110
+ this.transactionStatus = { ...store?.transactionStatus }
111
+ this.config = {
112
+ ...store?.config,
113
+ logger__INTERNAL: console,
114
+ logger: {
115
+ ...console,
116
+ info: () => undefined,
117
+ ...store?.config?.logger,
118
+ },
119
+ name,
120
+ }
121
+ }
122
+
123
+ store?.atoms.forEach((atom) => {
124
+ atom.install(this)
125
+ })
126
+ store?.readonlySelectors.forEach((selector) => {
127
+ selector.install(this)
128
+ })
129
+ store?.selectors.forEach((selector) => {
130
+ selector.install(this)
131
+ })
132
+ store?.transactions.forEach((tx) => {
133
+ tx.install(this)
134
+ })
135
+ store?.timelines.forEach((timeline) => {
136
+ timeline.install(this)
137
+ })
138
+ }
139
+ }
140
+
141
+ export const IMPLICIT = {
142
+ STORE_INTERNAL: undefined as Store | undefined,
143
+ get STORE(): Store {
144
+ return (
145
+ this.STORE_INTERNAL ?? (this.STORE_INTERNAL = new Store(`IMPLICIT_STORE`))
146
+ )
147
+ },
148
+ }
149
+
150
+ export const clearStore = (store: Store = IMPLICIT.STORE): void => {
151
+ const { config } = store
152
+ Object.assign(store, new Store(config.name))
153
+ store.config = config
154
+ }
@@ -0,0 +1,53 @@
1
+ import type {
2
+ AtomToken,
3
+ ReadonlySelectorToken,
4
+ SelectorToken,
5
+ StateToken,
6
+ } from "atom.io"
7
+ import type { Atom, ReadonlySelector, Selector, Store } from ".."
8
+ import { withdraw } from ".."
9
+ import { target } from "../transaction"
10
+
11
+ export function withdrawNewFamilyMember<T>(
12
+ token: AtomToken<T>,
13
+ store: Store,
14
+ ): Atom<T> | null
15
+ export function withdrawNewFamilyMember<T>(
16
+ token: SelectorToken<T>,
17
+ store: Store,
18
+ ): Selector<T> | null
19
+ export function withdrawNewFamilyMember<T>(
20
+ token: ReadonlySelectorToken<T>,
21
+ store: Store,
22
+ ): ReadonlySelector<T> | null
23
+ export function withdrawNewFamilyMember<T>(
24
+ token: StateToken<T>,
25
+ store: Store,
26
+ ): Atom<T> | Selector<T> | null
27
+ export function withdrawNewFamilyMember<T>(
28
+ token: ReadonlySelectorToken<T> | StateToken<T>,
29
+ store: Store,
30
+ ): Atom<T> | ReadonlySelector<T> | Selector<T> | null
31
+ export function withdrawNewFamilyMember<T>(
32
+ token:
33
+ | AtomToken<T>
34
+ | ReadonlySelectorToken<T>
35
+ | SelectorToken<T>
36
+ | StateToken<T>,
37
+ store: Store,
38
+ ): Atom<T> | ReadonlySelector<T> | Selector<T> | null {
39
+ store.config.logger?.info(
40
+ `👪 creating new family member "${token.key}" in store "${store.config.name}"`,
41
+ )
42
+ if (token.family) {
43
+ const core = target(store)
44
+ const family = core.families.get(token.family.key)
45
+ if (family) {
46
+ const jsonSubKey = JSON.parse(token.family.subKey)
47
+ family(jsonSubKey)
48
+ const state = withdraw(token, store)
49
+ return state
50
+ }
51
+ }
52
+ return null
53
+ }
@@ -0,0 +1,113 @@
1
+ import type {
2
+ AtomToken,
3
+ ReadonlySelectorToken,
4
+ SelectorToken,
5
+ StateToken,
6
+ TimelineToken,
7
+ TransactionToken,
8
+ ƒn,
9
+ } from "atom.io"
10
+
11
+ import type { Atom } from "../atom"
12
+ import type { ReadonlySelector, Selector } from "../selector"
13
+ import { addAtomToTimeline } from "../timeline"
14
+ import type { Timeline } from "../timeline"
15
+ import type { Transaction } from "../transaction"
16
+ import { target } from "../transaction"
17
+ import type { Store } from "./store"
18
+
19
+ export function withdraw<T>(token: AtomToken<T>, store: Store): Atom<T> | null
20
+ export function withdraw<T>(
21
+ token: SelectorToken<T>,
22
+ store: Store,
23
+ ): Selector<T> | null
24
+ export function withdraw<T>(
25
+ token: StateToken<T>,
26
+ store: Store,
27
+ ): Atom<T> | Selector<T> | null
28
+ export function withdraw<T>(
29
+ token: ReadonlySelectorToken<T>,
30
+ store: Store,
31
+ ): ReadonlySelector<T> | null
32
+ export function withdraw<T>(
33
+ token: TransactionToken<T>,
34
+ store: Store,
35
+ ): Transaction<T extends ƒn ? T : never> | null
36
+ export function withdraw<T>(
37
+ token: ReadonlySelectorToken<T> | StateToken<T>,
38
+ store: Store,
39
+ ): Atom<T> | ReadonlySelector<T> | Selector<T> | null
40
+ export function withdraw<T>(token: TimelineToken, store: Store): Timeline | null
41
+ export function withdraw<T>(
42
+ token:
43
+ | ReadonlySelectorToken<T>
44
+ | StateToken<T>
45
+ | TimelineToken
46
+ | TransactionToken<T>,
47
+ store: Store,
48
+ ):
49
+ | Atom<T>
50
+ | ReadonlySelector<T>
51
+ | Selector<T>
52
+ | Timeline
53
+ | Transaction<T extends ƒn ? T : never>
54
+ | null {
55
+ let core = target(store)
56
+ let state =
57
+ core.atoms.get(token.key) ??
58
+ core.selectors.get(token.key) ??
59
+ core.readonlySelectors.get(token.key) ??
60
+ core.transactions.get(token.key) ??
61
+ core.timelines.get(token.key)
62
+ if (state) {
63
+ return state
64
+ }
65
+ if (store.transactionStatus.phase === `applying`) {
66
+ core = store.transactionStatus.core
67
+ state =
68
+ core.atoms.get(token.key) ??
69
+ core.selectors.get(token.key) ??
70
+ core.readonlySelectors.get(token.key) ??
71
+ core.transactions.get(token.key) ??
72
+ core.timelines.get(token.key)
73
+
74
+ if (state) {
75
+ store.config.logger?.info(`🛠️ add ${token.type} "${token.key}"`)
76
+ switch (state.type) {
77
+ case `atom`: {
78
+ store.atoms.set(token.key, state)
79
+ store.valueMap.set(token.key, state.default)
80
+ const stateKey = state.key
81
+ const familyKey = state.family?.key
82
+ let timelineKey = core.timelineAtoms.getRelatedKey(stateKey)
83
+ if (timelineKey === undefined && typeof familyKey === `string`) {
84
+ timelineKey = core.timelineAtoms.getRelatedKey(familyKey)
85
+ }
86
+ const timeline =
87
+ typeof timelineKey === `string`
88
+ ? store.timelines.get(timelineKey)
89
+ : undefined
90
+
91
+ if (timeline) {
92
+ addAtomToTimeline(state, timeline, store)
93
+ }
94
+ break
95
+ }
96
+ case `selector`:
97
+ core.selectors.set(token.key, state)
98
+ break
99
+ case `readonly_selector`:
100
+ core.readonlySelectors.set(token.key, state)
101
+ break
102
+ case `transaction`:
103
+ core.transactions.set(token.key, state)
104
+ break
105
+ case `timeline`:
106
+ core.timelines.set(token.key, state)
107
+ break
108
+ }
109
+ return state
110
+ }
111
+ }
112
+ return null
113
+ }
@@ -0,0 +1,21 @@
1
+ export class Subject<T> {
2
+ public Subscriber: (value: T) => void
3
+
4
+ public subscribers: Map<string, this[`Subscriber`]> = new Map()
5
+
6
+ public subscribe(key: string, subscriber: this[`Subscriber`]): () => void {
7
+ this.subscribers.set(key, subscriber)
8
+ const unsubscribe = () => this.unsubscribe(key)
9
+ return unsubscribe
10
+ }
11
+
12
+ private unsubscribe(key: string) {
13
+ this.subscribers.delete(key)
14
+ }
15
+
16
+ public next(value: T): void {
17
+ for (const subscriber of this.subscribers.values()) {
18
+ subscriber(value)
19
+ }
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ export * from "./subscribe-to-root-atoms"
@@ -0,0 +1,19 @@
1
+ import type { Atom } from "../atom"
2
+ import type { ReadonlySelector, Selector } from "../selector"
3
+ import type { Store } from "../store"
4
+ import { IMPLICIT } from "../store"
5
+ import { target } from "../transaction"
6
+
7
+ export const recallState = <T>(
8
+ state: Atom<T> | ReadonlySelector<T> | Selector<T>,
9
+ store: Store = IMPLICIT.STORE,
10
+ ): T => {
11
+ const core = target(store)
12
+ if (!core.operation.open) {
13
+ store.config.logger?.warn(
14
+ `recall called outside of an operation. This is probably a bug.`,
15
+ )
16
+ return core.valueMap.get(state.key)
17
+ }
18
+ return core.operation.prev.get(state.key)
19
+ }
@@ -0,0 +1,47 @@
1
+ import { getState__INTERNAL } from "../get-state-internal"
2
+ import type { ReadonlySelector, Selector } from "../selector"
3
+ import { traceAllSelectorAtoms } from "../selector"
4
+ import type { Store } from "../store"
5
+ import { withdraw } from "../store"
6
+ import { recallState } from "./recall-state"
7
+
8
+ export const subscribeToRootAtoms = <T>(
9
+ state: ReadonlySelector<T> | Selector<T>,
10
+ store: Store,
11
+ ): (() => void)[] | null => {
12
+ const dependencySubscriptions =
13
+ `default` in state
14
+ ? null
15
+ : traceAllSelectorAtoms(state.key, store).map((atomToken) => {
16
+ const atom = withdraw(atomToken, store)
17
+ if (atom === null) {
18
+ throw new Error(
19
+ `Atom "${atomToken.key}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`,
20
+ )
21
+ }
22
+ return atom.subject.subscribe(
23
+ `${state.type}:${state.key}`,
24
+ (atomChange) => {
25
+ store.config.logger?.info(
26
+ `📢 selector "${state.key}" saw root "${atomToken.key}" go (`,
27
+ atomChange.oldValue,
28
+ `->`,
29
+ atomChange.newValue,
30
+ `)`,
31
+ )
32
+ const oldValue = recallState(state, store)
33
+ // ❗ this retrieves a stale cached value when applying a transaction on the server
34
+ const newValue = getState__INTERNAL(state, store)
35
+ store.config.logger?.info(
36
+ ` <- "${state.key}" went (`,
37
+ oldValue,
38
+ `->`,
39
+ newValue,
40
+ `)`,
41
+ )
42
+ state.subject.next({ newValue, oldValue })
43
+ },
44
+ )
45
+ })
46
+ return dependencySubscriptions
47
+ }
@@ -1,15 +1,16 @@
1
- import { IMPLICIT, withdraw } from ".."
1
+ import type { AtomToken, TimelineUpdate } from "atom.io"
2
+
3
+ import type { Store } from "../store"
4
+ import { IMPLICIT, withdraw } from "../store"
5
+ import { target } from "../transaction"
2
6
  import type {
3
7
  Timeline,
4
- Store,
5
- TimelineTransactionUpdate,
6
8
  TimelineAtomUpdate,
7
- } from ".."
8
- import type { AtomFamily, AtomToken, TimelineUpdate } from "../.."
9
+ TimelineTransactionUpdate,
10
+ } from "./timeline-internal"
9
11
 
10
12
  export const addAtomToTimeline = (
11
13
  atomToken: AtomToken<any>,
12
- atoms: (AtomFamily<any> | AtomToken<any>)[],
13
14
  tl: Timeline,
14
15
  store: Store = IMPLICIT.STORE,
15
16
  ): void => {
@@ -19,7 +20,7 @@ export const addAtomToTimeline = (
19
20
  `Cannot subscribe to atom "${atomToken.key}" because it has not been initialized in store "${store.config.name}"`,
20
21
  )
21
22
  }
22
- atom.subject.subscribe((update) => {
23
+ atom.subject.subscribe(`timeline`, (update) => {
23
24
  const currentSelectorKey =
24
25
  store.operation.open && store.operation.token.type === `selector`
25
26
  ? store.operation.token.key
@@ -78,29 +79,46 @@ export const addAtomToTimeline = (
78
79
  )
79
80
  }
80
81
  tl.transactionKey = currentTransactionKey
81
- const subscription = currentTransaction.subject.subscribe((update) => {
82
- subscription.unsubscribe()
83
- if (tl.timeTraveling === null && currentTransactionTime) {
84
- if (tl.at !== tl.history.length) {
85
- tl.history.splice(tl.at)
86
- }
87
- const timelineTransactionUpdate: TimelineTransactionUpdate = {
88
- type: `transaction_update`,
89
- timestamp: currentTransactionTime,
90
- ...update,
91
- atomUpdates: update.atomUpdates.filter((atomUpdate) =>
92
- atoms.some((atom) => atom.key === atomUpdate.key),
93
- ),
82
+ const unsubscribe = currentTransaction.subject.subscribe(
83
+ `timeline:${tl.key}`,
84
+ (update) => {
85
+ unsubscribe()
86
+ if (tl.timeTraveling === null && currentTransactionTime) {
87
+ if (tl.at !== tl.history.length) {
88
+ tl.history.splice(tl.at)
89
+ }
90
+
91
+ const atomUpdates = update.atomUpdates.filter((atomUpdate) => {
92
+ const core = target(store)
93
+ const atomOrFamilyKeys = core.timelineAtoms.getRelatedKeys(
94
+ tl.key,
95
+ )
96
+
97
+ return atomOrFamilyKeys
98
+ ? [...atomOrFamilyKeys].some(
99
+ (key) =>
100
+ key === atomUpdate.key ||
101
+ key === atomUpdate.family?.key,
102
+ )
103
+ : false
104
+ })
105
+
106
+ const timelineTransactionUpdate: TimelineTransactionUpdate = {
107
+ type: `transaction_update`,
108
+ timestamp: currentTransactionTime,
109
+ ...update,
110
+ atomUpdates,
111
+ }
112
+ tl.history.push(timelineTransactionUpdate)
113
+ tl.at = tl.history.length
114
+ tl.subject.next(timelineTransactionUpdate)
94
115
  }
95
- tl.history.push(timelineTransactionUpdate)
96
- tl.at = tl.history.length
97
- tl.subject.next(timelineTransactionUpdate)
98
- }
99
- tl.transactionKey = null
100
- store.config.logger?.info(
101
- `⌛ timeline "${tl.key}" got a transaction_update "${update.key}"`,
102
- )
103
- })
116
+ tl.transactionKey = null
117
+ store.config.logger?.info(
118
+ `⌛ timeline "${tl.key}" got a transaction_update "${update.key}"`,
119
+ )
120
+ },
121
+ )
104
122
  }
105
123
  } else if (currentSelectorKey && currentSelectorTime) {
106
124
  let latestUpdate: TimelineUpdate | undefined = tl.history.at(-1)
@@ -156,6 +174,9 @@ export const addAtomToTimeline = (
156
174
  oldValue: update.oldValue,
157
175
  newValue: update.newValue,
158
176
  }
177
+ if (atom.family) {
178
+ atomUpdate.family = atom.family
179
+ }
159
180
  tl.history.push(atomUpdate)
160
181
  tl.subject.next(atomUpdate)
161
182
  store.config.logger?.info(
@@ -0,0 +1,3 @@
1
+ export * from "./add-atom-to-timeline"
2
+ export * from "./time-travel-internal"
3
+ export * from "./timeline-internal"
@@ -1,7 +1,8 @@
1
- import type { Store } from "."
2
- import { IMPLICIT } from "."
3
- import type { TimelineToken } from ".."
4
- import { setState } from ".."
1
+ import type { TimelineToken } from "atom.io"
2
+ import { setState } from "atom.io"
3
+
4
+ import type { Store } from "../store"
5
+ import { IMPLICIT } from "../store"
5
6
 
6
7
  export const redo__INTERNAL = (
7
8
  token: TimelineToken,
@@ -65,7 +66,6 @@ export const undo__INTERNAL = (
65
66
  return
66
67
  }
67
68
  timelineData.timeTraveling = `into_past`
68
-
69
69
  --timelineData.at
70
70
  const update = timelineData.history[timelineData.at]
71
71
  switch (update.type) {
@@ -76,7 +76,7 @@ export const undo__INTERNAL = (
76
76
  }
77
77
  case `selector_update`:
78
78
  case `transaction_update`: {
79
- for (const atomUpdate of update.atomUpdates) {
79
+ for (const atomUpdate of [...update.atomUpdates].reverse()) {
80
80
  const { key, oldValue } = atomUpdate
81
81
  setState({ key, type: `atom` }, oldValue, store)
82
82
  }
@@ -1,20 +1,24 @@
1
- import type { ƒn } from "~/packages/anvl/src/function"
2
-
3
- import type { Store } from "."
4
- import { Subject, target, IMPLICIT } from "."
5
- import { addAtomToTimeline } from "./timeline/add-atom-to-timeline"
6
1
  import type {
2
+ FamilyMetadata,
7
3
  StateUpdate,
8
4
  TimelineOptions,
9
5
  TimelineToken,
10
6
  TimelineUpdate,
11
7
  TransactionUpdate,
12
- } from ".."
8
+ ƒn,
9
+ } from "atom.io"
10
+
11
+ import type { Store } from "../store"
12
+ import { IMPLICIT } from "../store"
13
+ import { Subject } from "../subject"
14
+ import { target } from "../transaction"
15
+ import { addAtomToTimeline } from "./add-atom-to-timeline"
13
16
 
14
17
  export type TimelineAtomUpdate = StateUpdate<unknown> & {
15
18
  key: string
16
19
  type: `atom_update`
17
20
  timestamp: number
21
+ family?: FamilyMetadata
18
22
  }
19
23
  export type TimelineSelectorUpdate = {
20
24
  key: string
@@ -29,6 +33,7 @@ export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
29
33
  }
30
34
 
31
35
  export type Timeline = {
36
+ type: `timeline`
32
37
  key: string
33
38
  at: number
34
39
  timeTraveling: `into_future` | `into_past` | null
@@ -51,6 +56,7 @@ export function timeline__INTERNAL(
51
56
  data: Timeline | null = null,
52
57
  ): TimelineToken {
53
58
  const tl: Timeline = {
59
+ type: `timeline`,
54
60
  key: options.key,
55
61
  at: 0,
56
62
  timeTraveling: null,
@@ -64,7 +70,7 @@ export function timeline__INTERNAL(
64
70
 
65
71
  const core = target(store)
66
72
  for (const tokenOrFamily of options.atoms) {
67
- const timelineKey = core.timelineAtoms.getRelatedId(tokenOrFamily.key)
73
+ const timelineKey = core.timelineAtoms.getRelatedKey(tokenOrFamily.key)
68
74
  if (timelineKey) {
69
75
  store.config.logger?.error(
70
76
  `❌ Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`,
@@ -73,13 +79,15 @@ export function timeline__INTERNAL(
73
79
  }
74
80
  if (tokenOrFamily.type === `atom_family`) {
75
81
  const family = tokenOrFamily
76
- family.subject.subscribe((token) =>
77
- addAtomToTimeline(token, options.atoms, tl, store),
78
- )
82
+ family.subject.subscribe(`timeline:${options.key}`, (token) => {
83
+ if (!core.atoms.has(token.key)) {
84
+ addAtomToTimeline(token, tl, store)
85
+ }
86
+ })
79
87
  } else {
80
88
  const token = tokenOrFamily
81
89
  if (`family` in token && token.family) {
82
- const familyTimelineKey = core.timelineAtoms.getRelatedId(
90
+ const familyTimelineKey = core.timelineAtoms.getRelatedKey(
83
91
  token.family.key,
84
92
  )
85
93
  if (familyTimelineKey) {
@@ -89,7 +97,7 @@ export function timeline__INTERNAL(
89
97
  continue
90
98
  }
91
99
  }
92
- addAtomToTimeline(token, options.atoms, tl, store)
100
+ addAtomToTimeline(token, tl, store)
93
101
  }
94
102
  core.timelineAtoms = core.timelineAtoms.set({
95
103
  atomKey: tokenOrFamily.key,
@@ -1,4 +1,4 @@
1
- import type { Store } from ".."
1
+ import type { Store } from "../store"
2
2
 
3
3
  export const abortTransaction = (store: Store): void => {
4
4
  if (store.transactionStatus.phase === `idle`) {