atom.io 0.4.1 → 0.6.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 (101) hide show
  1. package/README.md +38 -10
  2. package/dist/index.d.mts +614 -0
  3. package/dist/index.d.ts +130 -77
  4. package/dist/index.js +584 -347
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +582 -347
  7. package/dist/index.mjs.map +1 -1
  8. package/json/dist/index.d.mts +18 -0
  9. package/json/dist/index.d.ts +18 -0
  10. package/json/dist/index.js +51 -0
  11. package/json/dist/index.js.map +1 -0
  12. package/json/dist/index.mjs +15 -0
  13. package/json/dist/index.mjs.map +1 -0
  14. package/json/package.json +15 -0
  15. package/package.json +43 -9
  16. package/react/dist/index.d.mts +24 -0
  17. package/react/dist/index.d.ts +18 -11
  18. package/react/dist/index.js +45 -21
  19. package/react/dist/index.js.map +1 -1
  20. package/react/dist/index.mjs +31 -21
  21. package/react/dist/index.mjs.map +1 -1
  22. package/react-devtools/dist/index.d.mts +15 -0
  23. package/react-devtools/dist/index.d.ts +4 -4
  24. package/react-devtools/dist/index.js +1 -1
  25. package/react-devtools/dist/index.js.map +1 -1
  26. package/react-devtools/dist/index.mjs +1 -1
  27. package/react-devtools/dist/index.mjs.map +1 -1
  28. package/realtime/dist/index.d.mts +27 -0
  29. package/realtime/dist/index.d.ts +27 -0
  30. package/realtime/dist/index.js +191 -0
  31. package/realtime/dist/index.js.map +1 -0
  32. package/realtime/dist/index.mjs +152 -0
  33. package/realtime/dist/index.mjs.map +1 -0
  34. package/realtime/package.json +15 -0
  35. package/realtime-react/dist/index.d.mts +45 -0
  36. package/realtime-react/dist/index.d.ts +45 -0
  37. package/realtime-react/dist/index.js +213 -0
  38. package/realtime-react/dist/index.js.map +1 -0
  39. package/realtime-react/dist/index.mjs +168 -0
  40. package/realtime-react/dist/index.mjs.map +1 -0
  41. package/realtime-react/package.json +15 -0
  42. package/src/index.ts +21 -5
  43. package/src/internal/atom-internal.ts +1 -1
  44. package/src/internal/families-internal.ts +3 -3
  45. package/src/internal/get.ts +39 -15
  46. package/src/internal/index.ts +2 -0
  47. package/src/internal/meta/meta-state.ts +1 -1
  48. package/src/internal/operation.ts +3 -1
  49. package/src/internal/selector/create-read-write-selector.ts +62 -0
  50. package/src/internal/selector/create-readonly-selector.ts +52 -0
  51. package/src/internal/selector/index.ts +4 -0
  52. package/src/internal/selector/lookup-selector-sources.ts +16 -0
  53. package/src/internal/selector/register-selector.ts +57 -0
  54. package/src/internal/selector/trace-selector-atoms.ts +43 -0
  55. package/src/internal/selector/update-selector-atoms.ts +33 -0
  56. package/src/internal/selector-internal.ts +9 -197
  57. package/src/internal/set.ts +1 -1
  58. package/src/internal/store.ts +44 -17
  59. package/src/internal/subscribe-internal.ts +6 -1
  60. package/src/internal/time-travel-internal.ts +7 -7
  61. package/src/internal/timeline/add-atom-to-timeline.ts +164 -0
  62. package/src/internal/timeline/index.ts +1 -0
  63. package/src/internal/timeline-internal.ts +39 -146
  64. package/src/internal/transaction/abort-transaction.ts +12 -0
  65. package/src/internal/transaction/apply-transaction.ts +54 -0
  66. package/src/internal/transaction/build-transaction.ts +33 -0
  67. package/src/internal/transaction/index.ts +25 -0
  68. package/src/internal/transaction/redo-transaction.ts +23 -0
  69. package/src/internal/transaction/undo-transaction.ts +23 -0
  70. package/src/internal/transaction-internal.ts +16 -133
  71. package/src/json/index.ts +1 -0
  72. package/src/json/select-json.ts +18 -0
  73. package/src/react/index.ts +2 -46
  74. package/src/react/store-context.tsx +14 -0
  75. package/src/react/store-hooks.ts +48 -0
  76. package/src/react-devtools/AtomIODevtools.tsx +1 -1
  77. package/src/react-explorer/AtomIOExplorer.tsx +2 -2
  78. package/src/react-explorer/explorer-states.ts +5 -5
  79. package/src/react-explorer/index.ts +1 -1
  80. package/src/react-explorer/space-states.ts +8 -9
  81. package/src/realtime/README.md +33 -0
  82. package/src/realtime/hook-composition/expose-family.ts +101 -0
  83. package/src/realtime/hook-composition/expose-single.ts +38 -0
  84. package/src/realtime/hook-composition/index.ts +12 -0
  85. package/src/realtime/hook-composition/receive-state.ts +29 -0
  86. package/src/realtime/hook-composition/receive-transaction.ts +18 -0
  87. package/src/realtime/index.ts +1 -0
  88. package/src/realtime-react/index.ts +3 -0
  89. package/src/realtime-react/realtime-context.tsx +31 -0
  90. package/src/realtime-react/realtime-hooks.ts +39 -0
  91. package/src/realtime-react/realtime-state.ts +10 -0
  92. package/src/realtime-react/use-pull-family-member.ts +27 -0
  93. package/src/realtime-react/use-pull-family.ts +25 -0
  94. package/src/realtime-react/use-pull.ts +23 -0
  95. package/src/realtime-react/use-push.ts +26 -0
  96. package/src/realtime-react/use-server-action.ts +34 -0
  97. package/src/selector.ts +9 -6
  98. package/src/silo.ts +53 -0
  99. package/src/subscribe.ts +42 -2
  100. package/src/timeline.ts +10 -0
  101. package/src/transaction.ts +24 -12
