atom.io 0.9.9 → 0.10.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.
- package/dist/index.d.mts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +36 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -55
- package/dist/index.mjs.map +1 -1
- package/internal/dist/index.d.mts +52 -25
- package/internal/dist/index.d.ts +52 -25
- package/internal/dist/index.js +352 -385
- package/internal/dist/index.js.map +1 -1
- package/internal/dist/index.mjs +349 -385
- package/internal/dist/index.mjs.map +1 -1
- package/internal/src/atom/create-atom.ts +5 -5
- package/internal/src/atom/delete-atom.ts +9 -2
- package/internal/src/atom/is-default.ts +2 -2
- package/internal/src/caching.ts +7 -5
- package/internal/src/get-state-internal.ts +4 -4
- package/internal/src/index.ts +1 -0
- package/internal/src/keys.ts +30 -0
- package/internal/src/mutable/create-mutable-atom.ts +2 -2
- package/internal/src/mutable/tracker.ts +1 -1
- package/internal/src/operation.ts +7 -7
- package/internal/src/selector/create-read-write-selector.ts +2 -8
- package/internal/src/selector/create-readonly-selector.ts +1 -1
- package/internal/src/selector/create-selector.ts +5 -3
- package/internal/src/selector/get-selector-dependency-keys.ts +20 -0
- package/internal/src/selector/index.ts +1 -1
- package/internal/src/selector/register-selector.ts +4 -11
- package/internal/src/selector/trace-selector-atoms.ts +26 -26
- package/internal/src/selector/update-selector-atoms.ts +14 -14
- package/internal/src/set-state/copy-mutable-if-needed.ts +1 -1
- package/internal/src/set-state/copy-mutable-in-transaction.ts +1 -1
- package/internal/src/set-state/emit-update.ts +1 -1
- package/internal/src/set-state/evict-downstream.ts +5 -6
- package/internal/src/set-state/set-atom.ts +1 -4
- package/internal/src/set-state/stow-update.ts +10 -4
- package/internal/src/store/index.ts +0 -1
- package/internal/src/store/store.ts +27 -10
- package/internal/src/store/withdraw-new-family-member.ts +1 -1
- package/internal/src/store/withdraw.ts +1 -1
- package/internal/src/subscribe/recall-state.ts +2 -2
- package/internal/src/subscribe/subscribe-to-root-atoms.ts +7 -8
- package/internal/src/timeline/add-atom-to-timeline.ts +8 -8
- package/internal/src/timeline/time-travel-internal.ts +12 -12
- package/internal/src/timeline/timeline-internal.ts +2 -2
- package/internal/src/transaction/abort-transaction.ts +3 -3
- package/internal/src/transaction/apply-transaction.ts +6 -6
- package/internal/src/transaction/build-transaction.ts +2 -3
- package/internal/src/transaction/redo-transaction.ts +1 -1
- package/internal/src/transaction/transaction-internal.ts +2 -2
- package/internal/src/transaction/undo-transaction.ts +1 -1
- package/package.json +3 -3
- package/react-devtools/dist/index.d.mts +3 -3
- package/react-devtools/dist/index.d.ts +3 -3
- package/realtime-client/dist/index.js +6 -9
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/dist/index.mjs +6 -9
- package/realtime-client/dist/index.mjs.map +1 -1
- package/realtime-client/src/use-server-action.ts +6 -8
- package/src/atom.ts +3 -0
- package/src/logger.ts +25 -36
- package/src/subscribe.ts +7 -7
- package/internal/src/selector/lookup-selector-sources.ts +0 -20
- package/internal/src/store/lookup.ts +0 -26
|
@@ -29,16 +29,16 @@ export function createAtom<T>(
|
|
|
29
29
|
family?: FamilyMetadata,
|
|
30
30
|
store: Store = IMPLICIT.STORE,
|
|
31
31
|
): AtomToken<T> {
|
|
32
|
-
store.
|
|
32
|
+
store.logger.info(
|
|
33
33
|
`🔨 creating atom "${options.key}" in store "${store.config.name}"`,
|
|
34
34
|
)
|
|
35
35
|
const core = target(store)
|
|
36
36
|
const existing = core.atoms.get(options.key)
|
|
37
37
|
if (existing) {
|
|
38
|
-
store.
|
|
39
|
-
|
|
38
|
+
store.logger.error(
|
|
39
|
+
`❓ Tried to create atom "${options.key}",`,
|
|
40
40
|
`but it already exists in the store.`,
|
|
41
|
-
`(Ignore if you are using hot module replacement.)`,
|
|
41
|
+
`(Ignore if you are in development using hot module replacement.)`,
|
|
42
42
|
)
|
|
43
43
|
return deposit(existing)
|
|
44
44
|
}
|
|
@@ -47,7 +47,7 @@ export function createAtom<T>(
|
|
|
47
47
|
...options,
|
|
48
48
|
type: `atom`,
|
|
49
49
|
install: (store: Store) => {
|
|
50
|
-
store.
|
|
50
|
+
store.logger.info(
|
|
51
51
|
`🛠️ installing atom "${options.key}" in store "${store.config.name}"`,
|
|
52
52
|
)
|
|
53
53
|
return `mutable` in options
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AtomToken } from "~/packages/atom.io/src"
|
|
2
|
+
import type { Store } from ".."
|
|
2
3
|
import { IMPLICIT, target } from ".."
|
|
3
4
|
|
|
4
|
-
export function deleteAtom(
|
|
5
|
+
export function deleteAtom(
|
|
6
|
+
atomToken: AtomToken<unknown>,
|
|
7
|
+
store: Store = IMPLICIT.STORE,
|
|
8
|
+
): void {
|
|
9
|
+
const core = target(store)
|
|
10
|
+
const { key } = atomToken
|
|
5
11
|
core.atoms.delete(key)
|
|
6
12
|
core.valueMap.delete(key)
|
|
7
13
|
core.selectorAtoms.delete(key)
|
|
8
14
|
core.atomsThatAreDefault.delete(key)
|
|
9
15
|
core.timelineAtoms.delete(key)
|
|
16
|
+
store.logger.info(`🔥 Atom "${key}" deleted`)
|
|
10
17
|
}
|
|
@@ -32,6 +32,6 @@ export const isSelectorDefault = (
|
|
|
32
32
|
key: string,
|
|
33
33
|
store: Store = IMPLICIT.STORE,
|
|
34
34
|
): boolean => {
|
|
35
|
-
const
|
|
36
|
-
return
|
|
35
|
+
const rootKeys = traceAllSelectorAtoms(key, store)
|
|
36
|
+
return rootKeys.every((rootKey) => isAtomDefault(rootKey, store))
|
|
37
37
|
}
|
package/internal/src/caching.ts
CHANGED
|
@@ -27,10 +27,9 @@ export const cacheValue = (
|
|
|
27
27
|
subject.next({ newValue: value, oldValue: value })
|
|
28
28
|
})
|
|
29
29
|
.catch((error) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
)
|
|
30
|
+
if (error !== `canceled`) {
|
|
31
|
+
store.logger.error(`🙅♂️ Promised value for "${key}" rejected:`, error)
|
|
32
|
+
}
|
|
34
33
|
})
|
|
35
34
|
} else {
|
|
36
35
|
target(store).valueMap.set(key, value)
|
|
@@ -56,6 +55,9 @@ export const evictCachedValue = (
|
|
|
56
55
|
if (currentValue instanceof Future) {
|
|
57
56
|
currentValue.cancel()
|
|
58
57
|
}
|
|
58
|
+
if (core.operation.open) {
|
|
59
|
+
core.operation.prev.set(key, currentValue)
|
|
60
|
+
}
|
|
59
61
|
core.valueMap.delete(key)
|
|
60
|
-
store.
|
|
62
|
+
store.logger.info(`🗑 evicted "${key}"`)
|
|
61
63
|
}
|
|
@@ -9,15 +9,15 @@ export const getState__INTERNAL = <T>(
|
|
|
9
9
|
store: Store = IMPLICIT.STORE,
|
|
10
10
|
): T => {
|
|
11
11
|
if (isValueCached(state.key, store)) {
|
|
12
|
-
store.
|
|
12
|
+
store.logger.info(`📖 reading "${state.key}"`)
|
|
13
13
|
return readCachedValue(state.key, store)
|
|
14
14
|
}
|
|
15
15
|
if (state.type !== `atom`) {
|
|
16
|
-
store.
|
|
16
|
+
store.logger.info(`🧮 calculating "${state.key}"`)
|
|
17
17
|
return state.get()
|
|
18
18
|
}
|
|
19
|
-
store.
|
|
20
|
-
|
|
19
|
+
store.logger.error(
|
|
20
|
+
`🐞 Attempted to get atom "${state.key}", which was never initialized in store "${store.config.name}".`,
|
|
21
21
|
)
|
|
22
22
|
return state.default
|
|
23
23
|
}
|
package/internal/src/index.ts
CHANGED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Store } from "./store"
|
|
2
|
+
import { target } from "./transaction"
|
|
3
|
+
|
|
4
|
+
export type AtomKey<T> = string & { __atomKey?: never; __brand?: T }
|
|
5
|
+
export type SelectorKey<T> = string & { __selectorKey?: never; __brand?: T }
|
|
6
|
+
export type ReadonlySelectorKey<T> = string & {
|
|
7
|
+
__readonlySelectorKey?: never
|
|
8
|
+
__brand?: T
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const isAtomKey = (key: string, store: Store): key is AtomKey<unknown> =>
|
|
12
|
+
target(store).atoms.has(key)
|
|
13
|
+
export const isSelectorKey = (
|
|
14
|
+
key: string,
|
|
15
|
+
store: Store,
|
|
16
|
+
): key is SelectorKey<unknown> => target(store).selectors.has(key)
|
|
17
|
+
export const isReadonlySelectorKey = (
|
|
18
|
+
key: string,
|
|
19
|
+
store: Store,
|
|
20
|
+
): key is ReadonlySelectorKey<unknown> =>
|
|
21
|
+
target(store).readonlySelectors.has(key)
|
|
22
|
+
|
|
23
|
+
export type StateKey<T> = AtomKey<T> | ReadonlySelectorKey<T> | SelectorKey<T>
|
|
24
|
+
export const isStateKey = (
|
|
25
|
+
key: string,
|
|
26
|
+
store: Store,
|
|
27
|
+
): key is StateKey<unknown> =>
|
|
28
|
+
isAtomKey(key, store) ||
|
|
29
|
+
isSelectorKey(key, store) ||
|
|
30
|
+
isReadonlySelectorKey(key, store)
|
|
@@ -17,7 +17,7 @@ export function createMutableAtom<
|
|
|
17
17
|
options: MutableAtomOptions<Core, SerializableCore>,
|
|
18
18
|
store: Store = IMPLICIT.STORE,
|
|
19
19
|
): MutableAtomToken<Core, SerializableCore> {
|
|
20
|
-
store.
|
|
20
|
+
store.logger.info(
|
|
21
21
|
`🔧 creating mutable atom "${options.key}" in store "${store.config.name}"`,
|
|
22
22
|
)
|
|
23
23
|
const coreState = createAtom<Core>(options, undefined, store)
|
|
@@ -26,7 +26,7 @@ export function createMutableAtom<
|
|
|
26
26
|
subscribe(
|
|
27
27
|
jsonState,
|
|
28
28
|
() => {
|
|
29
|
-
store.
|
|
29
|
+
store.logger.info(
|
|
30
30
|
`🔍 tracker-initializer:${store?.config.name}:${
|
|
31
31
|
store.transactionStatus.phase === `idle`
|
|
32
32
|
? `main`
|
|
@@ -21,7 +21,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
21
21
|
store: Store = IMPLICIT.STORE,
|
|
22
22
|
): AtomToken<typeof this.Update | null> {
|
|
23
23
|
const latestUpdateStateKey = `*${mutableState.key}`
|
|
24
|
-
deleteAtom(latestUpdateStateKey,
|
|
24
|
+
deleteAtom({ type: `atom`, key: latestUpdateStateKey }, store)
|
|
25
25
|
const familyMetaData: FamilyMetadata | undefined = mutableState.family
|
|
26
26
|
? {
|
|
27
27
|
key: `*${mutableState.family.key}`,
|
|
@@ -22,7 +22,7 @@ export const openOperation = (
|
|
|
22
22
|
): `rejection` | undefined => {
|
|
23
23
|
const core = target(store)
|
|
24
24
|
if (core.operation.open) {
|
|
25
|
-
store.
|
|
25
|
+
store.logger.error(
|
|
26
26
|
`❌ failed to setState to "${token.key}" during a setState for "${core.operation.token.key}"`,
|
|
27
27
|
)
|
|
28
28
|
return `rejection`
|
|
@@ -30,11 +30,11 @@ export const openOperation = (
|
|
|
30
30
|
core.operation = {
|
|
31
31
|
open: true,
|
|
32
32
|
done: new Set(),
|
|
33
|
-
prev: new Map(
|
|
33
|
+
prev: new Map(),
|
|
34
34
|
time: Date.now(),
|
|
35
35
|
token,
|
|
36
36
|
}
|
|
37
|
-
store.
|
|
37
|
+
store.logger.info(
|
|
38
38
|
`⭕ operation start from "${token.key}" in store "${store.config.name}"${
|
|
39
39
|
store.transactionStatus.phase === `idle`
|
|
40
40
|
? ``
|
|
@@ -45,14 +45,14 @@ export const openOperation = (
|
|
|
45
45
|
export const closeOperation = (store: Store): void => {
|
|
46
46
|
const core = target(store)
|
|
47
47
|
core.operation = { open: false }
|
|
48
|
-
store.
|
|
48
|
+
store.logger.info(`🔴 operation done`)
|
|
49
49
|
store.subject.operationStatus.next(core.operation)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
export const isDone = (key: string, store: Store = IMPLICIT.STORE): boolean => {
|
|
53
53
|
const core = target(store)
|
|
54
54
|
if (!core.operation.open) {
|
|
55
|
-
store.
|
|
55
|
+
store.logger.warn(
|
|
56
56
|
`isDone called outside of an operation. This is probably a bug.`,
|
|
57
57
|
)
|
|
58
58
|
return true
|
|
@@ -62,8 +62,8 @@ export const isDone = (key: string, store: Store = IMPLICIT.STORE): boolean => {
|
|
|
62
62
|
export const markDone = (key: string, store: Store = IMPLICIT.STORE): void => {
|
|
63
63
|
const core = target(store)
|
|
64
64
|
if (!core.operation.open) {
|
|
65
|
-
store.
|
|
66
|
-
|
|
65
|
+
store.logger.warn(
|
|
66
|
+
`🐞 markDone called outside of an operation. This is probably a bug.`,
|
|
67
67
|
)
|
|
68
68
|
return
|
|
69
69
|
}
|
|
@@ -27,13 +27,7 @@ export const createReadWriteSelector = <T>(
|
|
|
27
27
|
const setSelf = (next: T | ((oldValue: T) => T)): void => {
|
|
28
28
|
const oldValue = getSelf()
|
|
29
29
|
const newValue = become(next)(oldValue)
|
|
30
|
-
store.
|
|
31
|
-
` <- "${options.key}" went (`,
|
|
32
|
-
oldValue,
|
|
33
|
-
`->`,
|
|
34
|
-
newValue,
|
|
35
|
-
`)`,
|
|
36
|
-
)
|
|
30
|
+
store.logger.info(`📝 set "${options.key}" (`, oldValue, `->`, newValue, `)`)
|
|
37
31
|
cacheValue(options.key, newValue, subject, store)
|
|
38
32
|
markDone(options.key, store)
|
|
39
33
|
if (store.transactionStatus.phase === `idle`) {
|
|
@@ -52,7 +46,7 @@ export const createReadWriteSelector = <T>(
|
|
|
52
46
|
}
|
|
53
47
|
core.selectors.set(options.key, mySelector)
|
|
54
48
|
const initialValue = getSelf()
|
|
55
|
-
store.
|
|
49
|
+
store.logger.info(`✨ "${options.key}" =`, initialValue)
|
|
56
50
|
const token: SelectorToken<T> = {
|
|
57
51
|
key: options.key,
|
|
58
52
|
type: `selector`,
|
|
@@ -36,7 +36,7 @@ export const createReadonlySelector = <T>(
|
|
|
36
36
|
}
|
|
37
37
|
core.readonlySelectors.set(options.key, readonlySelector)
|
|
38
38
|
const initialValue = getSelf()
|
|
39
|
-
store.
|
|
39
|
+
store.logger.info(`✨ "${options.key}" =`, initialValue)
|
|
40
40
|
const token: ReadonlySelectorToken<T> = {
|
|
41
41
|
key: options.key,
|
|
42
42
|
type: `readonly_selector`,
|
|
@@ -51,10 +51,12 @@ export function createSelector<T>(
|
|
|
51
51
|
const existingReadonly = core.readonlySelectors.get(options.key)
|
|
52
52
|
|
|
53
53
|
if (existingWritable || existingReadonly) {
|
|
54
|
-
store.
|
|
55
|
-
|
|
54
|
+
store.logger.error(
|
|
55
|
+
`❓ Tried to create ${
|
|
56
|
+
existingReadonly ? `readonly selector` : `selector`
|
|
57
|
+
}`,
|
|
56
58
|
`"${options.key}", but it already exists in the store.`,
|
|
57
|
-
`(Ignore if you are using hot module replacement.)`,
|
|
59
|
+
`(Ignore if you are in development using hot module replacement.)`,
|
|
58
60
|
)
|
|
59
61
|
}
|
|
60
62
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AtomKey, ReadonlySelectorKey, SelectorKey } from "../keys"
|
|
2
|
+
import { isStateKey } from "../keys"
|
|
3
|
+
import type { Store } from "../store"
|
|
4
|
+
import { target } from "../transaction"
|
|
5
|
+
|
|
6
|
+
export const getSelectorDependencyKeys = (
|
|
7
|
+
key: string,
|
|
8
|
+
store: Store,
|
|
9
|
+
): (
|
|
10
|
+
| AtomKey<unknown>
|
|
11
|
+
| ReadonlySelectorKey<unknown>
|
|
12
|
+
| SelectorKey<unknown>
|
|
13
|
+
)[] => {
|
|
14
|
+
const sources = target(store)
|
|
15
|
+
.selectorGraph.getRelationEntries({ downstreamSelectorKey: key })
|
|
16
|
+
.filter(([_, { source }]) => source !== key)
|
|
17
|
+
.map(([_, { source }]) => source)
|
|
18
|
+
.filter((source) => isStateKey(source, store))
|
|
19
|
+
return sources
|
|
20
|
+
}
|
|
@@ -25,17 +25,10 @@ export const registerSelector = (
|
|
|
25
25
|
}
|
|
26
26
|
const dependencyValue = getState__INTERNAL(dependencyState, store)
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
)
|
|
33
|
-
} else {
|
|
34
|
-
store.config.logger?.info(
|
|
35
|
-
`🔌 registerSelector "${selectorKey}" <- ( "${dependency.key}" =`,
|
|
36
|
-
dependencyValue,
|
|
37
|
-
`)`,
|
|
38
|
-
)
|
|
28
|
+
store.logger.info(
|
|
29
|
+
`🔌 selector "${selectorKey}" registers dependency ( "${dependency.key}" = ${dependencyValue} )`,
|
|
30
|
+
)
|
|
31
|
+
if (!alreadyRegistered) {
|
|
39
32
|
core.selectorGraph = core.selectorGraph.set(
|
|
40
33
|
{
|
|
41
34
|
upstreamSelectorKey: dependency.key,
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
import type { AtomToken, ReadonlySelectorToken, StateToken } from "atom.io"
|
|
2
|
-
|
|
3
1
|
import type { Store } from ".."
|
|
4
|
-
import {
|
|
2
|
+
import type { AtomKey, StateKey } from "../keys"
|
|
3
|
+
import { isAtomKey } from "../keys"
|
|
4
|
+
import { getSelectorDependencyKeys } from "./get-selector-dependency-keys"
|
|
5
5
|
|
|
6
6
|
export const traceSelectorAtoms = (
|
|
7
7
|
selectorKey: string,
|
|
8
|
-
|
|
8
|
+
directDependencyKey: StateKey<unknown>,
|
|
9
9
|
store: Store,
|
|
10
|
-
):
|
|
11
|
-
const
|
|
10
|
+
): AtomKey<unknown>[] => {
|
|
11
|
+
const rootKeys: AtomKey<unknown>[] = []
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const indirectDependencyKeys = getSelectorDependencyKeys(
|
|
14
|
+
directDependencyKey,
|
|
15
|
+
store,
|
|
16
|
+
)
|
|
14
17
|
let depth = 0
|
|
15
|
-
while (
|
|
18
|
+
while (indirectDependencyKeys.length > 0) {
|
|
16
19
|
// biome-ignore lint/style/noNonNullAssertion: just checked length ^^^
|
|
17
|
-
const
|
|
20
|
+
const indirectDependencyKey = indirectDependencyKeys.shift()!
|
|
18
21
|
++depth
|
|
19
|
-
if (depth > 999) {
|
|
20
|
-
store.config.logger?.warn(
|
|
21
|
-
`Maximum selector dependency depth exceeded 999 in selector "${selectorKey}".`,
|
|
22
|
-
)
|
|
23
|
-
}
|
|
24
22
|
if (depth > 99999) {
|
|
25
23
|
throw new Error(
|
|
26
|
-
`Maximum selector dependency depth exceeded in selector "${selectorKey}".`,
|
|
24
|
+
`Maximum selector dependency depth exceeded (> 99999) in selector "${selectorKey}". This is likely due to a circular dependency.`,
|
|
27
25
|
)
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
if (!isAtomKey(indirectDependencyKey, store)) {
|
|
29
|
+
indirectDependencyKeys.push(
|
|
30
|
+
...getSelectorDependencyKeys(indirectDependencyKey, store),
|
|
31
|
+
)
|
|
32
|
+
} else if (!rootKeys.includes(indirectDependencyKey)) {
|
|
33
|
+
rootKeys.push(indirectDependencyKey)
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
return
|
|
37
|
+
return rootKeys
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export const traceAllSelectorAtoms = (
|
|
41
41
|
selectorKey: string,
|
|
42
42
|
store: Store,
|
|
43
|
-
):
|
|
44
|
-
const
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
?
|
|
48
|
-
: traceSelectorAtoms(selectorKey,
|
|
43
|
+
): AtomKey<unknown>[] => {
|
|
44
|
+
const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store)
|
|
45
|
+
return directDependencyKeys.flatMap((depKey) =>
|
|
46
|
+
isAtomKey(depKey, store)
|
|
47
|
+
? depKey
|
|
48
|
+
: traceSelectorAtoms(selectorKey, depKey, store),
|
|
49
49
|
)
|
|
50
50
|
}
|
|
@@ -15,20 +15,20 @@ export const updateSelectorAtoms = (
|
|
|
15
15
|
selectorKey,
|
|
16
16
|
atomKey: dependency.key,
|
|
17
17
|
})
|
|
18
|
-
store.
|
|
19
|
-
|
|
18
|
+
store.logger.info(
|
|
19
|
+
`🔍 selector "${selectorKey}" discovers root atom "${dependency.key}"`,
|
|
20
20
|
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
21
|
+
} else {
|
|
22
|
+
const rootKeys = traceSelectorAtoms(selectorKey, dependency.key, store)
|
|
23
|
+
store.logger.info(
|
|
24
|
+
`🔍 selector "${selectorKey}" discovers root atoms:`,
|
|
25
|
+
rootKeys.map((r) => r),
|
|
26
|
+
)
|
|
27
|
+
for (const atomKey of rootKeys) {
|
|
28
|
+
core.selectorAtoms = core.selectorAtoms.set({
|
|
29
|
+
selectorKey,
|
|
30
|
+
atomKey,
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -13,7 +13,7 @@ export function copyMutableIfNeeded<T>(
|
|
|
13
13
|
const originValue = origin.valueMap.get(atom.key)
|
|
14
14
|
const targetValue = target.valueMap.get(atom.key)
|
|
15
15
|
if (originValue === targetValue) {
|
|
16
|
-
origin.
|
|
16
|
+
origin.logger.info(`📃 copying`, `${atom.key}`)
|
|
17
17
|
const copiedValue = transform.fromJson(transform.toJson(originValue))
|
|
18
18
|
target.valueMap.set(atom.key, copiedValue)
|
|
19
19
|
new Tracker(atom, origin)
|
|
@@ -14,7 +14,7 @@ export function copyMutableIfWithinTransaction<T>(
|
|
|
14
14
|
store.transactionStatus.phase === `applying`
|
|
15
15
|
) {
|
|
16
16
|
if (`toJson` in atom && `fromJson` in atom) {
|
|
17
|
-
store.
|
|
17
|
+
store.logger.info(
|
|
18
18
|
`📄 copyMutableIfWithinTransaction: ${atom.key} is mutable`,
|
|
19
19
|
)
|
|
20
20
|
const copiedValue = copyMutableIfNeeded(
|
|
@@ -11,23 +11,22 @@ export const evictDownStream = <T>(
|
|
|
11
11
|
): void => {
|
|
12
12
|
const core = target(store)
|
|
13
13
|
const downstreamKeys = core.selectorAtoms.getRelatedKeys(state.key)
|
|
14
|
-
store.
|
|
15
|
-
|
|
14
|
+
store.logger.info(
|
|
15
|
+
`🧹 evicting ${downstreamKeys?.size} states downstream from ${state.type} "${state.key}":`,
|
|
16
16
|
downstreamKeys,
|
|
17
17
|
)
|
|
18
18
|
if (core.operation.open) {
|
|
19
|
-
store.
|
|
19
|
+
store.logger.info(`🧹`, [...core.operation.done], `already done`)
|
|
20
20
|
}
|
|
21
21
|
if (downstreamKeys) {
|
|
22
22
|
for (const key of downstreamKeys) {
|
|
23
23
|
if (isDone(key, store)) {
|
|
24
|
-
store.config.logger?.info(` || ${key} already done`)
|
|
25
24
|
continue
|
|
26
25
|
}
|
|
27
26
|
const state = core.selectors.get(key) ?? core.readonlySelectors.get(key)
|
|
28
27
|
if (!state) {
|
|
29
|
-
store.
|
|
30
|
-
|
|
28
|
+
store.logger.error(
|
|
29
|
+
`🐞 "${key}" was not found in selectors or readonlySelectors`,
|
|
31
30
|
)
|
|
32
31
|
return
|
|
33
32
|
}
|
|
@@ -19,15 +19,12 @@ export const setAtom = <T>(
|
|
|
19
19
|
const oldValue = getState__INTERNAL(atom, store)
|
|
20
20
|
let newValue = copyMutableIfWithinTransaction(atom, store)
|
|
21
21
|
newValue = become(next)(newValue)
|
|
22
|
-
store.
|
|
22
|
+
store.logger.info(`📝 setting atom "${atom.key}" to`, newValue)
|
|
23
23
|
cacheValue(atom.key, newValue, atom.subject, store)
|
|
24
24
|
if (isAtomDefault(atom.key, store)) {
|
|
25
25
|
markAtomAsNotDefault(atom.key, store)
|
|
26
26
|
}
|
|
27
27
|
markDone(atom.key, store)
|
|
28
|
-
store.config.logger?.info(
|
|
29
|
-
` || evicting caches downstream from "${atom.key}"`,
|
|
30
|
-
)
|
|
31
28
|
evictDownStream(atom, store)
|
|
32
29
|
const update = { oldValue, newValue }
|
|
33
30
|
if (store.transactionStatus.phase !== `building`) {
|
|
@@ -22,10 +22,10 @@ export const stowUpdate = <T>(
|
|
|
22
22
|
store: Store,
|
|
23
23
|
): void => {
|
|
24
24
|
const { key } = state
|
|
25
|
-
const { logger } = store
|
|
25
|
+
const { logger } = store
|
|
26
26
|
if (store.transactionStatus.phase !== `building`) {
|
|
27
|
-
store.
|
|
28
|
-
|
|
27
|
+
store.logger.warn(
|
|
28
|
+
`🐞 stowUpdate called outside of a transaction. This is probably a bug.`,
|
|
29
29
|
)
|
|
30
30
|
return
|
|
31
31
|
}
|
|
@@ -38,5 +38,11 @@ export const stowUpdate = <T>(
|
|
|
38
38
|
atomUpdate.family = state.family
|
|
39
39
|
}
|
|
40
40
|
store.transactionStatus.atomUpdates.push(atomUpdate)
|
|
41
|
-
logger
|
|
41
|
+
store.logger.info(
|
|
42
|
+
`📁 ${key} stowed (`,
|
|
43
|
+
update.oldValue,
|
|
44
|
+
`->`,
|
|
45
|
+
update.newValue,
|
|
46
|
+
`)`,
|
|
47
|
+
)
|
|
42
48
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AtomIOLogger } from "atom.io"
|
|
1
2
|
import type {
|
|
2
3
|
AtomFamily,
|
|
3
4
|
AtomToken,
|
|
@@ -94,12 +95,33 @@ export class Store {
|
|
|
94
95
|
|
|
95
96
|
public config: {
|
|
96
97
|
name: string
|
|
97
|
-
logger: Logger | null
|
|
98
|
-
logger__INTERNAL: Logger
|
|
99
98
|
} = {
|
|
100
99
|
name: `IMPLICIT_STORE`,
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public loggers: AtomIOLogger[] = [
|
|
103
|
+
new AtomIOLogger(
|
|
104
|
+
{ ...console },
|
|
105
|
+
`warn`,
|
|
106
|
+
(message) => !message.includes(`👁🗨`),
|
|
107
|
+
),
|
|
108
|
+
]
|
|
109
|
+
public logger: Logger = {
|
|
110
|
+
error: (message: string) => {
|
|
111
|
+
for (const logger of this.loggers) {
|
|
112
|
+
logger.error(message)
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
info: (message: string) => {
|
|
116
|
+
for (const logger of this.loggers) {
|
|
117
|
+
logger.info(message)
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
warn: (message: string) => {
|
|
121
|
+
for (const logger of this.loggers) {
|
|
122
|
+
logger.warn(message)
|
|
123
|
+
}
|
|
124
|
+
},
|
|
103
125
|
}
|
|
104
126
|
|
|
105
127
|
public constructor(name: string, store: Store | null = null) {
|
|
@@ -110,14 +132,9 @@ export class Store {
|
|
|
110
132
|
this.transactionStatus = { ...store?.transactionStatus }
|
|
111
133
|
this.config = {
|
|
112
134
|
...store?.config,
|
|
113
|
-
logger__INTERNAL: console,
|
|
114
|
-
logger: {
|
|
115
|
-
...console,
|
|
116
|
-
info: () => undefined,
|
|
117
|
-
...store?.config?.logger,
|
|
118
|
-
},
|
|
119
135
|
name,
|
|
120
136
|
}
|
|
137
|
+
|
|
121
138
|
for (const [, atom] of store.atoms) {
|
|
122
139
|
atom.install(this)
|
|
123
140
|
}
|
|
@@ -36,7 +36,7 @@ export function withdrawNewFamilyMember<T>(
|
|
|
36
36
|
| StateToken<T>,
|
|
37
37
|
store: Store,
|
|
38
38
|
): Atom<T> | ReadonlySelector<T> | Selector<T> | undefined {
|
|
39
|
-
store.
|
|
39
|
+
store.logger.info(
|
|
40
40
|
`👪 creating new family member "${token.key}" in store "${store.config.name}"`,
|
|
41
41
|
)
|
|
42
42
|
if (token.family) {
|
|
@@ -78,7 +78,7 @@ export function withdraw<T>(
|
|
|
78
78
|
core.timelines.get(token.key)
|
|
79
79
|
|
|
80
80
|
if (state) {
|
|
81
|
-
store.
|
|
81
|
+
store.logger.info(`🛠️ add ${token.type} "${token.key}"`)
|
|
82
82
|
switch (state.type) {
|
|
83
83
|
case `atom`: {
|
|
84
84
|
store.atoms.set(token.key, state)
|
|
@@ -10,8 +10,8 @@ export const recallState = <T>(
|
|
|
10
10
|
): T => {
|
|
11
11
|
const core = target(store)
|
|
12
12
|
if (!core.operation.open) {
|
|
13
|
-
store.
|
|
14
|
-
|
|
13
|
+
store.logger.warn(
|
|
14
|
+
`🐞recall called outside of an operation. This is probably a bug.`,
|
|
15
15
|
)
|
|
16
16
|
return core.valueMap.get(state.key)
|
|
17
17
|
}
|