atom.io 0.36.2 → 0.37.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/data/index.d.ts.map +1 -1
- package/dist/data/index.js.map +1 -1
- package/dist/eslint-plugin/index.js +1 -2
- package/dist/eslint-plugin/index.js.map +1 -1
- package/dist/internal/index.d.ts +66 -98
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +544 -507
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts +2 -2
- package/dist/introspection/index.d.ts.map +1 -1
- package/dist/introspection/index.js +1 -1
- package/dist/introspection/index.js.map +1 -1
- package/dist/json/index.d.ts +2 -1
- package/dist/json/index.d.ts.map +1 -1
- package/dist/json/index.js.map +1 -1
- package/dist/main/index.d.ts +154 -139
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js.map +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.d.ts.map +1 -1
- package/dist/react-devtools/index.js +54 -56
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.d.ts +3 -3
- package/dist/realtime-client/index.d.ts.map +1 -1
- package/dist/realtime-client/index.js +6 -6
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.d.ts.map +1 -1
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts +5 -5
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js +10 -12
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/transceivers/set-rtx/index.d.ts +1 -1
- package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
- package/dist/transceivers/set-rtx/index.js +1 -3
- package/dist/transceivers/set-rtx/index.js.map +1 -1
- package/dist/use-o-DXPncKmZ.js.map +1 -1
- package/dist/web/index.d.ts +2 -2
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js.map +1 -1
- package/package.json +14 -14
- package/src/internal/atom/dispose-atom.ts +5 -4
- package/src/internal/caching.ts +3 -3
- package/src/internal/families/create-readonly-held-selector-family.ts +3 -5
- package/src/internal/families/create-readonly-pure-selector-family.ts +3 -5
- package/src/internal/families/create-regular-atom-family.ts +3 -6
- package/src/internal/families/create-writable-held-selector-family.ts +3 -5
- package/src/internal/families/create-writable-pure-selector-family.ts +3 -5
- package/src/internal/families/find-in-store.ts +17 -34
- package/src/internal/families/init-family-member.ts +5 -87
- package/src/internal/families/mint-in-store.ts +74 -0
- package/src/internal/get-state/read-or-compute-value.ts +4 -2
- package/src/internal/index.ts +19 -18
- package/src/internal/ingest-updates/ingest-atom-update.ts +7 -7
- package/src/internal/ingest-updates/ingest-creation-disposal.ts +11 -11
- package/src/internal/ingest-updates/ingest-selector-update.ts +8 -4
- package/src/internal/ingest-updates/ingest-transaction-update.ts +5 -6
- package/src/internal/install-into-store.ts +2 -2
- package/src/internal/join/join-internal.ts +1 -1
- package/src/internal/molecule.ts +12 -9
- package/src/internal/mutable/create-mutable-atom-family.ts +3 -6
- package/src/internal/mutable/tracker.ts +2 -2
- package/src/internal/mutable/transceiver.ts +6 -4
- package/src/internal/operation.ts +17 -14
- package/src/internal/selector/create-readonly-held-selector.ts +9 -7
- package/src/internal/selector/create-readonly-pure-selector.ts +8 -5
- package/src/internal/selector/create-writable-held-selector.ts +12 -21
- package/src/internal/selector/create-writable-pure-selector.ts +16 -29
- package/src/internal/selector/dispose-selector.ts +6 -1
- package/src/internal/selector/get-selector-dependency-keys.ts +2 -6
- package/src/internal/selector/register-selector.ts +64 -74
- package/src/internal/selector/trace-selector-atoms.ts +2 -2
- package/src/internal/selector/update-selector-atoms.ts +2 -2
- package/src/internal/set-state/dispatch-state-update.ts +101 -0
- package/src/internal/set-state/operate-on-store.ts +126 -0
- package/src/internal/set-state/reset-atom-or-selector.ts +24 -15
- package/src/internal/set-state/set-atom-or-selector.ts +9 -4
- package/src/internal/set-state/set-atom.ts +4 -49
- package/src/internal/set-state/set-into-store.ts +11 -77
- package/src/internal/set-state/set-selector.ts +35 -0
- package/src/internal/store/store.ts +4 -4
- package/src/internal/subscribe/subscribe-in-store.ts +3 -3
- package/src/internal/subscribe/subscribe-to-timeline.ts +2 -2
- package/src/internal/timeline/create-timeline.ts +57 -101
- package/src/internal/timeline/time-travel.ts +1 -1
- package/src/internal/transaction/abort-transaction.ts +1 -1
- package/src/internal/transaction/apply-transaction.ts +7 -7
- package/src/internal/transaction/build-transaction.ts +10 -9
- package/src/internal/transaction/create-transaction.ts +4 -3
- package/src/internal/transaction/index.ts +6 -2
- package/src/introspection/attach-introspection-states.ts +2 -2
- package/src/introspection/attach-transaction-logs.ts +13 -6
- package/src/json/index.ts +3 -1
- package/src/main/atom.ts +2 -1
- package/src/main/events.ts +109 -0
- package/src/main/get-state.ts +1 -1
- package/src/main/index.ts +3 -0
- package/src/main/subscribe.ts +9 -19
- package/src/main/timeline.ts +3 -21
- package/src/main/transaction.ts +0 -65
- package/src/main/validators.ts +8 -2
- package/src/react-devtools/TimelineIndex.tsx +1 -1
- package/src/react-devtools/TransactionIndex.tsx +5 -3
- package/src/react-devtools/Updates.tsx +54 -46
- package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +20 -10
- package/src/realtime-client/realtime-client-stores/client-sync-store.ts +4 -4
- package/src/realtime-client/sync-continuity.ts +1 -1
- package/src/realtime-server/continuity/prepare-to-serve-transaction-request.ts +14 -8
- package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +5 -2
- package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
- package/src/realtime-server/realtime-action-receiver.ts +6 -3
- package/src/realtime-server/realtime-server-stores/server-sync-store.ts +13 -16
- package/src/transceivers/set-rtx/set-rtx.ts +1 -3
- package/src/web/persist-sync.ts +2 -2
- package/src/internal/set-state/emit-update.ts +0 -40
|
@@ -7,18 +7,15 @@ import type {
|
|
|
7
7
|
import type { WritablePureSelector } from ".."
|
|
8
8
|
import { writeToCache } from "../caching"
|
|
9
9
|
import { newest } from "../lineage"
|
|
10
|
-
import { markDone } from "../operation"
|
|
11
|
-
import { become } from "../set-state"
|
|
12
10
|
import type { Store } from "../store"
|
|
13
11
|
import { Subject } from "../subject"
|
|
14
|
-
import { isRootStore } from "../transaction"
|
|
15
12
|
import { registerSelector } from "./register-selector"
|
|
16
13
|
|
|
17
|
-
export
|
|
14
|
+
export function createWritablePureSelector<T>(
|
|
18
15
|
store: Store,
|
|
19
16
|
options: WritablePureSelectorOptions<T>,
|
|
20
17
|
family: FamilyMetadata | undefined,
|
|
21
|
-
): WritablePureSelectorToken<T>
|
|
18
|
+
): WritablePureSelectorToken<T> {
|
|
22
19
|
const target = newest(store)
|
|
23
20
|
const subject = new Subject<{ newValue: T; oldValue: T }>()
|
|
24
21
|
const covered = new Set<string>()
|
|
@@ -28,7 +25,7 @@ export const createWritablePureSelector = <T>(
|
|
|
28
25
|
const { find, get, json } = setterToolkit
|
|
29
26
|
const getterToolkit = { find, get, json }
|
|
30
27
|
|
|
31
|
-
const
|
|
28
|
+
const getFrom = (innerTarget: Store): T => {
|
|
32
29
|
const upstreamStates = innerTarget.selectorGraph.getRelationEntries({
|
|
33
30
|
downstreamSelectorKey: key,
|
|
34
31
|
})
|
|
@@ -38,43 +35,33 @@ export const createWritablePureSelector = <T>(
|
|
|
38
35
|
}
|
|
39
36
|
}
|
|
40
37
|
innerTarget.selectorAtoms.delete(key)
|
|
41
|
-
const value =
|
|
38
|
+
const value = options.get(getterToolkit)
|
|
42
39
|
const cached = writeToCache(innerTarget, mySelector, value)
|
|
43
40
|
store.logger.info(`✨`, type, key, `=`, cached)
|
|
44
41
|
covered.clear()
|
|
45
|
-
return
|
|
42
|
+
return cached
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
const setSelf = (
|
|
49
|
-
const innerTarget = newest(store)
|
|
50
|
-
const oldValue = getSelf(options.get, innerTarget)
|
|
51
|
-
const newValue = become(next)(oldValue)
|
|
52
|
-
store.logger.info(`📝`, type, key, `set (`, oldValue, `->`, newValue, `)`)
|
|
53
|
-
writeToCache(innerTarget, mySelector, newValue)
|
|
54
|
-
markDone(innerTarget, options.key)
|
|
55
|
-
if (isRootStore(innerTarget)) {
|
|
56
|
-
subject.next({ newValue, oldValue })
|
|
57
|
-
}
|
|
45
|
+
const setSelf = (newValue: T): void => {
|
|
58
46
|
options.set(setterToolkit, newValue)
|
|
59
47
|
}
|
|
48
|
+
|
|
60
49
|
const mySelector: WritablePureSelector<T> = {
|
|
61
50
|
...options,
|
|
62
51
|
type,
|
|
63
52
|
subject,
|
|
53
|
+
getFrom,
|
|
54
|
+
setSelf,
|
|
64
55
|
install: (s: Store) => createWritablePureSelector(s, options, family),
|
|
65
|
-
get: getSelf,
|
|
66
|
-
set: setSelf,
|
|
67
|
-
...(family && { family }),
|
|
68
56
|
}
|
|
57
|
+
if (family) mySelector.family = family
|
|
58
|
+
|
|
69
59
|
target.writableSelectors.set(key, mySelector)
|
|
70
|
-
const initialValue =
|
|
60
|
+
const initialValue = getFrom(target)
|
|
71
61
|
store.logger.info(`✨`, mySelector.type, mySelector.key, `=`, initialValue)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (family) {
|
|
77
|
-
token.family = family
|
|
78
|
-
}
|
|
62
|
+
|
|
63
|
+
const token: WritablePureSelectorToken<T> = { key, type }
|
|
64
|
+
if (family) token.family = family
|
|
65
|
+
|
|
79
66
|
return token
|
|
80
67
|
}
|
|
@@ -35,6 +35,7 @@ export function disposeSelector(
|
|
|
35
35
|
type: `state_disposal`,
|
|
36
36
|
subType: `selector`,
|
|
37
37
|
token: selectorToken,
|
|
38
|
+
timestamp: Date.now(),
|
|
38
39
|
})
|
|
39
40
|
}
|
|
40
41
|
break
|
|
@@ -50,6 +51,7 @@ export function disposeSelector(
|
|
|
50
51
|
type: `state_disposal`,
|
|
51
52
|
subType: `selector`,
|
|
52
53
|
token: selectorToken,
|
|
54
|
+
timestamp: Date.now(),
|
|
53
55
|
})
|
|
54
56
|
}
|
|
55
57
|
break
|
|
@@ -65,6 +67,7 @@ export function disposeSelector(
|
|
|
65
67
|
type: `state_disposal`,
|
|
66
68
|
subType: `selector`,
|
|
67
69
|
token: selectorToken,
|
|
70
|
+
timestamp: Date.now(),
|
|
68
71
|
})
|
|
69
72
|
}
|
|
70
73
|
break
|
|
@@ -80,6 +83,7 @@ export function disposeSelector(
|
|
|
80
83
|
type: `state_disposal`,
|
|
81
84
|
subType: `selector`,
|
|
82
85
|
token: selectorToken,
|
|
86
|
+
timestamp: Date.now(),
|
|
83
87
|
})
|
|
84
88
|
}
|
|
85
89
|
break
|
|
@@ -91,10 +95,11 @@ export function disposeSelector(
|
|
|
91
95
|
target.moleculeData.delete(familyMeta.key, familyMeta.subKey)
|
|
92
96
|
store.logger.info(`🔥`, selectorToken.type, key, `deleted`)
|
|
93
97
|
if (isChildStore(target) && target.transactionMeta.phase === `building`) {
|
|
94
|
-
target.transactionMeta.update.
|
|
98
|
+
target.transactionMeta.update.subEvents.push({
|
|
95
99
|
type: `state_disposal`,
|
|
96
100
|
subType: `selector`,
|
|
97
101
|
token: selectorToken,
|
|
102
|
+
timestamp: Date.now(),
|
|
98
103
|
})
|
|
99
104
|
} else {
|
|
100
105
|
store.on.selectorDisposal.next(selectorToken)
|
|
@@ -3,14 +3,10 @@ import { isStateKey } from "../keys"
|
|
|
3
3
|
import { newest } from "../lineage"
|
|
4
4
|
import type { Store } from "../store"
|
|
5
5
|
|
|
6
|
-
export
|
|
6
|
+
export function getSelectorDependencyKeys(
|
|
7
7
|
store: Store,
|
|
8
8
|
key: string,
|
|
9
|
-
): (
|
|
10
|
-
| AtomKey<unknown>
|
|
11
|
-
| ReadonlySelectorKey<unknown>
|
|
12
|
-
| SelectorKey<unknown>
|
|
13
|
-
)[] => {
|
|
9
|
+
): (AtomKey<unknown> | ReadonlySelectorKey<unknown> | SelectorKey<unknown>)[] {
|
|
14
10
|
const sources = newest(store)
|
|
15
11
|
.selectorGraph.getRelationEntries({ downstreamSelectorKey: key })
|
|
16
12
|
.filter(([_, { source }]) => source !== key)
|
|
@@ -7,18 +7,18 @@ import type {
|
|
|
7
7
|
WritableToken,
|
|
8
8
|
WriterToolkit,
|
|
9
9
|
} from "atom.io"
|
|
10
|
-
import type { Json } from "atom.io/json"
|
|
10
|
+
import type { Canonical, Json } from "atom.io/json"
|
|
11
11
|
|
|
12
12
|
import { findInStore } from "../families"
|
|
13
13
|
import { readOrComputeValue } from "../get-state/read-or-compute-value"
|
|
14
14
|
import { newest } from "../lineage"
|
|
15
15
|
import { getJsonToken } from "../mutable"
|
|
16
|
-
import {
|
|
16
|
+
import { operateOnStore } from "../set-state/operate-on-store"
|
|
17
17
|
import type { Store } from "../store"
|
|
18
18
|
import { withdraw } from "../store"
|
|
19
19
|
import { updateSelectorAtoms } from "./update-selector-atoms"
|
|
20
20
|
|
|
21
|
-
export
|
|
21
|
+
export function registerSelector(
|
|
22
22
|
store: Store,
|
|
23
23
|
selectorType:
|
|
24
24
|
| `readonly_held_selector`
|
|
@@ -27,78 +27,68 @@ export const registerSelector = (
|
|
|
27
27
|
| `writable_pure_selector`,
|
|
28
28
|
selectorKey: string,
|
|
29
29
|
covered: Set<string>,
|
|
30
|
-
): WriterToolkit
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
): WriterToolkit {
|
|
31
|
+
return {
|
|
32
|
+
get: (
|
|
33
|
+
...params:
|
|
34
|
+
| [ReadableFamilyToken<any, any>, Json.Serializable]
|
|
35
|
+
| [ReadableToken<any>]
|
|
36
|
+
) => {
|
|
37
|
+
const target = newest(store)
|
|
38
|
+
let dependency: ReadableToken<any>
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if (params.length === 2) {
|
|
41
|
+
const [family, key] = params
|
|
42
|
+
dependency = findInStore(store, family, key)
|
|
43
|
+
} else {
|
|
44
|
+
;[dependency] = params
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const dependencyState = withdraw(store, dependency)
|
|
48
|
+
const dependencyValue = readOrComputeValue(store, dependencyState)
|
|
49
|
+
const dependencyKey = dependency.key
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
51
|
+
store.logger.info(
|
|
52
|
+
`🔌`,
|
|
53
|
+
selectorType,
|
|
54
|
+
selectorKey,
|
|
55
|
+
`registers dependency ( "${dependencyKey}" =`,
|
|
56
|
+
dependencyValue,
|
|
57
|
+
`)`,
|
|
58
|
+
)
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
value = params[2]
|
|
95
|
-
token = findInStore(store, family, key)
|
|
96
|
-
}
|
|
97
|
-
const target = newest(store)
|
|
98
|
-
const state = withdraw(target, token)
|
|
99
|
-
setAtomOrSelector(target, state, value)
|
|
100
|
-
}) as typeof setState,
|
|
101
|
-
find: ((...args: Parameters<typeof findState>) =>
|
|
102
|
-
findInStore(store, ...args)) as typeof findState,
|
|
103
|
-
json: (token) => getJsonToken(store, token),
|
|
104
|
-
})
|
|
60
|
+
target.selectorGraph.set(
|
|
61
|
+
{
|
|
62
|
+
upstreamSelectorKey: dependencyKey,
|
|
63
|
+
downstreamSelectorKey: selectorKey,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
source: dependency.key,
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
updateSelectorAtoms(
|
|
70
|
+
store,
|
|
71
|
+
selectorType,
|
|
72
|
+
selectorKey,
|
|
73
|
+
dependency as any,
|
|
74
|
+
covered,
|
|
75
|
+
)
|
|
76
|
+
return dependencyValue
|
|
77
|
+
},
|
|
78
|
+
set: (<T, K extends Canonical, New extends T, Key extends K>(
|
|
79
|
+
...params:
|
|
80
|
+
| [
|
|
81
|
+
token: WritableFamilyToken<T, K>,
|
|
82
|
+
key: Key,
|
|
83
|
+
value: New | ((oldValue: any) => New),
|
|
84
|
+
]
|
|
85
|
+
| [token: WritableToken<T>, value: New | ((oldValue: T) => New)]
|
|
86
|
+
) => {
|
|
87
|
+
const target = newest(store)
|
|
88
|
+
operateOnStore(target, false, ...params)
|
|
89
|
+
}) as typeof setState,
|
|
90
|
+
find: ((...args: Parameters<typeof findState>) =>
|
|
91
|
+
findInStore(store, ...args)) as typeof findState,
|
|
92
|
+
json: (token) => getJsonToken(store, token),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -2,11 +2,11 @@ import type { Atom, Store } from ".."
|
|
|
2
2
|
import { isAtomKey } from "../keys"
|
|
3
3
|
import { getSelectorDependencyKeys } from "./get-selector-dependency-keys"
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export function traceRootSelectorAtoms(
|
|
6
6
|
store: Store,
|
|
7
7
|
selectorKey: string,
|
|
8
8
|
covered: Set<string> = new Set<string>(),
|
|
9
|
-
): Map<string, Atom<unknown>>
|
|
9
|
+
): Map<string, Atom<unknown>> {
|
|
10
10
|
const dependencies = getSelectorDependencyKeys(store, selectorKey)
|
|
11
11
|
|
|
12
12
|
const roots = new Map<string, Atom<unknown>>()
|
|
@@ -4,7 +4,7 @@ import { newest } from "../lineage"
|
|
|
4
4
|
import type { Store } from "../store"
|
|
5
5
|
import { traceRootSelectorAtoms } from "./trace-selector-atoms"
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export function updateSelectorAtoms(
|
|
8
8
|
store: Store,
|
|
9
9
|
selectorType:
|
|
10
10
|
| `readonly_held_selector`
|
|
@@ -14,7 +14,7 @@ export const updateSelectorAtoms = (
|
|
|
14
14
|
selectorKey: string,
|
|
15
15
|
dependency: ReadonlyPureSelectorToken<unknown> | WritableToken<unknown>,
|
|
16
16
|
covered: Set<string>,
|
|
17
|
-
): void
|
|
17
|
+
): void {
|
|
18
18
|
const target = newest(store)
|
|
19
19
|
const { type: dependencyType, key: dependencyKey } = dependency
|
|
20
20
|
if (dependencyType === `atom` || dependencyType === `mutable_atom`) {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AtomToken,
|
|
3
|
+
AtomUpdateEvent,
|
|
4
|
+
StateUpdate,
|
|
5
|
+
WritableToken,
|
|
6
|
+
} from "atom.io"
|
|
7
|
+
|
|
8
|
+
import type { MutableAtom, WritableState } from ".."
|
|
9
|
+
import { hasRole } from "../atom"
|
|
10
|
+
import { readOrComputeValue } from "../get-state"
|
|
11
|
+
import type { Transceiver } from "../mutable"
|
|
12
|
+
import { isTransceiver } from "../mutable"
|
|
13
|
+
import type { OpenOperation } from "../operation"
|
|
14
|
+
import { deposit, type Store } from "../store"
|
|
15
|
+
import { isChildStore, isRootStore } from "../transaction"
|
|
16
|
+
import { evictDownstreamFromAtom } from "./evict-downstream"
|
|
17
|
+
|
|
18
|
+
export function dispatchOrDeferStateUpdate<T>(
|
|
19
|
+
target: Store & { operation: OpenOperation<any> },
|
|
20
|
+
state: WritableState<T>,
|
|
21
|
+
[oldValue, newValue]: [T, T],
|
|
22
|
+
_stateIsNewlyCreated: boolean,
|
|
23
|
+
): void {
|
|
24
|
+
const { key, subject, type } = state
|
|
25
|
+
|
|
26
|
+
const update: StateUpdate<T> = {
|
|
27
|
+
oldValue: isTransceiver(oldValue) ? oldValue.READONLY_VIEW : oldValue,
|
|
28
|
+
newValue: isTransceiver(newValue) ? newValue.READONLY_VIEW : newValue,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isRootStore(target)) {
|
|
32
|
+
switch (type) {
|
|
33
|
+
case `mutable_atom`:
|
|
34
|
+
target.logger.info(
|
|
35
|
+
`📢`,
|
|
36
|
+
type,
|
|
37
|
+
key,
|
|
38
|
+
`is now (`,
|
|
39
|
+
newValue,
|
|
40
|
+
`) subscribers:`,
|
|
41
|
+
subject.subscribers,
|
|
42
|
+
)
|
|
43
|
+
break
|
|
44
|
+
case `atom`:
|
|
45
|
+
case `writable_pure_selector`:
|
|
46
|
+
case `writable_held_selector`:
|
|
47
|
+
target.logger.info(
|
|
48
|
+
`📢`,
|
|
49
|
+
type,
|
|
50
|
+
key,
|
|
51
|
+
`went (`,
|
|
52
|
+
oldValue,
|
|
53
|
+
`->`,
|
|
54
|
+
newValue,
|
|
55
|
+
`) subscribers:`,
|
|
56
|
+
subject.subscribers,
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
subject.next(update)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (isChildStore(target) && (type === `mutable_atom` || type === `atom`)) {
|
|
63
|
+
if (target.on.transactionApplying.state === null) {
|
|
64
|
+
const token: WritableToken<T> = deposit(state)
|
|
65
|
+
|
|
66
|
+
if (isTransceiver(newValue)) {
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
const { timestamp } = target.operation
|
|
70
|
+
const atomUpdate: AtomUpdateEvent<AtomToken<T>> = {
|
|
71
|
+
type: `atom_update`,
|
|
72
|
+
token,
|
|
73
|
+
timestamp,
|
|
74
|
+
update,
|
|
75
|
+
}
|
|
76
|
+
target.transactionMeta.update.subEvents.push(atomUpdate)
|
|
77
|
+
target.logger.info(
|
|
78
|
+
`📁`,
|
|
79
|
+
`atom`,
|
|
80
|
+
key,
|
|
81
|
+
`stowed (`,
|
|
82
|
+
oldValue,
|
|
83
|
+
`->`,
|
|
84
|
+
newValue,
|
|
85
|
+
`)`,
|
|
86
|
+
)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
if (hasRole(state, `tracker:signal`)) {
|
|
90
|
+
const keyOfMutable = key.slice(1)
|
|
91
|
+
const mutable = target.atoms.get(keyOfMutable) as MutableAtom<
|
|
92
|
+
Transceiver<unknown, any, any>
|
|
93
|
+
>
|
|
94
|
+
const transceiver = readOrComputeValue(target, mutable, `mut`)
|
|
95
|
+
const accepted = transceiver.do(update.newValue) === null
|
|
96
|
+
if (accepted === true) {
|
|
97
|
+
evictDownstreamFromAtom(target, mutable)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { WritableFamilyToken, WritableToken } from "atom.io"
|
|
2
|
+
import { type Canonical, parseJson } from "atom.io/json"
|
|
3
|
+
|
|
4
|
+
import { seekInStore } from "../families"
|
|
5
|
+
import { getFamilyOfToken } from "../families/get-family-of-token"
|
|
6
|
+
import { mintInStore } from "../families/mint-in-store"
|
|
7
|
+
import type { OpenOperation } from "../operation"
|
|
8
|
+
import { closeOperation, openOperation } from "../operation"
|
|
9
|
+
import { type Store, withdraw } from "../store"
|
|
10
|
+
import { dispatchOrDeferStateUpdate } from "./dispatch-state-update"
|
|
11
|
+
import { resetAtomOrSelector } from "./reset-atom-or-selector"
|
|
12
|
+
import { RESET_STATE } from "./reset-in-store"
|
|
13
|
+
import { setAtomOrSelector } from "./set-atom-or-selector"
|
|
14
|
+
|
|
15
|
+
export function operateOnStore<T, New extends T>(
|
|
16
|
+
store: Store,
|
|
17
|
+
ownOp: boolean,
|
|
18
|
+
...params:
|
|
19
|
+
| [
|
|
20
|
+
token: WritableFamilyToken<T, Canonical>,
|
|
21
|
+
key: Canonical,
|
|
22
|
+
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
23
|
+
]
|
|
24
|
+
| [
|
|
25
|
+
token: WritableToken<T>,
|
|
26
|
+
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
27
|
+
]
|
|
28
|
+
): void {
|
|
29
|
+
let existingToken: WritableToken<T> | undefined
|
|
30
|
+
let brandNewToken: WritableToken<T> | undefined
|
|
31
|
+
let token: WritableToken<T>
|
|
32
|
+
let family: WritableFamilyToken<T, Canonical> | null
|
|
33
|
+
let key: Canonical | null
|
|
34
|
+
let value: New | typeof RESET_STATE | ((oldValue: T) => New)
|
|
35
|
+
if (params.length === 2) {
|
|
36
|
+
token = params[0]
|
|
37
|
+
value = params[1]
|
|
38
|
+
if (token.family) {
|
|
39
|
+
// biome-ignore lint/style/noNonNullAssertion: this token belongs to a family
|
|
40
|
+
family = getFamilyOfToken(store, token)!
|
|
41
|
+
key = parseJson(token.family.subKey)
|
|
42
|
+
existingToken = seekInStore(store, family, key)
|
|
43
|
+
if (!existingToken) {
|
|
44
|
+
brandNewToken = mintInStore(store, family, key)
|
|
45
|
+
token = brandNewToken
|
|
46
|
+
} else {
|
|
47
|
+
token = existingToken
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
family = params[0]
|
|
52
|
+
key = params[1]
|
|
53
|
+
value = params[2]
|
|
54
|
+
existingToken = seekInStore(store, family, key)
|
|
55
|
+
if (!existingToken) {
|
|
56
|
+
brandNewToken = mintInStore(store, family, key)
|
|
57
|
+
token = brandNewToken
|
|
58
|
+
} else {
|
|
59
|
+
token = existingToken
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const action = value === RESET_STATE ? `reset` : `set`
|
|
64
|
+
|
|
65
|
+
let target: Store & { operation: OpenOperation }
|
|
66
|
+
|
|
67
|
+
if (ownOp) {
|
|
68
|
+
const result = openOperation(store, token)
|
|
69
|
+
const rejected = typeof result === `number`
|
|
70
|
+
if (rejected) {
|
|
71
|
+
const rejectionTime = result
|
|
72
|
+
const unsubscribe = store.on.operationClose.subscribe(
|
|
73
|
+
`waiting to ${action} "${token.key}" at T-${rejectionTime}`,
|
|
74
|
+
function waitUntilOperationCloseToSetState() {
|
|
75
|
+
unsubscribe()
|
|
76
|
+
store.logger.info(
|
|
77
|
+
`🟢`,
|
|
78
|
+
token.type,
|
|
79
|
+
token.key,
|
|
80
|
+
`resuming deferred`,
|
|
81
|
+
action,
|
|
82
|
+
`from T-${rejectionTime}`,
|
|
83
|
+
)
|
|
84
|
+
operateOnStore(store, ownOp, token, value)
|
|
85
|
+
},
|
|
86
|
+
)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
target = result
|
|
90
|
+
} else {
|
|
91
|
+
target = store as Store & { operation: OpenOperation }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (`counterfeit` in token && `family` in token) {
|
|
95
|
+
const subKey = token.family.subKey
|
|
96
|
+
const disposal = store.disposalTraces.buffer.find(
|
|
97
|
+
(item) => item?.key === subKey,
|
|
98
|
+
)
|
|
99
|
+
store.logger.error(
|
|
100
|
+
`❌`,
|
|
101
|
+
token.type,
|
|
102
|
+
token.key,
|
|
103
|
+
`could not be`,
|
|
104
|
+
action,
|
|
105
|
+
`because it was not found in the store "${store.config.name}".`,
|
|
106
|
+
disposal
|
|
107
|
+
? `This state was previously disposed:\n${disposal.trace}`
|
|
108
|
+
: `No previous disposal trace was found.`,
|
|
109
|
+
)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const state = withdraw(target, token)
|
|
114
|
+
let protoUpdate: [T, T]
|
|
115
|
+
if (value === RESET_STATE) {
|
|
116
|
+
protoUpdate = resetAtomOrSelector(target, state)
|
|
117
|
+
} else {
|
|
118
|
+
protoUpdate = setAtomOrSelector(target, state, value)
|
|
119
|
+
}
|
|
120
|
+
const isNewlyCreated = Boolean(brandNewToken)
|
|
121
|
+
dispatchOrDeferStateUpdate(target, state, protoUpdate, isNewlyCreated)
|
|
122
|
+
|
|
123
|
+
if (ownOp) {
|
|
124
|
+
closeOperation(target)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -1,40 +1,49 @@
|
|
|
1
|
-
import type { Atom, WritableState } from ".."
|
|
1
|
+
import type { Atom, OpenOperation, Store, WritableState } from ".."
|
|
2
2
|
import { traceRootSelectorAtoms } from ".."
|
|
3
|
-
import
|
|
3
|
+
import { dispatchOrDeferStateUpdate } from "./dispatch-state-update"
|
|
4
4
|
import { setAtom } from "./set-atom"
|
|
5
5
|
|
|
6
|
-
function resetAtom
|
|
7
|
-
|
|
6
|
+
function resetAtom<T>(
|
|
7
|
+
target: Store & { operation: OpenOperation },
|
|
8
|
+
atom: Atom<T>,
|
|
9
|
+
): [oldValue: T, newValue: T] {
|
|
10
|
+
switch (atom.type) {
|
|
8
11
|
case `mutable_atom`:
|
|
9
|
-
setAtom(
|
|
10
|
-
return
|
|
12
|
+
return setAtom(target, atom, new atom.class())
|
|
11
13
|
case `atom`: {
|
|
12
|
-
let def =
|
|
14
|
+
let def = atom.default
|
|
13
15
|
if (def instanceof Function) {
|
|
14
16
|
def = def()
|
|
15
17
|
}
|
|
16
|
-
setAtom(
|
|
18
|
+
return setAtom(target, atom, def)
|
|
17
19
|
}
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export function resetAtomOrSelector(
|
|
22
|
-
|
|
23
|
-
state: WritableState<
|
|
24
|
-
):
|
|
23
|
+
export function resetAtomOrSelector<T>(
|
|
24
|
+
target: Store & { operation: OpenOperation },
|
|
25
|
+
state: WritableState<T>,
|
|
26
|
+
): [oldValue: T, newValue: T] {
|
|
27
|
+
let protoUpdate: [T, T]
|
|
25
28
|
switch (state.type) {
|
|
26
29
|
case `atom`:
|
|
27
30
|
case `mutable_atom`:
|
|
28
|
-
resetAtom(
|
|
31
|
+
protoUpdate = resetAtom(target, state)
|
|
29
32
|
break
|
|
30
33
|
case `writable_pure_selector`:
|
|
31
34
|
case `writable_held_selector`:
|
|
32
35
|
{
|
|
33
|
-
const
|
|
36
|
+
const oldValue = state.getFrom(target)
|
|
37
|
+
const atoms = traceRootSelectorAtoms(target, state.key)
|
|
34
38
|
for (const atom of atoms.values()) {
|
|
35
|
-
resetAtom(
|
|
39
|
+
const rootProtoUpdate = resetAtom(target, atom)
|
|
40
|
+
dispatchOrDeferStateUpdate(target, state, rootProtoUpdate, false)
|
|
36
41
|
}
|
|
42
|
+
const newValue = state.getFrom(target)
|
|
43
|
+
protoUpdate = [oldValue, newValue]
|
|
37
44
|
}
|
|
38
45
|
break
|
|
39
46
|
}
|
|
47
|
+
|
|
48
|
+
return protoUpdate
|
|
40
49
|
}
|
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
import type { WritableState } from ".."
|
|
2
|
+
import type { OpenOperation } from "../operation"
|
|
2
3
|
import type { Store } from "../store"
|
|
3
4
|
import { setAtom } from "./set-atom"
|
|
5
|
+
import { setSelector } from "./set-selector"
|
|
4
6
|
|
|
5
7
|
export const setAtomOrSelector = <T>(
|
|
6
|
-
|
|
8
|
+
target: Store & { operation: OpenOperation },
|
|
7
9
|
state: WritableState<T>,
|
|
8
10
|
value: T | ((oldValue: T) => T),
|
|
9
|
-
):
|
|
11
|
+
): [oldValue: T, newValue: T] => {
|
|
12
|
+
let protoUpdate: [T, T]
|
|
10
13
|
switch (state.type) {
|
|
11
14
|
case `atom`:
|
|
12
15
|
case `mutable_atom`:
|
|
13
|
-
setAtom(
|
|
16
|
+
protoUpdate = setAtom(target, state, value)
|
|
14
17
|
break
|
|
15
18
|
case `writable_pure_selector`:
|
|
16
19
|
case `writable_held_selector`:
|
|
17
|
-
state
|
|
20
|
+
protoUpdate = setSelector(target, state, value)
|
|
18
21
|
break
|
|
19
22
|
}
|
|
23
|
+
|
|
24
|
+
return protoUpdate
|
|
20
25
|
}
|