atom.io 0.6.8 → 0.6.9
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 +226 -258
- package/dist/index.d.ts +226 -258
- package/dist/index.js +28 -1917
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1877
- package/dist/index.mjs.map +1 -1
- package/introspection/dist/index.d.mts +117 -171
- package/introspection/dist/index.d.ts +117 -171
- package/introspection/dist/index.js +6 -346
- package/introspection/dist/index.js.map +1 -1
- package/introspection/dist/index.mjs +5 -324
- package/introspection/dist/index.mjs.map +1 -1
- package/json/dist/index.d.mts +32 -1
- package/json/dist/index.d.ts +32 -1
- package/json/dist/index.js +31 -48
- package/json/dist/index.js.map +1 -1
- package/json/dist/index.mjs +6 -14
- package/json/dist/index.mjs.map +1 -1
- package/package.json +22 -14
- package/react/dist/index.js +34 -83
- package/react/dist/index.js.map +1 -1
- package/react/dist/index.mjs +7 -43
- package/react/dist/index.mjs.map +1 -1
- package/react-devtools/dist/index.css +1 -50
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.mts +124 -188
- package/react-devtools/dist/index.d.ts +124 -188
- package/react-devtools/dist/index.js +56 -4674
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/dist/index.mjs +19 -4642
- package/react-devtools/dist/index.mjs.map +1 -1
- package/realtime/dist/index.d.mts +1 -3
- package/realtime/dist/index.d.ts +1 -3
- package/realtime/dist/index.js +26 -184
- package/realtime/dist/index.js.map +1 -1
- package/realtime/dist/index.mjs +4 -148
- package/realtime/dist/index.mjs.map +1 -1
- package/realtime-react/dist/index.d.mts +2 -4
- package/realtime-react/dist/index.d.ts +2 -4
- package/realtime-react/dist/index.js +41 -214
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/dist/index.mjs +9 -169
- package/realtime-react/dist/index.mjs.map +1 -1
- package/src/atom.ts +4 -3
- package/src/index.ts +12 -9
- package/src/logger.ts +5 -5
- package/src/selector.ts +3 -3
- package/src/silo.ts +36 -39
- package/src/subscribe.ts +24 -19
- package/src/timeline.ts +9 -4
- package/src/transaction.ts +3 -4
- package/src/internal/atom-internal.ts +0 -54
- package/src/internal/families-internal.ts +0 -144
- package/src/internal/get.ts +0 -129
- package/src/internal/index.ts +0 -15
- package/src/internal/is-default.ts +0 -35
- package/src/internal/operation.ts +0 -139
- package/src/internal/selector/create-read-write-selector.ts +0 -68
- package/src/internal/selector/create-readonly-selector.ts +0 -48
- package/src/internal/selector/index.ts +0 -4
- package/src/internal/selector/lookup-selector-sources.ts +0 -16
- package/src/internal/selector/register-selector.ts +0 -57
- package/src/internal/selector/trace-selector-atoms.ts +0 -43
- package/src/internal/selector/update-selector-atoms.ts +0 -33
- package/src/internal/selector-internal.ts +0 -58
- package/src/internal/set.ts +0 -99
- package/src/internal/store.ts +0 -151
- package/src/internal/subscribe-internal.ts +0 -88
- package/src/internal/time-travel-internal.ts +0 -91
- package/src/internal/timeline/add-atom-to-timeline.ts +0 -168
- package/src/internal/timeline/index.ts +0 -1
- package/src/internal/timeline-internal.ts +0 -107
- package/src/internal/transaction/abort-transaction.ts +0 -12
- package/src/internal/transaction/apply-transaction.ts +0 -57
- package/src/internal/transaction/build-transaction.ts +0 -33
- package/src/internal/transaction/index.ts +0 -25
- package/src/internal/transaction/redo-transaction.ts +0 -23
- package/src/internal/transaction/undo-transaction.ts +0 -23
- package/src/internal/transaction-internal.ts +0 -61
- package/src/introspection/attach-atom-index.ts +0 -73
- package/src/introspection/attach-introspection-states.ts +0 -42
- package/src/introspection/attach-selector-index.ts +0 -77
- package/src/introspection/attach-timeline-family.ts +0 -59
- package/src/introspection/attach-timeline-index.ts +0 -36
- package/src/introspection/attach-transaction-index.ts +0 -38
- package/src/introspection/attach-transaction-logs.ts +0 -40
- package/src/introspection/index.ts +0 -20
- package/src/json/index.ts +0 -1
- package/src/json/select-json.ts +0 -18
- package/src/react/index.ts +0 -2
- package/src/react/store-context.tsx +0 -13
- package/src/react/store-hooks.ts +0 -47
- package/src/react-devtools/AtomIODevtools.tsx +0 -107
- package/src/react-devtools/Button.tsx +0 -24
- package/src/react-devtools/StateEditor.tsx +0 -74
- package/src/react-devtools/StateIndex.tsx +0 -156
- package/src/react-devtools/TimelineIndex.tsx +0 -92
- package/src/react-devtools/TransactionIndex.tsx +0 -70
- package/src/react-devtools/Updates.tsx +0 -145
- package/src/react-devtools/devtools.scss +0 -310
- package/src/react-devtools/index.ts +0 -72
- package/src/react-explorer/AtomIOExplorer.tsx +0 -218
- package/src/react-explorer/explorer-effects.ts +0 -20
- package/src/react-explorer/explorer-states.ts +0 -217
- package/src/react-explorer/index.ts +0 -23
- package/src/react-explorer/space-states.ts +0 -72
- package/src/react-explorer/view-states.ts +0 -41
- package/src/realtime/README.md +0 -33
- package/src/realtime/hook-composition/expose-family.ts +0 -101
- package/src/realtime/hook-composition/expose-single.ts +0 -38
- package/src/realtime/hook-composition/expose-timeline.ts +0 -60
- package/src/realtime/hook-composition/index.ts +0 -12
- package/src/realtime/hook-composition/receive-state.ts +0 -29
- package/src/realtime/hook-composition/receive-transaction.ts +0 -18
- package/src/realtime/index.ts +0 -1
- package/src/realtime-react/index.ts +0 -3
- package/src/realtime-react/realtime-context.tsx +0 -30
- package/src/realtime-react/realtime-hooks.ts +0 -39
- package/src/realtime-react/realtime-state.ts +0 -10
- package/src/realtime-react/use-pull-family-member.ts +0 -26
- package/src/realtime-react/use-pull-family.ts +0 -24
- package/src/realtime-react/use-pull.ts +0 -24
- package/src/realtime-react/use-push.ts +0 -27
- package/src/realtime-react/use-server-action.ts +0 -33
- package/src/realtime-testing/index.ts +0 -1
- package/src/realtime-testing/setup-realtime-test.tsx +0 -159
- package/src/tracker/index.ts +0 -3
- package/src/tracker/tracker.ts +0 -61
- package/src/web-effects/index.ts +0 -1
- package/src/web-effects/storage.ts +0 -30
package/src/internal/store.ts
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
import type { ƒn } from "~/packages/anvl/src/function"
|
|
2
|
-
import { doNothing } from "~/packages/anvl/src/function"
|
|
3
|
-
import { Join } from "~/packages/anvl/src/join"
|
|
4
|
-
|
|
5
|
-
import { Subject } from "."
|
|
6
|
-
import type {
|
|
7
|
-
Atom,
|
|
8
|
-
OperationProgress,
|
|
9
|
-
ReadonlySelector,
|
|
10
|
-
Selector,
|
|
11
|
-
TransactionStatus,
|
|
12
|
-
Timeline,
|
|
13
|
-
Transaction,
|
|
14
|
-
} from "."
|
|
15
|
-
import type {
|
|
16
|
-
AtomToken,
|
|
17
|
-
Logger,
|
|
18
|
-
ReadonlySelectorToken,
|
|
19
|
-
SelectorToken,
|
|
20
|
-
TimelineToken,
|
|
21
|
-
TransactionToken,
|
|
22
|
-
} from ".."
|
|
23
|
-
|
|
24
|
-
export type StoreCore = Pick<
|
|
25
|
-
Store,
|
|
26
|
-
| `atoms`
|
|
27
|
-
| `atomsThatAreDefault`
|
|
28
|
-
| `operation`
|
|
29
|
-
| `readonlySelectors`
|
|
30
|
-
| `selectorAtoms`
|
|
31
|
-
| `selectorGraph`
|
|
32
|
-
| `selectors`
|
|
33
|
-
| `timelineAtoms`
|
|
34
|
-
| `timelines`
|
|
35
|
-
| `transactions`
|
|
36
|
-
| `valueMap`
|
|
37
|
-
>
|
|
38
|
-
|
|
39
|
-
export interface Store {
|
|
40
|
-
atoms: Map<string, Atom<any>>
|
|
41
|
-
atomsThatAreDefault: Set<string>
|
|
42
|
-
readonlySelectors: Map<string, ReadonlySelector<any>>
|
|
43
|
-
selectorAtoms: Join<null, `selectorKey`, `atomKey`>
|
|
44
|
-
selectorGraph: Join<{ source: string }>
|
|
45
|
-
selectors: Map<string, Selector<any>>
|
|
46
|
-
timelineAtoms: Join<null, `timelineKey`, `atomKey`>
|
|
47
|
-
timelines: Map<string, Timeline>
|
|
48
|
-
transactions: Map<string, Transaction<any>>
|
|
49
|
-
valueMap: Map<string, any>
|
|
50
|
-
|
|
51
|
-
subject: {
|
|
52
|
-
atomCreation: Subject<AtomToken<unknown>>
|
|
53
|
-
selectorCreation: Subject<
|
|
54
|
-
ReadonlySelectorToken<unknown> | SelectorToken<unknown>
|
|
55
|
-
>
|
|
56
|
-
transactionCreation: Subject<TransactionToken<ƒn>>
|
|
57
|
-
timelineCreation: Subject<TimelineToken>
|
|
58
|
-
operationStatus: Subject<OperationProgress>
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
operation: OperationProgress
|
|
62
|
-
transactionStatus: TransactionStatus<ƒn>
|
|
63
|
-
config: {
|
|
64
|
-
name: string
|
|
65
|
-
logger: Logger | null
|
|
66
|
-
logger__INTERNAL: Logger
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export const createStore = (name: string, store: Store | null = null): Store => {
|
|
71
|
-
const created = {
|
|
72
|
-
...(store ??
|
|
73
|
-
(() => ({
|
|
74
|
-
atomsThatAreDefault: new Set(),
|
|
75
|
-
selectorAtoms: new Join({ relationType: `n:n` })
|
|
76
|
-
.from(`selectorKey`)
|
|
77
|
-
.to(`atomKey`),
|
|
78
|
-
selectorGraph: new Join({ relationType: `n:n` }),
|
|
79
|
-
}))()),
|
|
80
|
-
|
|
81
|
-
valueMap: new Map(store?.valueMap),
|
|
82
|
-
atoms: new Map(),
|
|
83
|
-
readonlySelectors: new Map(),
|
|
84
|
-
selectors: new Map(),
|
|
85
|
-
transactions: new Map(),
|
|
86
|
-
timelines: new Map(),
|
|
87
|
-
|
|
88
|
-
timelineAtoms: new Join({ relationType: `1:n` })
|
|
89
|
-
.from(`timelineKey`)
|
|
90
|
-
.to(`atomKey`),
|
|
91
|
-
|
|
92
|
-
subject: {
|
|
93
|
-
atomCreation: new Subject(),
|
|
94
|
-
selectorCreation: new Subject(),
|
|
95
|
-
transactionCreation: new Subject(),
|
|
96
|
-
timelineCreation: new Subject(),
|
|
97
|
-
operationStatus: new Subject(),
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
operation: {
|
|
101
|
-
open: false,
|
|
102
|
-
...store?.operation,
|
|
103
|
-
},
|
|
104
|
-
transactionStatus: {
|
|
105
|
-
phase: `idle`,
|
|
106
|
-
...store?.transactionStatus,
|
|
107
|
-
},
|
|
108
|
-
config: {
|
|
109
|
-
logger: {
|
|
110
|
-
...console,
|
|
111
|
-
info: doNothing,
|
|
112
|
-
...store?.config?.logger,
|
|
113
|
-
},
|
|
114
|
-
logger__INTERNAL: console,
|
|
115
|
-
...store?.config,
|
|
116
|
-
name,
|
|
117
|
-
},
|
|
118
|
-
} satisfies Store
|
|
119
|
-
|
|
120
|
-
store?.atoms.forEach((atom) => {
|
|
121
|
-
const copiedAtom = { ...atom, subject: new Subject() } satisfies Atom<any>
|
|
122
|
-
created.atoms.set(atom.key, copiedAtom)
|
|
123
|
-
})
|
|
124
|
-
store?.readonlySelectors.forEach((selector) => {
|
|
125
|
-
selector.install(created)
|
|
126
|
-
})
|
|
127
|
-
store?.selectors.forEach((selector) => {
|
|
128
|
-
selector.install(created)
|
|
129
|
-
})
|
|
130
|
-
store?.transactions.forEach((tx) => {
|
|
131
|
-
tx.install(created)
|
|
132
|
-
})
|
|
133
|
-
store?.timelines.forEach((timeline) => {
|
|
134
|
-
timeline.install(created)
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
return created
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export const IMPLICIT = {
|
|
141
|
-
STORE_INTERNAL: undefined as Store | undefined,
|
|
142
|
-
get STORE(): Store {
|
|
143
|
-
return this.STORE_INTERNAL ?? (this.STORE_INTERNAL = createStore(`DEFAULT`))
|
|
144
|
-
},
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export const clearStore = (store: Store = IMPLICIT.STORE): void => {
|
|
148
|
-
const { config } = store
|
|
149
|
-
Object.assign(store, createStore(config.name))
|
|
150
|
-
store.config = config
|
|
151
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import type { Atom, ReadonlySelector, Selector, Store } from "."
|
|
2
|
-
import {
|
|
3
|
-
getState__INTERNAL,
|
|
4
|
-
withdraw,
|
|
5
|
-
recallState,
|
|
6
|
-
traceAllSelectorAtoms,
|
|
7
|
-
} from "."
|
|
8
|
-
import type { StateUpdate } from ".."
|
|
9
|
-
|
|
10
|
-
export const prepareUpdate = <T>(
|
|
11
|
-
state: Atom<T> | ReadonlySelector<T> | Selector<T>,
|
|
12
|
-
store: Store,
|
|
13
|
-
): StateUpdate<T> => {
|
|
14
|
-
const oldValue = recallState(state, store)
|
|
15
|
-
const newValue = getState__INTERNAL(state, store)
|
|
16
|
-
return { newValue, oldValue }
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export const stowUpdate = <T>(
|
|
20
|
-
state: Atom<T>,
|
|
21
|
-
update: StateUpdate<T>,
|
|
22
|
-
store: Store,
|
|
23
|
-
): void => {
|
|
24
|
-
const { key } = state
|
|
25
|
-
const { logger } = store.config
|
|
26
|
-
if (store.transactionStatus.phase !== `building`) {
|
|
27
|
-
store.config.logger?.warn(
|
|
28
|
-
`stowUpdate called outside of a transaction. This is probably a bug.`,
|
|
29
|
-
)
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
store.transactionStatus.atomUpdates.push({ key, ...update })
|
|
33
|
-
logger?.info(`📝 ${key} stowed (`, update.oldValue, `->`, update.newValue, `)`)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const emitUpdate = <T>(
|
|
37
|
-
state: Atom<T> | ReadonlySelector<T> | Selector<T>,
|
|
38
|
-
update: StateUpdate<T>,
|
|
39
|
-
store: Store,
|
|
40
|
-
): void => {
|
|
41
|
-
const { key } = state
|
|
42
|
-
const { logger } = store.config
|
|
43
|
-
logger?.info(
|
|
44
|
-
`📢 ${state.type} "${key}" went (`,
|
|
45
|
-
update.oldValue,
|
|
46
|
-
`->`,
|
|
47
|
-
update.newValue,
|
|
48
|
-
`)`,
|
|
49
|
-
)
|
|
50
|
-
state.subject.next(update)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export const subscribeToRootAtoms = <T>(
|
|
54
|
-
state: ReadonlySelector<T> | Selector<T>,
|
|
55
|
-
store: Store,
|
|
56
|
-
): { unsubscribe: () => void }[] | null => {
|
|
57
|
-
const dependencySubscriptions =
|
|
58
|
-
`default` in state
|
|
59
|
-
? null
|
|
60
|
-
: traceAllSelectorAtoms(state.key, store).map((atomToken) => {
|
|
61
|
-
const atom = withdraw(atomToken, store)
|
|
62
|
-
if (atom === null) {
|
|
63
|
-
throw new Error(
|
|
64
|
-
`Atom "${atomToken.key}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`,
|
|
65
|
-
)
|
|
66
|
-
}
|
|
67
|
-
return atom.subject.subscribe((atomChange) => {
|
|
68
|
-
store.config.logger?.info(
|
|
69
|
-
`📢 selector "${state.key}" saw root "${atomToken.key}" go (`,
|
|
70
|
-
atomChange.oldValue,
|
|
71
|
-
`->`,
|
|
72
|
-
atomChange.newValue,
|
|
73
|
-
`)`,
|
|
74
|
-
)
|
|
75
|
-
const oldValue = recallState(state, store)
|
|
76
|
-
const newValue = getState__INTERNAL(state, store)
|
|
77
|
-
store.config.logger?.info(
|
|
78
|
-
` <- "${state.key}" went (`,
|
|
79
|
-
oldValue,
|
|
80
|
-
`->`,
|
|
81
|
-
newValue,
|
|
82
|
-
`)`,
|
|
83
|
-
)
|
|
84
|
-
state.subject.next({ newValue, oldValue })
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
return dependencySubscriptions
|
|
88
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { Store } from "."
|
|
2
|
-
import { IMPLICIT } from "."
|
|
3
|
-
import type { TimelineToken } from ".."
|
|
4
|
-
import { setState } from ".."
|
|
5
|
-
|
|
6
|
-
export const redo__INTERNAL = (
|
|
7
|
-
token: TimelineToken,
|
|
8
|
-
store: Store = IMPLICIT.STORE,
|
|
9
|
-
): void => {
|
|
10
|
-
store.config.logger?.info(`⏩ redo "${token.key}"`)
|
|
11
|
-
const timelineData = store.timelines.get(token.key)
|
|
12
|
-
if (!timelineData) {
|
|
13
|
-
store.config.logger?.error(
|
|
14
|
-
`Failed to redo on timeline "${token.key}". This timeline has not been initialized.`,
|
|
15
|
-
)
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
if (timelineData.at === timelineData.history.length) {
|
|
19
|
-
store.config.logger?.warn(
|
|
20
|
-
`Failed to redo at the end of timeline "${token.key}". There is nothing to redo.`,
|
|
21
|
-
)
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
timelineData.timeTraveling = `into_future`
|
|
25
|
-
const update = timelineData.history[timelineData.at]
|
|
26
|
-
switch (update.type) {
|
|
27
|
-
case `atom_update`: {
|
|
28
|
-
const { key, newValue } = update
|
|
29
|
-
setState({ key, type: `atom` }, newValue, store)
|
|
30
|
-
break
|
|
31
|
-
}
|
|
32
|
-
case `selector_update`:
|
|
33
|
-
case `transaction_update`: {
|
|
34
|
-
for (const atomUpdate of update.atomUpdates) {
|
|
35
|
-
const { key, newValue } = atomUpdate
|
|
36
|
-
setState({ key, type: `atom` }, newValue, store)
|
|
37
|
-
}
|
|
38
|
-
break
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
++timelineData.at
|
|
42
|
-
timelineData.subject.next(`redo`)
|
|
43
|
-
timelineData.timeTraveling = null
|
|
44
|
-
store.config.logger?.info(
|
|
45
|
-
`⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export const undo__INTERNAL = (
|
|
50
|
-
token: TimelineToken,
|
|
51
|
-
store: Store = IMPLICIT.STORE,
|
|
52
|
-
): void => {
|
|
53
|
-
store.config.logger?.info(`⏪ undo "${token.key}"`)
|
|
54
|
-
const timelineData = store.timelines.get(token.key)
|
|
55
|
-
if (!timelineData) {
|
|
56
|
-
store.config.logger?.error(
|
|
57
|
-
`Failed to undo on timeline "${token.key}". This timeline has not been initialized.`,
|
|
58
|
-
)
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
if (timelineData.at === 0) {
|
|
62
|
-
store.config.logger?.warn(
|
|
63
|
-
`Failed to undo at the beginning of timeline "${token.key}". There is nothing to undo.`,
|
|
64
|
-
)
|
|
65
|
-
return
|
|
66
|
-
}
|
|
67
|
-
timelineData.timeTraveling = `into_past`
|
|
68
|
-
|
|
69
|
-
--timelineData.at
|
|
70
|
-
const update = timelineData.history[timelineData.at]
|
|
71
|
-
switch (update.type) {
|
|
72
|
-
case `atom_update`: {
|
|
73
|
-
const { key, oldValue } = update
|
|
74
|
-
setState({ key, type: `atom` }, oldValue, store)
|
|
75
|
-
break
|
|
76
|
-
}
|
|
77
|
-
case `selector_update`:
|
|
78
|
-
case `transaction_update`: {
|
|
79
|
-
for (const atomUpdate of update.atomUpdates) {
|
|
80
|
-
const { key, oldValue } = atomUpdate
|
|
81
|
-
setState({ key, type: `atom` }, oldValue, store)
|
|
82
|
-
}
|
|
83
|
-
break
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
timelineData.subject.next(`undo`)
|
|
87
|
-
timelineData.timeTraveling = null
|
|
88
|
-
store.config.logger?.info(
|
|
89
|
-
`⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
|
|
90
|
-
)
|
|
91
|
-
}
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { IMPLICIT, withdraw } from ".."
|
|
2
|
-
import type {
|
|
3
|
-
Timeline,
|
|
4
|
-
Store,
|
|
5
|
-
TimelineTransactionUpdate,
|
|
6
|
-
TimelineAtomUpdate,
|
|
7
|
-
} from ".."
|
|
8
|
-
import type { AtomFamily, AtomToken, TimelineUpdate } from "../.."
|
|
9
|
-
|
|
10
|
-
export const addAtomToTimeline = (
|
|
11
|
-
atomToken: AtomToken<any>,
|
|
12
|
-
atoms: (AtomFamily<any> | AtomToken<any>)[],
|
|
13
|
-
tl: Timeline,
|
|
14
|
-
store: Store = IMPLICIT.STORE,
|
|
15
|
-
): void => {
|
|
16
|
-
const atom = withdraw(atomToken, store)
|
|
17
|
-
if (atom === null) {
|
|
18
|
-
throw new Error(
|
|
19
|
-
`Cannot subscribe to atom "${atomToken.key}" because it has not been initialized in store "${store.config.name}"`,
|
|
20
|
-
)
|
|
21
|
-
}
|
|
22
|
-
atom.subject.subscribe((update) => {
|
|
23
|
-
const currentSelectorKey =
|
|
24
|
-
store.operation.open && store.operation.token.type === `selector`
|
|
25
|
-
? store.operation.token.key
|
|
26
|
-
: null
|
|
27
|
-
const currentSelectorTime =
|
|
28
|
-
store.operation.open && store.operation.token.type === `selector`
|
|
29
|
-
? store.operation.time
|
|
30
|
-
: null
|
|
31
|
-
const currentTransactionKey =
|
|
32
|
-
store.transactionStatus.phase === `applying`
|
|
33
|
-
? store.transactionStatus.key
|
|
34
|
-
: null
|
|
35
|
-
const currentTransactionTime =
|
|
36
|
-
store.transactionStatus.phase === `applying`
|
|
37
|
-
? store.transactionStatus.time
|
|
38
|
-
: null
|
|
39
|
-
|
|
40
|
-
store.config.logger?.info(
|
|
41
|
-
`⏳ timeline "${tl.key}" saw atom "${atomToken.key}" go (`,
|
|
42
|
-
update.oldValue,
|
|
43
|
-
`->`,
|
|
44
|
-
update.newValue,
|
|
45
|
-
currentTransactionKey
|
|
46
|
-
? `) in transaction "${currentTransactionKey}"`
|
|
47
|
-
: currentSelectorKey
|
|
48
|
-
? `) in selector "${currentSelectorKey}"`
|
|
49
|
-
: `)`,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
if (tl.timeTraveling === null) {
|
|
53
|
-
if (tl.selectorTime && tl.selectorTime !== currentSelectorTime) {
|
|
54
|
-
const mostRecentUpdate: TimelineUpdate | undefined = tl.history.at(-1)
|
|
55
|
-
if (mostRecentUpdate === undefined) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
`Timeline "${tl.key}" has a selectorTime, but no history. This is most likely a bug in AtomIO.`,
|
|
58
|
-
)
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (
|
|
62
|
-
currentTransactionKey &&
|
|
63
|
-
store.transactionStatus.phase === `applying`
|
|
64
|
-
) {
|
|
65
|
-
const currentTransaction = withdraw(
|
|
66
|
-
{ key: currentTransactionKey, type: `transaction` },
|
|
67
|
-
store,
|
|
68
|
-
)
|
|
69
|
-
if (currentTransaction === null) {
|
|
70
|
-
throw new Error(
|
|
71
|
-
`Transaction "${currentTransactionKey}" not found in store "${store.config.name}". This is surprising, because we are in the application phase of "${currentTransactionKey}".`,
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
if (tl.transactionKey !== currentTransactionKey) {
|
|
75
|
-
if (tl.transactionKey) {
|
|
76
|
-
store.config.logger?.error(
|
|
77
|
-
`Timeline "${tl.key}" was unable to resolve transaction "${tl.transactionKey}. This is probably a bug.`,
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
tl.transactionKey = currentTransactionKey
|
|
81
|
-
const subscription = currentTransaction.subject.subscribe((update) => {
|
|
82
|
-
subscription.unsubscribe()
|
|
83
|
-
if (tl.timeTraveling === null && currentTransactionTime) {
|
|
84
|
-
if (tl.at !== tl.history.length) {
|
|
85
|
-
tl.history.splice(tl.at)
|
|
86
|
-
}
|
|
87
|
-
const timelineTransactionUpdate: TimelineTransactionUpdate = {
|
|
88
|
-
type: `transaction_update`,
|
|
89
|
-
timestamp: currentTransactionTime,
|
|
90
|
-
...update,
|
|
91
|
-
atomUpdates: update.atomUpdates.filter((atomUpdate) =>
|
|
92
|
-
atoms.some((atom) => atom.key === atomUpdate.key),
|
|
93
|
-
),
|
|
94
|
-
}
|
|
95
|
-
tl.history.push(timelineTransactionUpdate)
|
|
96
|
-
tl.at = tl.history.length
|
|
97
|
-
tl.subject.next(timelineTransactionUpdate)
|
|
98
|
-
}
|
|
99
|
-
tl.transactionKey = null
|
|
100
|
-
store.config.logger?.info(
|
|
101
|
-
`⌛ timeline "${tl.key}" got a transaction_update "${update.key}"`,
|
|
102
|
-
)
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
} else if (currentSelectorKey && currentSelectorTime) {
|
|
106
|
-
let latestUpdate: TimelineUpdate | undefined = tl.history.at(-1)
|
|
107
|
-
|
|
108
|
-
if (currentSelectorTime !== tl.selectorTime) {
|
|
109
|
-
latestUpdate = {
|
|
110
|
-
type: `selector_update`,
|
|
111
|
-
timestamp: currentSelectorTime,
|
|
112
|
-
key: currentSelectorKey,
|
|
113
|
-
atomUpdates: [],
|
|
114
|
-
}
|
|
115
|
-
latestUpdate.atomUpdates.push({
|
|
116
|
-
key: atom.key,
|
|
117
|
-
type: `atom_update`,
|
|
118
|
-
...update,
|
|
119
|
-
})
|
|
120
|
-
if (tl.at !== tl.history.length) {
|
|
121
|
-
tl.history.splice(tl.at)
|
|
122
|
-
}
|
|
123
|
-
tl.history.push(latestUpdate)
|
|
124
|
-
|
|
125
|
-
store.config.logger?.info(
|
|
126
|
-
`⌛ timeline "${tl.key}" got a selector_update "${currentSelectorKey}" with`,
|
|
127
|
-
latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key),
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
tl.at = tl.history.length
|
|
131
|
-
tl.selectorTime = currentSelectorTime
|
|
132
|
-
} else {
|
|
133
|
-
if (latestUpdate?.type === `selector_update`) {
|
|
134
|
-
latestUpdate.atomUpdates.push({
|
|
135
|
-
key: atom.key,
|
|
136
|
-
type: `atom_update`,
|
|
137
|
-
...update,
|
|
138
|
-
})
|
|
139
|
-
store.config.logger?.info(
|
|
140
|
-
` ⌛ timeline "${tl.key}" set selector_update "${currentSelectorKey}" to`,
|
|
141
|
-
latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key),
|
|
142
|
-
)
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (latestUpdate) tl.subject.next(latestUpdate)
|
|
146
|
-
} else {
|
|
147
|
-
const timestamp = Date.now()
|
|
148
|
-
tl.selectorTime = null
|
|
149
|
-
if (tl.at !== tl.history.length) {
|
|
150
|
-
tl.history.splice(tl.at)
|
|
151
|
-
}
|
|
152
|
-
const atomUpdate: TimelineAtomUpdate = {
|
|
153
|
-
type: `atom_update`,
|
|
154
|
-
timestamp,
|
|
155
|
-
key: atom.key,
|
|
156
|
-
oldValue: update.oldValue,
|
|
157
|
-
newValue: update.newValue,
|
|
158
|
-
}
|
|
159
|
-
tl.history.push(atomUpdate)
|
|
160
|
-
tl.subject.next(atomUpdate)
|
|
161
|
-
store.config.logger?.info(
|
|
162
|
-
`⌛ timeline "${tl.key}" got an atom_update to "${atom.key}"`,
|
|
163
|
-
)
|
|
164
|
-
tl.at = tl.history.length
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./add-atom-to-timeline"
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import type { ƒn } from "~/packages/anvl/src/function"
|
|
2
|
-
|
|
3
|
-
import type { Store } from "."
|
|
4
|
-
import { Subject, target, IMPLICIT } from "."
|
|
5
|
-
import { addAtomToTimeline } from "./timeline/add-atom-to-timeline"
|
|
6
|
-
import type {
|
|
7
|
-
StateUpdate,
|
|
8
|
-
TimelineOptions,
|
|
9
|
-
TimelineToken,
|
|
10
|
-
TimelineUpdate,
|
|
11
|
-
TransactionUpdate,
|
|
12
|
-
} from ".."
|
|
13
|
-
|
|
14
|
-
export type TimelineAtomUpdate = StateUpdate<unknown> & {
|
|
15
|
-
key: string
|
|
16
|
-
type: `atom_update`
|
|
17
|
-
timestamp: number
|
|
18
|
-
}
|
|
19
|
-
export type TimelineSelectorUpdate = {
|
|
20
|
-
key: string
|
|
21
|
-
type: `selector_update`
|
|
22
|
-
timestamp: number
|
|
23
|
-
atomUpdates: Omit<TimelineAtomUpdate, `timestamp`>[]
|
|
24
|
-
}
|
|
25
|
-
export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
|
|
26
|
-
key: string
|
|
27
|
-
type: `transaction_update`
|
|
28
|
-
timestamp: number
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type Timeline = {
|
|
32
|
-
key: string
|
|
33
|
-
at: number
|
|
34
|
-
timeTraveling: `into_future` | `into_past` | null
|
|
35
|
-
history: TimelineUpdate[]
|
|
36
|
-
selectorTime: number | null
|
|
37
|
-
transactionKey: string | null
|
|
38
|
-
install: (store: Store) => void
|
|
39
|
-
subject: Subject<
|
|
40
|
-
| TimelineAtomUpdate
|
|
41
|
-
| TimelineSelectorUpdate
|
|
42
|
-
| TimelineTransactionUpdate
|
|
43
|
-
| `redo`
|
|
44
|
-
| `undo`
|
|
45
|
-
>
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function timeline__INTERNAL(
|
|
49
|
-
options: TimelineOptions,
|
|
50
|
-
store: Store = IMPLICIT.STORE,
|
|
51
|
-
data: Timeline | null = null,
|
|
52
|
-
): TimelineToken {
|
|
53
|
-
const tl: Timeline = {
|
|
54
|
-
key: options.key,
|
|
55
|
-
at: 0,
|
|
56
|
-
timeTraveling: null,
|
|
57
|
-
selectorTime: null,
|
|
58
|
-
transactionKey: null,
|
|
59
|
-
...data,
|
|
60
|
-
history: data?.history.map((update) => ({ ...update })) ?? [],
|
|
61
|
-
install: (store) => timeline__INTERNAL(options, store, tl),
|
|
62
|
-
subject: new Subject(),
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const core = target(store)
|
|
66
|
-
for (const tokenOrFamily of options.atoms) {
|
|
67
|
-
const timelineKey = core.timelineAtoms.getRelatedId(tokenOrFamily.key)
|
|
68
|
-
if (timelineKey) {
|
|
69
|
-
store.config.logger?.error(
|
|
70
|
-
`❌ Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`,
|
|
71
|
-
)
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
if (tokenOrFamily.type === `atom_family`) {
|
|
75
|
-
const family = tokenOrFamily
|
|
76
|
-
family.subject.subscribe((token) =>
|
|
77
|
-
addAtomToTimeline(token, options.atoms, tl, store),
|
|
78
|
-
)
|
|
79
|
-
} else {
|
|
80
|
-
const token = tokenOrFamily
|
|
81
|
-
if (`family` in token && token.family) {
|
|
82
|
-
const familyTimelineKey = core.timelineAtoms.getRelatedId(
|
|
83
|
-
token.family.key,
|
|
84
|
-
)
|
|
85
|
-
if (familyTimelineKey) {
|
|
86
|
-
store.config.logger?.error(
|
|
87
|
-
`❌ Failed to add atom "${token.key}" to timeline "${options.key}" because its family "${token.family.key}" belongs to timeline "${familyTimelineKey}"`,
|
|
88
|
-
)
|
|
89
|
-
continue
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
addAtomToTimeline(token, options.atoms, tl, store)
|
|
93
|
-
}
|
|
94
|
-
core.timelineAtoms = core.timelineAtoms.set({
|
|
95
|
-
atomKey: tokenOrFamily.key,
|
|
96
|
-
timelineKey: options.key,
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
store.timelines.set(options.key, tl)
|
|
101
|
-
const token: TimelineToken = {
|
|
102
|
-
key: options.key,
|
|
103
|
-
type: `timeline`,
|
|
104
|
-
}
|
|
105
|
-
store.subject.timelineCreation.next(token)
|
|
106
|
-
return token
|
|
107
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Store } from ".."
|
|
2
|
-
|
|
3
|
-
export const abortTransaction = (store: Store): void => {
|
|
4
|
-
if (store.transactionStatus.phase === `idle`) {
|
|
5
|
-
store.config.logger?.warn(
|
|
6
|
-
`abortTransaction called outside of a transaction. This is probably a bug.`,
|
|
7
|
-
)
|
|
8
|
-
return
|
|
9
|
-
}
|
|
10
|
-
store.transactionStatus = { phase: `idle` }
|
|
11
|
-
store.config.logger?.info(`🪂`, `transaction fail`)
|
|
12
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import type { ƒn } from "~/packages/anvl/src/function"
|
|
2
|
-
|
|
3
|
-
import type { Store } from ".."
|
|
4
|
-
import { withdraw } from ".."
|
|
5
|
-
import type { AtomToken } from "../.."
|
|
6
|
-
import { setState } from "../.."
|
|
7
|
-
|
|
8
|
-
export const applyTransaction = <ƒ extends ƒn>(
|
|
9
|
-
output: ReturnType<ƒ>,
|
|
10
|
-
store: Store,
|
|
11
|
-
): void => {
|
|
12
|
-
if (store.transactionStatus.phase !== `building`) {
|
|
13
|
-
store.config.logger?.warn(
|
|
14
|
-
`abortTransaction called outside of a transaction. This is probably a bug.`,
|
|
15
|
-
)
|
|
16
|
-
return
|
|
17
|
-
}
|
|
18
|
-
store.config.logger?.info(
|
|
19
|
-
`🛃 apply transaction "${store.transactionStatus.key}"`,
|
|
20
|
-
)
|
|
21
|
-
store.transactionStatus.phase = `applying`
|
|
22
|
-
store.transactionStatus.output = output
|
|
23
|
-
const { atomUpdates } = store.transactionStatus
|
|
24
|
-
|
|
25
|
-
for (const { key, newValue } of atomUpdates) {
|
|
26
|
-
const token: AtomToken<unknown> = { key, type: `atom` }
|
|
27
|
-
if (!store.valueMap.has(token.key)) {
|
|
28
|
-
const newAtom = store.transactionStatus.core.atoms.get(token.key)
|
|
29
|
-
if (!newAtom) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
`Absurd Error: Atom "${token.key}" not found while copying updates from transaction "${store.transactionStatus.key}" to store "${store.config.name}"`,
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
store.atoms.set(newAtom.key, newAtom)
|
|
35
|
-
store.valueMap.set(newAtom.key, newAtom.default)
|
|
36
|
-
store.config.logger?.info(`🔧`, `add atom "${newAtom.key}"`)
|
|
37
|
-
}
|
|
38
|
-
setState(token, newValue, store)
|
|
39
|
-
}
|
|
40
|
-
const myTransaction = withdraw<ƒ>(
|
|
41
|
-
{ key: store.transactionStatus.key, type: `transaction` },
|
|
42
|
-
store,
|
|
43
|
-
)
|
|
44
|
-
if (myTransaction === null) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
`Transaction "${store.transactionStatus.key}" not found. Absurd. How is this running?`,
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
myTransaction.subject.next({
|
|
50
|
-
key: store.transactionStatus.key,
|
|
51
|
-
atomUpdates,
|
|
52
|
-
output,
|
|
53
|
-
params: store.transactionStatus.params as Parameters<ƒ>,
|
|
54
|
-
})
|
|
55
|
-
store.transactionStatus = { phase: `idle` }
|
|
56
|
-
store.config.logger?.info(`🛬`, `transaction done`)
|
|
57
|
-
}
|