atom.io 0.36.3 → 0.37.1
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 +71 -102
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +566 -515
- 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 +6 -6
- package/src/internal/atom/dispose-atom.ts +16 -9
- package/src/internal/caching.ts +1 -1
- 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 +7 -7
- 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/get-from-store.ts +19 -6
- package/src/internal/get-state/read-or-compute-value.ts +4 -2
- package/src/internal/index.ts +25 -36
- 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 +4 -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 +15 -28
- 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
|
@@ -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
|
}
|
|
@@ -1,65 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
import type { Atom, MutableAtom, Store } from ".."
|
|
4
|
-
import { hasRole } from "../atom/has-role"
|
|
1
|
+
import type { Atom, OpenOperation, Store } from ".."
|
|
5
2
|
import { writeToCache } from "../caching"
|
|
6
3
|
import { readOrComputeValue } from "../get-state/read-or-compute-value"
|
|
7
|
-
import { isTransceiver, type Transceiver } from "../mutable"
|
|
8
4
|
import { markDone } from "../operation"
|
|
9
|
-
import { isChildStore } from "../transaction/is-root-store"
|
|
10
5
|
import { become } from "./become"
|
|
11
|
-
import { emitUpdate } from "./emit-update"
|
|
12
6
|
import { evictDownstreamFromAtom } from "./evict-downstream"
|
|
13
7
|
|
|
14
8
|
export const setAtom = <T>(
|
|
15
|
-
target: Store,
|
|
9
|
+
target: Store & { operation: OpenOperation<any> },
|
|
16
10
|
atom: Atom<T>,
|
|
17
11
|
next: T | ((oldValue: T) => T),
|
|
18
|
-
):
|
|
12
|
+
): [oldValue: T, newValue: T] => {
|
|
19
13
|
const oldValue = readOrComputeValue(target, atom, `mut`)
|
|
20
14
|
let newValue = become(next)(oldValue)
|
|
21
15
|
target.logger.info(`📝`, `atom`, atom.key, `set to`, newValue)
|
|
22
16
|
newValue = writeToCache(target, atom, newValue)
|
|
23
17
|
markDone(target, atom.key)
|
|
24
18
|
evictDownstreamFromAtom(target, atom)
|
|
25
|
-
|
|
26
|
-
if (!isChildStore(target)) {
|
|
27
|
-
emitUpdate(target, atom, update)
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
if (target.on.transactionApplying.state === null) {
|
|
31
|
-
const { key } = atom
|
|
32
|
-
if (isTransceiver(update.newValue)) {
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
const atomUpdate: KeyedStateUpdate<T> = {
|
|
36
|
-
type: `atom_update`,
|
|
37
|
-
key,
|
|
38
|
-
...update,
|
|
39
|
-
}
|
|
40
|
-
if (atom.family) {
|
|
41
|
-
atomUpdate.family = atom.family
|
|
42
|
-
}
|
|
43
|
-
target.transactionMeta.update.updates.push(atomUpdate)
|
|
44
|
-
target.logger.info(
|
|
45
|
-
`📁`,
|
|
46
|
-
`atom`,
|
|
47
|
-
key,
|
|
48
|
-
`stowed (`,
|
|
49
|
-
update.oldValue,
|
|
50
|
-
`->`,
|
|
51
|
-
update.newValue,
|
|
52
|
-
`)`,
|
|
53
|
-
)
|
|
54
|
-
} else if (hasRole(atom, `tracker:signal`)) {
|
|
55
|
-
const key = atom.key.slice(1)
|
|
56
|
-
const mutable = target.atoms.get(key) as MutableAtom<
|
|
57
|
-
Transceiver<unknown, any, any>
|
|
58
|
-
>
|
|
59
|
-
const transceiver = readOrComputeValue(target, mutable, `mut`)
|
|
60
|
-
const accepted = transceiver.do(update.newValue) === null
|
|
61
|
-
if (accepted === true) {
|
|
62
|
-
evictDownstreamFromAtom(target, mutable)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
19
|
+
return [oldValue, newValue]
|
|
65
20
|
}
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import type { WritableFamilyToken, WritableToken } from "atom.io"
|
|
2
|
-
import {
|
|
2
|
+
import type { Canonical } from "atom.io/json"
|
|
3
3
|
|
|
4
|
-
import { findInStore } from "../families"
|
|
5
|
-
import { getFamilyOfToken } from "../families/get-family-of-token"
|
|
6
|
-
import { closeOperation, openOperation } from "../operation"
|
|
7
4
|
import type { Store } from "../store"
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { RESET_STATE } from "./reset-in-store"
|
|
11
|
-
import { setAtomOrSelector } from "./set-atom-or-selector"
|
|
5
|
+
import { operateOnStore } from "./operate-on-store"
|
|
6
|
+
import type { RESET_STATE } from "./reset-in-store"
|
|
12
7
|
|
|
13
8
|
export function setIntoStore<T, New extends T>(
|
|
14
9
|
store: Store,
|
|
@@ -16,10 +11,15 @@ export function setIntoStore<T, New extends T>(
|
|
|
16
11
|
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
17
12
|
): void
|
|
18
13
|
|
|
19
|
-
export function setIntoStore<
|
|
14
|
+
export function setIntoStore<
|
|
15
|
+
T,
|
|
16
|
+
K extends Canonical,
|
|
17
|
+
New extends T,
|
|
18
|
+
Key extends K,
|
|
19
|
+
>(
|
|
20
20
|
store: Store,
|
|
21
21
|
token: WritableFamilyToken<T, K>,
|
|
22
|
-
key:
|
|
22
|
+
key: Key,
|
|
23
23
|
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
24
24
|
): void
|
|
25
25
|
|
|
@@ -36,71 +36,5 @@ export function setIntoStore<T, New extends T>(
|
|
|
36
36
|
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
37
37
|
]
|
|
38
38
|
): void {
|
|
39
|
-
|
|
40
|
-
let family: WritableFamilyToken<T, Canonical> | null
|
|
41
|
-
let key: Canonical | null
|
|
42
|
-
let value: New | typeof RESET_STATE | ((oldValue: T) => New)
|
|
43
|
-
if (params.length === 2) {
|
|
44
|
-
token = params[0]
|
|
45
|
-
value = params[1]
|
|
46
|
-
if (token.family) {
|
|
47
|
-
// biome-ignore lint/style/noNonNullAssertion: this token belongs to a family
|
|
48
|
-
family = getFamilyOfToken(store, token)!
|
|
49
|
-
key = parseJson(token.family.subKey)
|
|
50
|
-
token = findInStore(store, family, key)
|
|
51
|
-
}
|
|
52
|
-
} else {
|
|
53
|
-
family = params[0]
|
|
54
|
-
key = params[1]
|
|
55
|
-
value = params[2]
|
|
56
|
-
token = findInStore(store, family, key)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const action = value === RESET_STATE ? `reset` : `set`
|
|
60
|
-
|
|
61
|
-
if (`counterfeit` in token && `family` in token) {
|
|
62
|
-
const subKey = token.family.subKey
|
|
63
|
-
const disposal = store.disposalTraces.buffer.find(
|
|
64
|
-
(item) => item?.key === subKey,
|
|
65
|
-
)
|
|
66
|
-
store.logger.error(
|
|
67
|
-
`❌`,
|
|
68
|
-
token.type,
|
|
69
|
-
token.key,
|
|
70
|
-
`could not be`,
|
|
71
|
-
action,
|
|
72
|
-
`because it was not found in the store "${store.config.name}".`,
|
|
73
|
-
disposal
|
|
74
|
-
? `This state was previously disposed:\n${disposal.trace}`
|
|
75
|
-
: `No previous disposal trace was found.`,
|
|
76
|
-
)
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const rejectionTime = openOperation(store, token)
|
|
81
|
-
if (rejectionTime) {
|
|
82
|
-
const unsubscribe = store.on.operationClose.subscribe(
|
|
83
|
-
`waiting to ${action} "${token.key}" at T-${rejectionTime}`,
|
|
84
|
-
function waitUntilOperationCloseToSetState() {
|
|
85
|
-
unsubscribe()
|
|
86
|
-
store.logger.info(
|
|
87
|
-
`🟢`,
|
|
88
|
-
token.type,
|
|
89
|
-
token.key,
|
|
90
|
-
`resuming deferred`,
|
|
91
|
-
action,
|
|
92
|
-
`from T-${rejectionTime}`,
|
|
93
|
-
)
|
|
94
|
-
setIntoStore(store, token, value)
|
|
95
|
-
},
|
|
96
|
-
)
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
const state = withdraw(store, token)
|
|
100
|
-
if (value === RESET_STATE) {
|
|
101
|
-
resetAtomOrSelector(store, state)
|
|
102
|
-
} else {
|
|
103
|
-
setAtomOrSelector(store, state, value)
|
|
104
|
-
}
|
|
105
|
-
closeOperation(store)
|
|
39
|
+
operateOnStore(store, true, ...params)
|
|
106
40
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { WritableSelector } from ".."
|
|
2
|
+
import { writeToCache } from "../caching"
|
|
3
|
+
import { markDone, type OpenOperation } from "../operation"
|
|
4
|
+
import type { Store } from "../store"
|
|
5
|
+
import { become } from "./become"
|
|
6
|
+
|
|
7
|
+
export function setSelector<T>(
|
|
8
|
+
target: Store & { operation: OpenOperation<any> },
|
|
9
|
+
selector: WritableSelector<T>,
|
|
10
|
+
next: T | ((oldValue: T) => T),
|
|
11
|
+
): [oldValue: T, newValue: T] {
|
|
12
|
+
let oldValue: T
|
|
13
|
+
let newValue: T
|
|
14
|
+
let constant: T
|
|
15
|
+
|
|
16
|
+
const { type, key } = selector
|
|
17
|
+
|
|
18
|
+
switch (selector.type) {
|
|
19
|
+
case `writable_pure_selector`:
|
|
20
|
+
oldValue = selector.getFrom(target)
|
|
21
|
+
newValue = become(next)(oldValue)
|
|
22
|
+
writeToCache(target, selector, newValue)
|
|
23
|
+
break
|
|
24
|
+
case `writable_held_selector`:
|
|
25
|
+
constant = selector.const
|
|
26
|
+
become(next)(constant)
|
|
27
|
+
oldValue = constant
|
|
28
|
+
newValue = constant
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
target.logger.info(`📝`, type, key, `setting to`, newValue)
|
|
32
|
+
markDone(target, key)
|
|
33
|
+
selector.setSelf(newValue)
|
|
34
|
+
return [oldValue, newValue]
|
|
35
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AtomToken,
|
|
3
3
|
Logger,
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
MoleculeCreationEvent,
|
|
5
|
+
MoleculeDisposalEvent,
|
|
6
6
|
SelectorToken,
|
|
7
7
|
TimelineToken,
|
|
8
8
|
TransactionToken,
|
|
@@ -253,8 +253,8 @@ export type StoreEventCarrier = {
|
|
|
253
253
|
transactionCreation: Subject<TransactionToken<Fn>>
|
|
254
254
|
transactionApplying: StatefulSubject<TransactionProgress<Fn> | null>
|
|
255
255
|
operationClose: Subject<OperationProgress>
|
|
256
|
-
moleculeCreation: Subject<
|
|
257
|
-
moleculeDisposal: Subject<
|
|
256
|
+
moleculeCreation: Subject<MoleculeCreationEvent>
|
|
257
|
+
moleculeDisposal: Subject<MoleculeDisposalEvent>
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
declare global {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ReadableToken,
|
|
3
|
+
TimelineEvent,
|
|
3
4
|
TimelineManageable,
|
|
4
5
|
TimelineToken,
|
|
5
|
-
TimelineUpdate,
|
|
6
6
|
TransactionToken,
|
|
7
7
|
TransactionUpdateHandler,
|
|
8
8
|
UpdateHandler,
|
|
@@ -30,7 +30,7 @@ export function subscribeInStore<F extends Fn>(
|
|
|
30
30
|
export function subscribeInStore<M extends TimelineManageable>(
|
|
31
31
|
store: Store,
|
|
32
32
|
token: TimelineToken<M>,
|
|
33
|
-
handleUpdate: (update:
|
|
33
|
+
handleUpdate: (update: TimelineEvent<M> | `redo` | `undo`) => void,
|
|
34
34
|
key?: string,
|
|
35
35
|
): () => void
|
|
36
36
|
export function subscribeInStore<M extends TimelineManageable>(
|
|
@@ -39,7 +39,7 @@ export function subscribeInStore<M extends TimelineManageable>(
|
|
|
39
39
|
handleUpdate:
|
|
40
40
|
| TransactionUpdateHandler<any>
|
|
41
41
|
| UpdateHandler<any>
|
|
42
|
-
| ((update:
|
|
42
|
+
| ((update: TimelineEvent<M> | `redo` | `undo`) => void),
|
|
43
43
|
key?: string,
|
|
44
44
|
): () => void
|
|
45
45
|
export function subscribeInStore(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TimelineManageable, TimelineToken
|
|
1
|
+
import type { TimelineEvent, TimelineManageable, TimelineToken } from "atom.io"
|
|
2
2
|
|
|
3
3
|
import type { Store } from "../store/store"
|
|
4
4
|
import { withdraw } from "../store/withdraw"
|
|
@@ -7,7 +7,7 @@ export const subscribeToTimeline = <ManagedAtom extends TimelineManageable>(
|
|
|
7
7
|
store: Store,
|
|
8
8
|
token: TimelineToken<ManagedAtom>,
|
|
9
9
|
key: string,
|
|
10
|
-
handleUpdate: (update:
|
|
10
|
+
handleUpdate: (update: TimelineEvent<any> | `redo` | `undo`) => void,
|
|
11
11
|
): (() => void) => {
|
|
12
12
|
const tl = withdraw(store, token)
|
|
13
13
|
store.logger.info(`👀`, `timeline`, token.key, `Adding subscription "${key}"`)
|
|
@@ -1,78 +1,38 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AtomFamilyToken,
|
|
3
3
|
AtomToken,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
StateCreation,
|
|
9
|
-
StateDisposal,
|
|
10
|
-
StateUpdate,
|
|
4
|
+
AtomUpdateEvent,
|
|
5
|
+
StateCreationEvent,
|
|
6
|
+
StateDisposalEvent,
|
|
7
|
+
TimelineEvent,
|
|
11
8
|
TimelineManageable,
|
|
12
9
|
TimelineOptions,
|
|
13
10
|
TimelineToken,
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
TransactionOutcomeEvent,
|
|
12
|
+
TransactionSubEvent,
|
|
16
13
|
TransactionToken,
|
|
17
|
-
TransactionUpdate,
|
|
18
|
-
TransactionUpdateContent,
|
|
19
14
|
} from "atom.io"
|
|
20
15
|
|
|
21
16
|
import { newest } from "../lineage"
|
|
22
17
|
import { getUpdateToken } from "../mutable"
|
|
23
|
-
import { type Store, withdraw } from "../store"
|
|
18
|
+
import { deposit, type Store, withdraw } from "../store"
|
|
24
19
|
import { Subject } from "../subject"
|
|
25
20
|
import { isChildStore } from "../transaction"
|
|
26
|
-
import type { Flat, Fn } from "../utility-types"
|
|
27
|
-
|
|
28
|
-
export type TimelineAtomUpdate<ManagedAtom extends TimelineManageable> = Flat<
|
|
29
|
-
StateUpdate<TokenType<ManagedAtom>> & {
|
|
30
|
-
key: string
|
|
31
|
-
type: `atom_update`
|
|
32
|
-
timestamp: number
|
|
33
|
-
family?: FamilyMetadata
|
|
34
|
-
}
|
|
35
|
-
>
|
|
36
|
-
export type TimelineSelectorUpdate<ManagedAtom extends TimelineManageable> = {
|
|
37
|
-
key: string
|
|
38
|
-
type: `selector_update`
|
|
39
|
-
timestamp: number
|
|
40
|
-
atomUpdates: Omit<TimelineAtomUpdate<ManagedAtom>, `timestamp`>[]
|
|
41
|
-
}
|
|
42
|
-
export type TimelineTransactionUpdate = Flat<
|
|
43
|
-
TransactionUpdate<Fn> & {
|
|
44
|
-
key: string
|
|
45
|
-
type: `transaction_update`
|
|
46
|
-
timestamp: number
|
|
47
|
-
}
|
|
48
|
-
>
|
|
49
|
-
export type TimelineStateCreation<T extends ReadableToken<any>> = Flat<
|
|
50
|
-
StateCreation<T> & { timestamp: number }
|
|
51
|
-
>
|
|
52
|
-
export type TimelineStateDisposal<T extends ReadableToken<any>> = Flat<
|
|
53
|
-
StateDisposal<T> & { timestamp: number }
|
|
54
|
-
>
|
|
55
|
-
export type TimelineMoleculeCreation = Flat<
|
|
56
|
-
MoleculeCreation & { timestamp: number }
|
|
57
|
-
>
|
|
58
|
-
export type TimelineMoleculeDisposal = Flat<
|
|
59
|
-
MoleculeDisposal & { timestamp: number }
|
|
60
|
-
>
|
|
61
21
|
|
|
62
22
|
export type Timeline<ManagedAtom extends TimelineManageable> = {
|
|
63
23
|
type: `timeline`
|
|
64
24
|
key: string
|
|
65
25
|
at: number
|
|
66
26
|
shouldCapture?: (
|
|
67
|
-
update:
|
|
27
|
+
update: TimelineEvent<ManagedAtom>,
|
|
68
28
|
timeline: Timeline<ManagedAtom>,
|
|
69
29
|
) => boolean
|
|
70
30
|
timeTraveling: `into_future` | `into_past` | null
|
|
71
|
-
history:
|
|
31
|
+
history: TimelineEvent<ManagedAtom>[]
|
|
72
32
|
selectorTime: number | null
|
|
73
33
|
transactionKey: string | null
|
|
74
34
|
install: (store: Store) => void
|
|
75
|
-
subject: Subject<
|
|
35
|
+
subject: Subject<TimelineEvent<ManagedAtom> | `redo` | `undo`>
|
|
76
36
|
subscriptions: Map<string, () => void>
|
|
77
37
|
}
|
|
78
38
|
|
|
@@ -187,15 +147,15 @@ function addAtomToTimeline(
|
|
|
187
147
|
`timeline`,
|
|
188
148
|
function timelineCapturesAtomUpdate(update) {
|
|
189
149
|
const target = newest(store)
|
|
190
|
-
const
|
|
150
|
+
const currentSelectorToken =
|
|
191
151
|
store.operation.open &&
|
|
192
152
|
store.operation.token.type === `writable_pure_selector`
|
|
193
|
-
? store.operation.token
|
|
153
|
+
? store.operation.token
|
|
194
154
|
: null
|
|
195
155
|
const currentSelectorTime =
|
|
196
156
|
store.operation.open &&
|
|
197
157
|
store.operation.token.type === `writable_pure_selector`
|
|
198
|
-
? store.operation.
|
|
158
|
+
? store.operation.timestamp
|
|
199
159
|
: null
|
|
200
160
|
|
|
201
161
|
const txUpdateInProgress = target.on.transactionApplying.state?.update
|
|
@@ -211,28 +171,30 @@ function addAtomToTimeline(
|
|
|
211
171
|
`->`,
|
|
212
172
|
update.newValue,
|
|
213
173
|
txUpdateInProgress
|
|
214
|
-
? `in transaction "${txUpdateInProgress.key}"`
|
|
215
|
-
:
|
|
216
|
-
? `in selector "${
|
|
174
|
+
? `in transaction "${txUpdateInProgress.token.key}"`
|
|
175
|
+
: currentSelectorToken
|
|
176
|
+
? `in selector "${currentSelectorToken.key}"`
|
|
217
177
|
: ``,
|
|
218
178
|
)
|
|
219
179
|
if (tl.timeTraveling === null) {
|
|
220
180
|
if (txUpdateInProgress) {
|
|
221
181
|
joinTransaction(store, tl, txUpdateInProgress)
|
|
222
|
-
} else if (
|
|
223
|
-
let latestUpdate:
|
|
182
|
+
} else if (currentSelectorToken && currentSelectorTime) {
|
|
183
|
+
let latestUpdate: TimelineEvent<any> | undefined = tl.history.at(-1)
|
|
224
184
|
|
|
225
185
|
if (currentSelectorTime !== tl.selectorTime) {
|
|
226
186
|
latestUpdate = {
|
|
227
187
|
type: `selector_update`,
|
|
228
188
|
timestamp: currentSelectorTime,
|
|
229
|
-
key: currentSelectorKey,
|
|
189
|
+
// key: currentSelectorKey,
|
|
190
|
+
token: currentSelectorToken,
|
|
230
191
|
atomUpdates: [],
|
|
231
192
|
}
|
|
232
193
|
latestUpdate.atomUpdates.push({
|
|
233
|
-
key: atom.key,
|
|
234
194
|
type: `atom_update`,
|
|
235
|
-
|
|
195
|
+
token: atomToken,
|
|
196
|
+
update,
|
|
197
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
236
198
|
})
|
|
237
199
|
if (tl.at !== tl.history.length) {
|
|
238
200
|
tl.history.splice(tl.at)
|
|
@@ -244,8 +206,10 @@ function addAtomToTimeline(
|
|
|
244
206
|
`⌛`,
|
|
245
207
|
`timeline`,
|
|
246
208
|
tl.key,
|
|
247
|
-
`got a selector_update "${
|
|
248
|
-
latestUpdate.atomUpdates.map(
|
|
209
|
+
`got a selector_update "${currentSelectorToken.key}" with`,
|
|
210
|
+
latestUpdate.atomUpdates.map(
|
|
211
|
+
(atomUpdate) => atomUpdate.token.key,
|
|
212
|
+
),
|
|
249
213
|
)
|
|
250
214
|
|
|
251
215
|
tl.at = tl.history.length
|
|
@@ -253,16 +217,19 @@ function addAtomToTimeline(
|
|
|
253
217
|
} else {
|
|
254
218
|
if (latestUpdate?.type === `selector_update`) {
|
|
255
219
|
latestUpdate.atomUpdates.push({
|
|
256
|
-
key: atom.key,
|
|
257
220
|
type: `atom_update`,
|
|
258
|
-
|
|
221
|
+
token: atomToken,
|
|
222
|
+
update,
|
|
223
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
259
224
|
})
|
|
260
225
|
store.logger.info(
|
|
261
226
|
`⌛`,
|
|
262
227
|
`timeline`,
|
|
263
228
|
tl.key,
|
|
264
|
-
`set selector_update "${
|
|
265
|
-
latestUpdate?.atomUpdates.map(
|
|
229
|
+
`set selector_update "${currentSelectorToken.key}" to`,
|
|
230
|
+
latestUpdate?.atomUpdates.map(
|
|
231
|
+
(atomUpdate) => atomUpdate.token.key,
|
|
232
|
+
),
|
|
266
233
|
)
|
|
267
234
|
}
|
|
268
235
|
}
|
|
@@ -282,15 +249,11 @@ function addAtomToTimeline(
|
|
|
282
249
|
if (tl.at !== tl.history.length) {
|
|
283
250
|
tl.history.splice(tl.at)
|
|
284
251
|
}
|
|
285
|
-
const atomUpdate:
|
|
252
|
+
const atomUpdate: AtomUpdateEvent<any> = {
|
|
286
253
|
type: `atom_update`,
|
|
254
|
+
token: deposit(atom),
|
|
255
|
+
update,
|
|
287
256
|
timestamp,
|
|
288
|
-
key: atom.key,
|
|
289
|
-
oldValue: update.oldValue,
|
|
290
|
-
newValue: update.newValue,
|
|
291
|
-
}
|
|
292
|
-
if (atom.family) {
|
|
293
|
-
atomUpdate.family = atom.family
|
|
294
257
|
}
|
|
295
258
|
const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true
|
|
296
259
|
store.logger.info(
|
|
@@ -340,9 +303,9 @@ function addAtomFamilyToTimeline(
|
|
|
340
303
|
function joinTransaction(
|
|
341
304
|
store: Store,
|
|
342
305
|
tl: Timeline<any>,
|
|
343
|
-
txUpdateInProgress:
|
|
306
|
+
txUpdateInProgress: TransactionOutcomeEvent<TransactionToken<any>>,
|
|
344
307
|
) {
|
|
345
|
-
const currentTxKey = txUpdateInProgress.key
|
|
308
|
+
const currentTxKey = txUpdateInProgress.token.key
|
|
346
309
|
const currentTxInstanceId = txUpdateInProgress.id
|
|
347
310
|
const currentTxToken: TransactionToken<any> = {
|
|
348
311
|
key: currentTxKey,
|
|
@@ -364,15 +327,16 @@ function joinTransaction(
|
|
|
364
327
|
// biome-ignore lint/style/noNonNullAssertion: we are in the context of this timeline
|
|
365
328
|
const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key)!
|
|
366
329
|
|
|
367
|
-
const
|
|
368
|
-
transactionUpdate.
|
|
330
|
+
const subEventsFiltered = filterTransactionSubEvents(
|
|
331
|
+
transactionUpdate.subEvents,
|
|
369
332
|
timelineTopics,
|
|
370
333
|
)
|
|
371
334
|
|
|
372
|
-
const timelineTransactionUpdate:
|
|
373
|
-
|
|
335
|
+
const timelineTransactionUpdate: TransactionOutcomeEvent<
|
|
336
|
+
TransactionToken<any>
|
|
337
|
+
> = {
|
|
374
338
|
...transactionUpdate,
|
|
375
|
-
|
|
339
|
+
subEvents: subEventsFiltered,
|
|
376
340
|
}
|
|
377
341
|
const willCapture =
|
|
378
342
|
tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true
|
|
@@ -387,19 +351,20 @@ function joinTransaction(
|
|
|
387
351
|
}
|
|
388
352
|
}
|
|
389
353
|
|
|
390
|
-
function
|
|
391
|
-
updates:
|
|
354
|
+
function filterTransactionSubEvents(
|
|
355
|
+
updates: TransactionSubEvent[],
|
|
392
356
|
timelineTopics: Set<string>,
|
|
393
|
-
):
|
|
357
|
+
): TransactionSubEvent[] {
|
|
394
358
|
return updates
|
|
395
359
|
.filter((updateFromTx) => {
|
|
396
|
-
if (updateFromTx.type === `
|
|
360
|
+
if (updateFromTx.type === `transaction_outcome`) {
|
|
397
361
|
return true
|
|
398
362
|
}
|
|
399
363
|
|
|
400
364
|
let key: string
|
|
401
365
|
let familyKey: string | undefined
|
|
402
366
|
switch (updateFromTx.type) {
|
|
367
|
+
case `atom_update`:
|
|
403
368
|
case `state_creation`:
|
|
404
369
|
case `state_disposal`:
|
|
405
370
|
key = updateFromTx.token.key
|
|
@@ -409,11 +374,6 @@ function filterTransactionUpdates(
|
|
|
409
374
|
case `molecule_disposal`:
|
|
410
375
|
case `molecule_transfer`:
|
|
411
376
|
return true // always include
|
|
412
|
-
case `atom_update`:
|
|
413
|
-
case `selector_update`:
|
|
414
|
-
key = updateFromTx.key
|
|
415
|
-
familyKey = updateFromTx.family?.key
|
|
416
|
-
break
|
|
417
377
|
}
|
|
418
378
|
timelineTopics.has(key)
|
|
419
379
|
if (familyKey && timelineTopics.has(familyKey)) {
|
|
@@ -421,12 +381,12 @@ function filterTransactionUpdates(
|
|
|
421
381
|
}
|
|
422
382
|
return timelineTopics.has(key)
|
|
423
383
|
})
|
|
424
|
-
.map((updateFromTx) => {
|
|
425
|
-
if (`
|
|
384
|
+
.map((updateFromTx): TransactionSubEvent => {
|
|
385
|
+
if (`subEvents` in updateFromTx) {
|
|
426
386
|
return {
|
|
427
387
|
...updateFromTx,
|
|
428
|
-
|
|
429
|
-
updateFromTx.
|
|
388
|
+
subEvents: filterTransactionSubEvents(
|
|
389
|
+
updateFromTx.subEvents,
|
|
430
390
|
timelineTopics,
|
|
431
391
|
),
|
|
432
392
|
}
|
|
@@ -437,13 +397,9 @@ function filterTransactionUpdates(
|
|
|
437
397
|
|
|
438
398
|
function handleStateLifecycleEvent(
|
|
439
399
|
store: Store,
|
|
440
|
-
event:
|
|
400
|
+
event: StateCreationEvent<any> | StateDisposalEvent<any>,
|
|
441
401
|
tl: Timeline<any>,
|
|
442
402
|
): void {
|
|
443
|
-
const timestamp = Date.now()
|
|
444
|
-
const timelineEvent = Object.assign(event, {
|
|
445
|
-
timestamp,
|
|
446
|
-
}) as TimelineUpdate<any>
|
|
447
403
|
if (!tl.timeTraveling) {
|
|
448
404
|
const target = newest(store)
|
|
449
405
|
if (isChildStore(target)) {
|
|
@@ -453,9 +409,9 @@ function handleStateLifecycleEvent(
|
|
|
453
409
|
if (txUpdateInProgress) {
|
|
454
410
|
joinTransaction(store, tl, txUpdateInProgress.update)
|
|
455
411
|
} else {
|
|
456
|
-
tl.history.push(
|
|
412
|
+
tl.history.push(event)
|
|
457
413
|
tl.at = tl.history.length
|
|
458
|
-
tl.subject.next(
|
|
414
|
+
tl.subject.next(event)
|
|
459
415
|
}
|
|
460
416
|
}
|
|
461
417
|
}
|