@@ -5,9 +5,11 @@ export * from "./is-default"
5
5
  export * as META from "./meta"
6
6
  export * from "./operation"
7
7
  export * from "./selector-internal"
8
+ export * from "./selector"
8
9
  export * from "./set"
9
10
  export * from "./store"
10
11
  export * from "./subscribe-internal"
11
12
  export * from "./time-travel-internal"
12
13
  export * from "./timeline-internal"
13
14
  export * from "./transaction-internal"
15
+ export * from "./transaction"
@@ -7,7 +7,7 @@ export type StateTokenIndex<
7
7
  Token extends
8
8
  | AtomToken<unknown>
9
9
  | ReadonlySelectorToken<unknown>
10
- | SelectorToken<unknown>
10
+ | SelectorToken<unknown>,
11
11
  > = Record<
12
12
  string,
13
13
  | Token
@@ -34,7 +34,9 @@ export const openOperation = (token: StateToken<any>, store: Store): void => {
34
34
  time: Date.now(),
35
35
  token,
36
36
  }
37
- store.config.logger?.info(`⭕ operation start from "${token.key}"`)
37
+ store.config.logger?.info(
38
+ `⭕ operation start from "${token.key}" in store "${store.config.name}"`
39
+ )
38
40
  }
39
41
  export const closeOperation = (store: Store): void => {
40
42
  const core = target(store)
@@ -0,0 +1,62 @@
1
+ import HAMT from "hamt_plus"
2
+ import * as Rx from "rxjs"
3
+
4
+ import { become } from "~/packages/anvl/src/function"
5
+
6
+ import {
7
+ type Store,
8
+ type Selector,
9
+ type StoreCore,
10
+ registerSelector,
11
+ selector__INTERNAL,
12
+ } from ".."
13
+ import type { FamilyMetadata, SelectorToken } from "../.."
14
+ import type { SelectorOptions } from "../../selector"
15
+ import { cacheValue, markDone } from "../operation"
16
+
17
+ export const createReadWriteSelector = <T>(
18
+ options: SelectorOptions<T>,
19
+ family: FamilyMetadata | undefined,
20
+ store: Store,
21
+ core: StoreCore
22
+ ): SelectorToken<T> => {
23
+ const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
24
+
25
+ const { get, set } = registerSelector(options.key, store)
26
+ const getSelf = () => {
27
+ const value = options.get({ get })
28
+ cacheValue(options.key, value, store)
29
+ return value
30
+ }
31
+
32
+ const setSelf = (next: T | ((oldValue: T) => T)): void => {
33
+ store.config.logger?.info(` <- "${options.key}" became`, next)
34
+ const oldValue = getSelf()
35
+ const newValue = become(next)(oldValue)
36
+ cacheValue(options.key, newValue, store)
37
+ markDone(options.key, store)
38
+ if (store.transactionStatus.phase === `idle`) {
39
+ subject.next({ newValue, oldValue })
40
+ }
41
+ options.set({ get, set }, newValue)
42
+ }
43
+ const mySelector: Selector<T> = {
44
+ ...options,
45
+ subject,
46
+ install: (s: Store) => selector__INTERNAL(options, family, s),
47
+ get: getSelf,
48
+ set: setSelf,
49
+ type: `selector`,
50
+ ...(family && { family }),
51
+ }
52
+ core.selectors = HAMT.set(options.key, mySelector, core.selectors)
53
+ const initialValue = getSelf()
54
+ store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
55
+ const token: SelectorToken<T> = {
56
+ key: options.key,
57
+ type: `selector`,
58
+ family,
59
+ }
60
+ store.subject.selectorCreation.next(token)
61
+ return token
62
+ }
@@ -0,0 +1,52 @@
1
+ import HAMT from "hamt_plus"
2
+ import * as Rx from "rxjs"
3
+
4
+ import { registerSelector } from "./register-selector"
5
+ import type {
6
+ FamilyMetadata,
7
+ ReadonlySelectorOptions,
8
+ ReadonlySelectorToken,
9
+ Store,
10
+ } from "../.."
11
+ import { cacheValue } from "../operation"
12
+ import { selector__INTERNAL, type ReadonlySelector } from "../selector-internal"
13
+ import type { StoreCore } from "../store"
14
+
15
+ export const createReadonlySelector = <T>(
16
+ options: ReadonlySelectorOptions<T>,
17
+ family: FamilyMetadata | undefined,
18
+ store: Store,
19
+ core: StoreCore
20
+ ): ReadonlySelectorToken<T> => {
21
+ const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
22
+
23
+ const { get } = registerSelector(options.key, store)
24
+ const getSelf = () => {
25
+ const value = options.get({ get })
26
+ cacheValue(options.key, value, store)
27
+ return value
28
+ }
29
+
30
+ const readonlySelector: ReadonlySelector<T> = {
31
+ ...options,
32
+ subject,
33
+ install: (s: Store) => selector__INTERNAL(options, family, s),
34
+ get: getSelf,
35
+ type: `readonly_selector`,
36
+ ...(family && { family }),
37
+ }
38
+ core.readonlySelectors = HAMT.set(
39
+ options.key,
40
+ readonlySelector,
41
+ core.readonlySelectors
42
+ )
43
+ const initialValue = getSelf()
44
+ store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
45
+ const token: ReadonlySelectorToken<T> = {
46
+ key: options.key,
47
+ type: `readonly_selector`,
48
+ family,
49
+ }
50
+ store.subject.selectorCreation.next(token)
51
+ return token
52
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./lookup-selector-sources"
2
+ export * from "./register-selector"
3
+ export * from "./trace-selector-atoms"
4
+ export * from "./update-selector-atoms"
@@ -0,0 +1,16 @@
1
+ import type { Store } from ".."
2
+ import { target, lookup } from ".."
3
+ import type { AtomToken, ReadonlySelectorToken, SelectorToken } from "../.."
4
+
5
+ export const lookupSelectorSources = (
6
+ key: string,
7
+ store: Store
8
+ ): (
9
+ | AtomToken<unknown>
10
+ | ReadonlySelectorToken<unknown>
11
+ | SelectorToken<unknown>
12
+ )[] =>
13
+ target(store)
14
+ .selectorGraph.getRelations(key)
15
+ .filter(({ source }) => source !== key)
16
+ .map(({ source }) => lookup(source, store))
@@ -0,0 +1,57 @@
1
+ import { updateSelectorAtoms } from "./update-selector-atoms"
2
+ import type { Transactors } from "../../transaction"
3
+ import { getState__INTERNAL, withdraw } from "../get"
4
+ import { setState__INTERNAL } from "../set"
5
+ import type { Store } from "../store"
6
+ import { IMPLICIT } from "../store"
7
+ import { target } from "../transaction-internal"
8
+
9
+ export const registerSelector = (
10
+ selectorKey: string,
11
+ store: Store = IMPLICIT.STORE
12
+ ): Transactors => ({
13
+ get: (dependency) => {
14
+ const core = target(store)
15
+ const alreadyRegistered = core.selectorGraph
16
+ .getRelations(selectorKey)
17
+ .some(({ source }) => source === dependency.key)
18
+
19
+ const dependencyState = withdraw(dependency, store)
20
+ if (dependencyState === null) {
21
+ throw new Error(
22
+ `State "${dependency.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
23
+ )
24
+ }
25
+ const dependencyValue = getState__INTERNAL(dependencyState, store)
26
+
27
+ if (alreadyRegistered) {
28
+ store.config.logger?.info(
29
+ ` || ${selectorKey} <- ${dependency.key} =`,
30
+ dependencyValue
31
+ )
32
+ } else {
33
+ store.config.logger?.info(
34
+ `🔌 registerSelector "${selectorKey}" <- ( "${dependency.key}" =`,
35
+ dependencyValue,
36
+ `)`
37
+ )
38
+ core.selectorGraph = core.selectorGraph.set(
39
+ { from: dependency.key, to: selectorKey },
40
+ {
41
+ source: dependency.key,
42
+ }
43
+ )
44
+ }
45
+ updateSelectorAtoms(selectorKey, dependency, store)
46
+ return dependencyValue
47
+ },
48
+ set: (stateToken, newValue) => {
49
+ const state = withdraw(stateToken, store)
50
+ if (state === null) {
51
+ throw new Error(
52
+ `State "${stateToken.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
53
+ )
54
+ }
55
+ setState__INTERNAL(state, newValue, store)
56
+ },
57
+ })
@@ -0,0 +1,43 @@
1
+ import { lookupSelectorSources } from "./lookup-selector-sources"
2
+ import type { Store, AtomToken, ReadonlySelectorToken, StateToken } from "../.."
3
+
4
+ export const traceSelectorAtoms = (
5
+ selectorKey: string,
6
+ dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
7
+ store: Store
8
+ ): AtomToken<unknown>[] => {
9
+ const roots: AtomToken<unknown>[] = []
10
+
11
+ const sources = lookupSelectorSources(dependency.key, store)
12
+ let depth = 0
13
+ while (sources.length > 0) {
14
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
15
+ const source = sources.shift()!
16
+ ++depth
17
+ if (depth > 999) {
18
+ throw new Error(
19
+ `Maximum selector dependency depth exceeded in selector "${selectorKey}".`
20
+ )
21
+ }
22
+
23
+ if (source.type !== `atom`) {
24
+ sources.push(...lookupSelectorSources(source.key, store))
25
+ } else {
26
+ roots.push(source)
27
+ }
28
+ }
29
+
30
+ return roots
31
+ }
32
+
33
+ export const traceAllSelectorAtoms = (
34
+ selectorKey: string,
35
+ store: Store
36
+ ): AtomToken<unknown>[] => {
37
+ const sources = lookupSelectorSources(selectorKey, store)
38
+ return sources.flatMap((source) =>
39
+ source.type === `atom`
40
+ ? source
41
+ : traceSelectorAtoms(selectorKey, source, store)
42
+ )
43
+ }
@@ -0,0 +1,33 @@
1
+ import { traceSelectorAtoms } from "./trace-selector-atoms"
2
+ import type { Store } from ".."
3
+ import { target } from ".."
4
+ import type { ReadonlySelectorToken, StateToken } from "../.."
5
+
6
+ export const updateSelectorAtoms = (
7
+ selectorKey: string,
8
+ dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
9
+ store: Store
10
+ ): void => {
11
+ const core = target(store)
12
+ if (dependency.type === `atom`) {
13
+ core.selectorAtoms = core.selectorAtoms.set({
14
+ selectorKey,
15
+ atomKey: dependency.key,
16
+ })
17
+ store.config.logger?.info(
18
+ ` || adding root for "${selectorKey}": ${dependency.key}`
19
+ )
20
+ return
21
+ }
22
+ const roots = traceSelectorAtoms(selectorKey, dependency, store)
23
+ store.config.logger?.info(
24
+ ` || adding roots for "${selectorKey}":`,
25
+ roots.map((r) => r.key)
26
+ )
27
+ for (const root of roots) {
28
+ core.selectorAtoms = core.selectorAtoms.set({
29
+ selectorKey,
30
+ atomKey: root.key,
31
+ })
32
+ }
33
+ }
@@ -1,34 +1,23 @@
1
1
  import HAMT from "hamt_plus"
2
- import * as Rx from "rxjs"
3
-
4
- import { become } from "~/packages/anvl/src/function"
2
+ import type * as Rx from "rxjs"
5
3
 
6
4
  import type { Store } from "."
7
- import {
8
- target,
9
- cacheValue,
10
- markDone,
11
- lookup,
12
- IMPLICIT,
13
- getState__INTERNAL,
14
- setState__INTERNAL,
15
- withdraw,
16
- } from "."
5
+ import { target, IMPLICIT } from "."
6
+ import { createReadWriteSelector } from "./selector/create-read-write-selector"
7
+ import { createReadonlySelector } from "./selector/create-readonly-selector"
17
8
  import type {
18
- AtomToken,
19
9
  FamilyMetadata,
20
10
  ReadonlySelectorOptions,
21
11
  ReadonlySelectorToken,
22
12
  SelectorOptions,
23
13
  SelectorToken,
24
- StateToken,
25
14
  } from ".."
26
- import type { Transactors } from "../transaction"
27
15
 
28
16
  export type Selector<T> = {
29
17
  key: string
30
18
  type: `selector`
31
19
  family?: FamilyMetadata
20
+ install: (store: Store) => void
32
21
  subject: Rx.Subject<{ newValue: T; oldValue: T }>
33
22
  get: () => T
34
23
  set: (newValue: T | ((oldValue: T) => T)) => void
@@ -37,133 +26,11 @@ export type ReadonlySelector<T> = {
37
26
  key: string
38
27
  type: `readonly_selector`
39
28
  family?: FamilyMetadata
29
+ install: (store: Store) => void
40
30
  subject: Rx.Subject<{ newValue: T; oldValue: T }>
41
31
  get: () => T
42
32
  }
43
33
 
44
- export const lookupSelectorSources = (
45
- key: string,
46
- store: Store
47
- ): (
48
- | AtomToken<unknown>
49
- | ReadonlySelectorToken<unknown>
50
- | SelectorToken<unknown>
51
- )[] =>
52
- target(store)
53
- .selectorGraph.getRelations(key)
54
- .filter(({ source }) => source !== key)
55
- .map(({ source }) => lookup(source, store))
56
-
57
- export const traceSelectorAtoms = (
58
- selectorKey: string,
59
- dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
60
- store: Store
61
- ): AtomToken<unknown>[] => {
62
- const roots: AtomToken<unknown>[] = []
63
-
64
- const sources = lookupSelectorSources(dependency.key, store)
65
- let depth = 0
66
- while (sources.length > 0) {
67
- /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
68
- const source = sources.shift()!
69
- ++depth
70
- if (depth > 999) {
71
- throw new Error(
72
- `Maximum selector dependency depth exceeded in selector "${selectorKey}".`
73
- )
74
- }
75
-
76
- if (source.type !== `atom`) {
77
- sources.push(...lookupSelectorSources(source.key, store))
78
- } else {
79
- roots.push(source)
80
- }
81
- }
82
-
83
- return roots
84
- }
85
-
86
- export const traceAllSelectorAtoms = (
87
- selectorKey: string,
88
- store: Store
89
- ): AtomToken<unknown>[] => {
90
- const sources = lookupSelectorSources(selectorKey, store)
91
- return sources.flatMap((source) =>
92
- source.type === `atom`
93
- ? source
94
- : traceSelectorAtoms(selectorKey, source, store)
95
- )
96
- }
97
-
98
- export const updateSelectorAtoms = (
99
- selectorKey: string,
100
- dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
101
- store: Store
102
- ): void => {
103
- const core = target(store)
104
- if (dependency.type === `atom`) {
105
- core.selectorAtoms = core.selectorAtoms.set({
106
- selectorKey,
107
- atomKey: dependency.key,
108
- })
109
- store.config.logger?.info(
110
- ` || adding root for "${selectorKey}": ${dependency.key}`
111
- )
112
- return
113
- }
114
- const roots = traceSelectorAtoms(selectorKey, dependency, store)
115
- store.config.logger?.info(
116
- ` || adding roots for "${selectorKey}":`,
117
- roots.map((r) => r.key)
118
- )
119
- for (const root of roots) {
120
- core.selectorAtoms = core.selectorAtoms.set({
121
- selectorKey,
122
- atomKey: root.key,
123
- })
124
- }
125
- }
126
-
127
- export const registerSelector = (
128
- selectorKey: string,
129
- store: Store = IMPLICIT.STORE
130
- ): Transactors => ({
131
- get: (dependency) => {
132
- const core = target(store)
133
- const alreadyRegistered = core.selectorGraph
134
- .getRelations(selectorKey)
135
- .some(({ source }) => source === dependency.key)
136
-
137
- const dependencyState = withdraw(dependency, store)
138
- const dependencyValue = getState__INTERNAL(dependencyState, store)
139
-
140
- if (alreadyRegistered) {
141
- store.config.logger?.info(
142
- ` || ${selectorKey} <- ${dependency.key} =`,
143
- dependencyValue
144
- )
145
- } else {
146
- store.config.logger?.info(
147
- `🔌 registerSelector "${selectorKey}" <- ( "${dependency.key}" =`,
148
- dependencyValue,
149
- `)`
150
- )
151
- core.selectorGraph = core.selectorGraph.set(
152
- { from: dependency.key, to: selectorKey },
153
- {
154
- source: dependency.key,
155
- }
156
- )
157
- }
158
- updateSelectorAtoms(selectorKey, dependency, store)
159
- return dependencyValue
160
- },
161
- set: (stateToken, newValue) => {
162
- const state = withdraw(stateToken, store)
163
- setState__INTERNAL(state, newValue, store)
164
- },
165
- })
166
-
167
34
  export function selector__INTERNAL<T>(
168
35
  options: SelectorOptions<T>,
169
36
  family?: FamilyMetadata,
@@ -180,70 +47,15 @@ export function selector__INTERNAL<T>(
180
47
  store: Store = IMPLICIT.STORE
181
48
  ): ReadonlySelectorToken<T> | SelectorToken<T> {
182
49
  const core = target(store)
50
+
183
51
  if (HAMT.has(options.key, core.selectors)) {
184
52
  store.config.logger?.error(
185
53
  `Key "${options.key}" already exists in the store.`
186
54
  )
187
55
  }
188
56
 
189
- const subject = new Rx.Subject<{ newValue: T; oldValue: T }>()
190
-
191
- const { get, set } = registerSelector(options.key, store)
192
- const getSelf = () => {
193
- const value = options.get({ get })
194
- cacheValue(options.key, value, store)
195
- return value
196
- }
197
57
  if (!(`set` in options)) {
198
- const readonlySelector: ReadonlySelector<T> = {
199
- ...options,
200
- subject,
201
- get: getSelf,
202
- type: `readonly_selector`,
203
- ...(family && { family }),
204
- }
205
- core.readonlySelectors = HAMT.set(
206
- options.key,
207
- readonlySelector,
208
- core.readonlySelectors
209
- )
210
- const initialValue = getSelf()
211
- store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
212
- const token: ReadonlySelectorToken<T> = {
213
- key: options.key,
214
- type: `readonly_selector`,
215
- family,
216
- }
217
- store.subject.selectorCreation.next(token)
218
- return token
219
- }
220
- const setSelf = (next: T | ((oldValue: T) => T)): void => {
221
- store.config.logger?.info(` <- "${options.key}" became`, next)
222
- const oldValue = getSelf()
223
- const newValue = become(next)(oldValue)
224
- cacheValue(options.key, newValue, store)
225
- markDone(options.key, store)
226
- if (store.transactionStatus.phase === `idle`) {
227
- subject.next({ newValue, oldValue })
228
- }
229
- options.set({ get, set }, newValue)
230
- }
231
- const mySelector: Selector<T> = {
232
- ...options,
233
- subject,
234
- get: getSelf,
235
- set: setSelf,
236
- type: `selector`,
237
- ...(family && { family }),
238
- }
239
- core.selectors = HAMT.set(options.key, mySelector, core.selectors)
240
- const initialValue = getSelf()
241
- store.config.logger?.info(` ✨ "${options.key}" =`, initialValue)
242
- const token: SelectorToken<T> = {
243
- key: options.key,
244
- type: `selector`,
245
- family,
58
+ return createReadonlySelector(options, family, store, core)
246
59
  }
247
- store.subject.selectorCreation.next(token)
248
- return token
60
+ return createReadWriteSelector(options, family, store, core)
249
61
  }
@@ -61,7 +61,7 @@ export const setAtomState = <T>(
61
61
  const newValue = become(next)(oldValue)
62
62
  store.config.logger?.info(`<< setting atom "${atom.key}" to`, newValue)
63
63
  cacheValue(atom.key, newValue, store)
64
- if (isAtomDefault(atom.key)) {
64
+ if (isAtomDefault(atom.key, store)) {
65
65
  markAtomAsNotDefault(atom.key, store)
66
66
  }
67
67
  markDone(atom.key, store)
@@ -2,6 +2,7 @@ import type { Hamt } from "hamt_plus"
2
2
  import HAMT from "hamt_plus"
3
3
  import * as Rx from "rxjs"
4
4
 
5
+ import type { ƒn } from "~/packages/anvl/src/function"
5
6
  import { doNothing } from "~/packages/anvl/src/function"
6
7
  import { Join } from "~/packages/anvl/src/join"
7
8
 
@@ -12,7 +13,7 @@ import type {
12
13
  Selector,
13
14
  TransactionStatus,
14
15
  Timeline,
15
- TimelineData,
16
+ Transaction,
16
17
  } from "."
17
18
  import type {
18
19
  AtomToken,
@@ -20,9 +21,7 @@ import type {
20
21
  ReadonlySelectorToken,
21
22
  SelectorToken,
22
23
  TimelineToken,
23
- Transaction,
24
24
  TransactionToken,
25
- ƒn,
26
25
  } from ".."
27
26
 
28
27
  export type StoreCore = Pick<
@@ -47,9 +46,8 @@ export interface Store {
47
46
  selectorAtoms: Join<null, `selectorKey`, `atomKey`>
48
47
  selectorGraph: Join<{ source: string }>
49
48
  selectors: Hamt<Selector<any>, string>
50
- timelines: Hamt<Timeline, string>
51
49
  timelineAtoms: Join<null, `timelineKey`, `atomKey`>
52
- timelineStore: Hamt<TimelineData, string>
50
+ timelines: Hamt<Timeline, string>
53
51
  transactions: Hamt<Transaction<any>, string>
54
52
  valueMap: Hamt<any, string>
55
53
 
@@ -71,46 +69,75 @@ export interface Store {
71
69
  }
72
70
  }
73
71
 
74
- export const createStore = (name: string): Store =>
75
- ({
72
+ export const createStore = (name: string, store: Store | null = null): Store => {
73
+ const copiedStore = {
74
+ ...(store ??
75
+ (() => ({
76
+ atomsThatAreDefault: new Set(),
77
+ selectorAtoms: new Join({ relationType: `n:n` })
78
+ .from(`selectorKey`)
79
+ .to(`atomKey`),
80
+ selectorGraph: new Join({ relationType: `n:n` }),
81
+ valueMap: HAMT.make<any, string>(),
82
+ }))()),
83
+
76
84
  atoms: HAMT.make<Atom<any>, string>(),
77
- atomsThatAreDefault: new Set(),
78
85
  readonlySelectors: HAMT.make<ReadonlySelector<any>, string>(),
79
- selectorAtoms: new Join({ relationType: `n:n` })
80
- .from(`selectorKey`)
81
- .to(`atomKey`),
82
- selectorGraph: new Join({ relationType: `n:n` }),
83
86
  selectors: HAMT.make<Selector<any>, string>(),
87
+ transactions: HAMT.make<Transaction<any>, string>(),
84
88
  timelines: HAMT.make<Timeline, string>(),
89
+
85
90
  timelineAtoms: new Join({ relationType: `1:n` })
86
91
  .from(`timelineKey`)
87
92
  .to(`atomKey`),
88
- timelineStore: HAMT.make<TimelineData, string>(),
89
- transactions: HAMT.make<Transaction<any>, string>(),
90
- valueMap: HAMT.make<any, string>(),
91
93
 
92
94
  subject: {
93
95
  atomCreation: new Rx.Subject(),
94
96
  selectorCreation: new Rx.Subject(),
95
97
  transactionCreation: new Rx.Subject(),
96
98
  timelineCreation: new Rx.Subject(),
99
+ ...store?.subject,
97
100
  },
98
101
 
99
102
  operation: {
100
103
  open: false,
104
+ ...store?.operation,
101
105
  },
102
106
  transactionStatus: {
103
107
  phase: `idle`,
108
+ ...store?.transactionStatus,
104
109
  },
105
110
  config: {
106
- name,
107
111
  logger: {
108
112
  ...console,
109
113
  info: doNothing,
114
+ ...store?.config?.logger,
110
115
  },
111
116
  logger__INTERNAL: console,
117
+ ...store?.config,
118
+ name,
112
119
  },
113
- } satisfies Store)
120
+ } satisfies Store
121
+
122
+ store?.atoms.forEach((atom) => {
123
+ const copiedAtom = { ...atom, subject: new Rx.Subject() } satisfies Atom<any>
124
+ copiedStore.atoms = HAMT.set(atom.key, copiedAtom, copiedStore.atoms)
125
+ })
126
+ store?.readonlySelectors.forEach((selector) => {
127
+ selector.install(copiedStore)
128
+ })
129
+ store?.selectors.forEach((selector) => {
130
+ selector.install(copiedStore)
131
+ })
132
+ store?.transactions.forEach((tx) => {
133
+ tx.install(copiedStore)
134
+ })
135
+ store?.timelines.forEach((timeline) => {
136
+ timeline.install(copiedStore)
137
+ })
138
+
139
+ return copiedStore
140
+ }
114
141
 
115
142
  export const IMPLICIT = {
116
143
  STORE_INTERNAL: undefined as Store | undefined,