atom.io 0.6.9 → 0.7.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/README.md +21 -2
- package/dist/index.d.mts +34 -421
- package/dist/index.d.ts +34 -421
- package/dist/index.js +248 -23
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +209 -4
- package/dist/index.mjs.map +1 -1
- package/internal/dist/index.d.mts +342 -0
- package/internal/dist/index.d.ts +342 -0
- package/internal/dist/index.js +1873 -0
- package/internal/dist/index.js.map +1 -0
- package/internal/dist/index.mjs +1798 -0
- package/internal/dist/index.mjs.map +1 -0
- package/internal/package.json +15 -0
- package/internal/src/atom/create-atom.ts +75 -0
- package/internal/src/atom/delete-atom.ts +10 -0
- package/internal/src/atom/index.ts +3 -0
- package/internal/src/atom/is-default.ts +37 -0
- package/internal/src/caching.ts +21 -0
- package/internal/src/families/create-atom-family.ts +59 -0
- package/internal/src/families/create-readonly-selector-family.ts +45 -0
- package/internal/src/families/create-selector-family.ts +67 -0
- package/internal/src/families/index.ts +3 -0
- package/internal/src/get-state-internal.ts +23 -0
- package/internal/src/index.ts +13 -0
- package/internal/src/mutable/create-mutable-atom-family.ts +25 -0
- package/internal/src/mutable/create-mutable-atom.ts +49 -0
- package/internal/src/mutable/get-json-token.ts +22 -0
- package/internal/src/mutable/get-update-token.ts +20 -0
- package/internal/src/mutable/index.ts +17 -0
- package/internal/src/mutable/is-atom-token-mutable.ts +7 -0
- package/internal/src/mutable/tracker-family.ts +61 -0
- package/internal/src/mutable/tracker.ts +164 -0
- package/internal/src/mutable/transceiver.ts +110 -0
- package/internal/src/operation.ts +68 -0
- package/internal/src/selector/create-read-write-selector.ts +65 -0
- package/internal/src/selector/create-readonly-selector.ts +49 -0
- package/internal/src/selector/create-selector.ts +65 -0
- package/internal/src/selector/index.ts +5 -0
- package/internal/src/selector/lookup-selector-sources.ts +20 -0
- package/internal/src/selector/register-selector.ts +61 -0
- package/internal/src/selector/trace-selector-atoms.ts +45 -0
- package/internal/src/selector/update-selector-atoms.ts +34 -0
- package/internal/src/set-state/become.ts +10 -0
- package/internal/src/set-state/copy-mutable-if-needed.ts +23 -0
- package/internal/src/set-state/copy-mutable-in-transaction.ts +59 -0
- package/internal/src/set-state/copy-mutable-into-new-store.ts +34 -0
- package/internal/src/set-state/emit-update.ts +23 -0
- package/internal/src/set-state/evict-downstream.ts +39 -0
- package/internal/src/set-state/index.ts +2 -0
- package/internal/src/set-state/set-atom-state.ts +38 -0
- package/internal/src/set-state/set-selector-state.ts +19 -0
- package/internal/src/set-state/set-state-internal.ts +18 -0
- package/internal/src/set-state/stow-update.ts +42 -0
- package/internal/src/store/deposit.ts +43 -0
- package/internal/src/store/index.ts +5 -0
- package/internal/src/store/lookup.ts +26 -0
- package/internal/src/store/store.ts +154 -0
- package/internal/src/store/withdraw-new-family-member.ts +53 -0
- package/internal/src/store/withdraw.ts +113 -0
- package/internal/src/subject.ts +21 -0
- package/internal/src/subscribe/index.ts +1 -0
- package/internal/src/subscribe/recall-state.ts +19 -0
- package/internal/src/subscribe/subscribe-to-root-atoms.ts +47 -0
- package/internal/src/timeline/add-atom-to-timeline.ts +189 -0
- package/internal/src/timeline/index.ts +3 -0
- package/internal/src/timeline/time-travel-internal.ts +91 -0
- package/internal/src/timeline/timeline-internal.ts +115 -0
- package/internal/src/transaction/abort-transaction.ts +12 -0
- package/internal/src/transaction/apply-transaction.ts +64 -0
- package/internal/src/transaction/build-transaction.ts +39 -0
- package/internal/src/transaction/index.ts +26 -0
- package/internal/src/transaction/redo-transaction.ts +22 -0
- package/internal/src/transaction/transaction-internal.ts +64 -0
- package/internal/src/transaction/undo-transaction.ts +22 -0
- package/introspection/dist/index.d.mts +3 -197
- package/introspection/dist/index.d.ts +3 -197
- package/introspection/dist/index.js +329 -4
- package/introspection/dist/index.js.map +1 -1
- package/introspection/dist/index.mjs +310 -4
- package/introspection/dist/index.mjs.map +1 -1
- package/introspection/src/attach-atom-index.ts +84 -0
- package/introspection/src/attach-introspection-states.ts +38 -0
- package/introspection/src/attach-selector-index.ts +90 -0
- package/introspection/src/attach-timeline-family.ts +59 -0
- package/introspection/src/attach-timeline-index.ts +38 -0
- package/introspection/src/attach-transaction-index.ts +40 -0
- package/introspection/src/attach-transaction-logs.ts +43 -0
- package/introspection/src/index.ts +20 -0
- package/json/dist/index.d.mts +10 -2
- package/json/dist/index.d.ts +10 -2
- package/json/dist/index.js +83 -26
- package/json/dist/index.js.map +1 -1
- package/json/dist/index.mjs +74 -3
- package/json/dist/index.mjs.map +1 -1
- package/json/src/index.ts +5 -0
- package/json/src/select-json-family.ts +35 -0
- package/json/src/select-json.ts +22 -0
- package/package.json +103 -63
- package/react/dist/index.d.mts +9 -17
- package/react/dist/index.d.ts +9 -17
- package/react/dist/index.js +44 -27
- package/react/dist/index.js.map +1 -1
- package/react/dist/index.mjs +24 -4
- package/react/dist/index.mjs.map +1 -1
- package/react/src/index.ts +2 -0
- package/react/src/store-context.tsx +12 -0
- package/react/src/store-hooks.ts +36 -0
- package/react-devtools/dist/index.css +50 -1
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.mts +104 -71
- package/react-devtools/dist/index.d.ts +104 -71
- package/react-devtools/dist/index.js +2806 -44
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/dist/index.mjs +2775 -10
- package/react-devtools/dist/index.mjs.map +1 -1
- package/react-devtools/src/AtomIODevtools.tsx +109 -0
- package/react-devtools/src/Button.tsx +23 -0
- package/react-devtools/src/StateEditor.tsx +75 -0
- package/react-devtools/src/StateIndex.tsx +159 -0
- package/react-devtools/src/TimelineIndex.tsx +88 -0
- package/react-devtools/src/TransactionIndex.tsx +70 -0
- package/react-devtools/src/Updates.tsx +150 -0
- package/react-devtools/src/devtools.scss +310 -0
- package/react-devtools/src/index.ts +72 -0
- package/realtime-react/dist/index.d.mts +8 -22
- package/realtime-react/dist/index.d.ts +8 -22
- package/realtime-react/dist/index.js +87 -32
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/dist/index.mjs +62 -6
- package/realtime-react/dist/index.mjs.map +1 -1
- package/realtime-react/src/index.ts +7 -0
- package/realtime-react/src/realtime-context.tsx +29 -0
- package/realtime-react/src/use-pull-family-member.ts +15 -0
- package/realtime-react/src/use-pull-mutable-family-member.ts +20 -0
- package/realtime-react/src/use-pull-mutable.ts +17 -0
- package/realtime-react/src/use-pull.ts +15 -0
- package/realtime-react/src/use-push.ts +19 -0
- package/realtime-react/src/use-server-action.ts +18 -0
- package/realtime-testing/dist/index.d.mts +49 -0
- package/realtime-testing/dist/index.d.ts +49 -0
- package/realtime-testing/dist/index.js +147 -0
- package/realtime-testing/dist/index.js.map +1 -0
- package/realtime-testing/dist/index.mjs +116 -0
- package/realtime-testing/dist/index.mjs.map +1 -0
- package/realtime-testing/src/index.ts +1 -0
- package/realtime-testing/src/setup-realtime-test.tsx +161 -0
- package/src/atom.ts +64 -9
- package/src/index.ts +36 -32
- package/src/logger.ts +3 -3
- package/src/selector.ts +3 -3
- package/src/silo.ts +29 -20
- package/src/subscribe.ts +3 -3
- package/src/timeline.ts +2 -2
- package/transceivers/set-rtx/dist/index.d.mts +39 -0
- package/transceivers/set-rtx/dist/index.d.ts +39 -0
- package/transceivers/set-rtx/dist/index.js +213 -0
- package/transceivers/set-rtx/dist/index.js.map +1 -0
- package/transceivers/set-rtx/dist/index.mjs +211 -0
- package/transceivers/set-rtx/dist/index.mjs.map +1 -0
- package/{realtime → transceivers/set-rtx}/package.json +1 -1
- package/transceivers/set-rtx/src/index.ts +1 -0
- package/transceivers/set-rtx/src/set-rtx.ts +242 -0
- package/realtime/dist/index.d.mts +0 -23
- package/realtime/dist/index.d.ts +0 -23
- package/realtime/dist/index.js +0 -32
- package/realtime/dist/index.js.map +0 -1
- package/realtime/dist/index.mjs +0 -7
- package/realtime/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { TimelineToken } from "atom.io"
|
|
2
|
+
import { setState } from "atom.io"
|
|
3
|
+
|
|
4
|
+
import type { Store } from "../store"
|
|
5
|
+
import { IMPLICIT } from "../store"
|
|
6
|
+
|
|
7
|
+
export const redo__INTERNAL = (
|
|
8
|
+
token: TimelineToken,
|
|
9
|
+
store: Store = IMPLICIT.STORE,
|
|
10
|
+
): void => {
|
|
11
|
+
store.config.logger?.info(`⏩ redo "${token.key}"`)
|
|
12
|
+
const timelineData = store.timelines.get(token.key)
|
|
13
|
+
if (!timelineData) {
|
|
14
|
+
store.config.logger?.error(
|
|
15
|
+
`Failed to redo on timeline "${token.key}". This timeline has not been initialized.`,
|
|
16
|
+
)
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
if (timelineData.at === timelineData.history.length) {
|
|
20
|
+
store.config.logger?.warn(
|
|
21
|
+
`Failed to redo at the end of timeline "${token.key}". There is nothing to redo.`,
|
|
22
|
+
)
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
timelineData.timeTraveling = `into_future`
|
|
26
|
+
const update = timelineData.history[timelineData.at]
|
|
27
|
+
switch (update.type) {
|
|
28
|
+
case `atom_update`: {
|
|
29
|
+
const { key, newValue } = update
|
|
30
|
+
setState({ key, type: `atom` }, newValue, store)
|
|
31
|
+
break
|
|
32
|
+
}
|
|
33
|
+
case `selector_update`:
|
|
34
|
+
case `transaction_update`: {
|
|
35
|
+
for (const atomUpdate of update.atomUpdates) {
|
|
36
|
+
const { key, newValue } = atomUpdate
|
|
37
|
+
setState({ key, type: `atom` }, newValue, store)
|
|
38
|
+
}
|
|
39
|
+
break
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
++timelineData.at
|
|
43
|
+
timelineData.subject.next(`redo`)
|
|
44
|
+
timelineData.timeTraveling = null
|
|
45
|
+
store.config.logger?.info(
|
|
46
|
+
`⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const undo__INTERNAL = (
|
|
51
|
+
token: TimelineToken,
|
|
52
|
+
store: Store = IMPLICIT.STORE,
|
|
53
|
+
): void => {
|
|
54
|
+
store.config.logger?.info(`⏪ undo "${token.key}"`)
|
|
55
|
+
const timelineData = store.timelines.get(token.key)
|
|
56
|
+
if (!timelineData) {
|
|
57
|
+
store.config.logger?.error(
|
|
58
|
+
`Failed to undo on timeline "${token.key}". This timeline has not been initialized.`,
|
|
59
|
+
)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
if (timelineData.at === 0) {
|
|
63
|
+
store.config.logger?.warn(
|
|
64
|
+
`Failed to undo at the beginning of timeline "${token.key}". There is nothing to undo.`,
|
|
65
|
+
)
|
|
66
|
+
return
|
|
67
|
+
}
|
|
68
|
+
timelineData.timeTraveling = `into_past`
|
|
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].reverse()) {
|
|
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
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FamilyMetadata,
|
|
3
|
+
StateUpdate,
|
|
4
|
+
TimelineOptions,
|
|
5
|
+
TimelineToken,
|
|
6
|
+
TimelineUpdate,
|
|
7
|
+
TransactionUpdate,
|
|
8
|
+
ƒn,
|
|
9
|
+
} from "atom.io"
|
|
10
|
+
|
|
11
|
+
import type { Store } from "../store"
|
|
12
|
+
import { IMPLICIT } from "../store"
|
|
13
|
+
import { Subject } from "../subject"
|
|
14
|
+
import { target } from "../transaction"
|
|
15
|
+
import { addAtomToTimeline } from "./add-atom-to-timeline"
|
|
16
|
+
|
|
17
|
+
export type TimelineAtomUpdate = StateUpdate<unknown> & {
|
|
18
|
+
key: string
|
|
19
|
+
type: `atom_update`
|
|
20
|
+
timestamp: number
|
|
21
|
+
family?: FamilyMetadata
|
|
22
|
+
}
|
|
23
|
+
export type TimelineSelectorUpdate = {
|
|
24
|
+
key: string
|
|
25
|
+
type: `selector_update`
|
|
26
|
+
timestamp: number
|
|
27
|
+
atomUpdates: Omit<TimelineAtomUpdate, `timestamp`>[]
|
|
28
|
+
}
|
|
29
|
+
export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
|
|
30
|
+
key: string
|
|
31
|
+
type: `transaction_update`
|
|
32
|
+
timestamp: number
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type Timeline = {
|
|
36
|
+
type: `timeline`
|
|
37
|
+
key: string
|
|
38
|
+
at: number
|
|
39
|
+
timeTraveling: `into_future` | `into_past` | null
|
|
40
|
+
history: TimelineUpdate[]
|
|
41
|
+
selectorTime: number | null
|
|
42
|
+
transactionKey: string | null
|
|
43
|
+
install: (store: Store) => void
|
|
44
|
+
subject: Subject<
|
|
45
|
+
| TimelineAtomUpdate
|
|
46
|
+
| TimelineSelectorUpdate
|
|
47
|
+
| TimelineTransactionUpdate
|
|
48
|
+
| `redo`
|
|
49
|
+
| `undo`
|
|
50
|
+
>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function timeline__INTERNAL(
|
|
54
|
+
options: TimelineOptions,
|
|
55
|
+
store: Store = IMPLICIT.STORE,
|
|
56
|
+
data: Timeline | null = null,
|
|
57
|
+
): TimelineToken {
|
|
58
|
+
const tl: Timeline = {
|
|
59
|
+
type: `timeline`,
|
|
60
|
+
key: options.key,
|
|
61
|
+
at: 0,
|
|
62
|
+
timeTraveling: null,
|
|
63
|
+
selectorTime: null,
|
|
64
|
+
transactionKey: null,
|
|
65
|
+
...data,
|
|
66
|
+
history: data?.history.map((update) => ({ ...update })) ?? [],
|
|
67
|
+
install: (store) => timeline__INTERNAL(options, store, tl),
|
|
68
|
+
subject: new Subject(),
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const core = target(store)
|
|
72
|
+
for (const tokenOrFamily of options.atoms) {
|
|
73
|
+
const timelineKey = core.timelineAtoms.getRelatedKey(tokenOrFamily.key)
|
|
74
|
+
if (timelineKey) {
|
|
75
|
+
store.config.logger?.error(
|
|
76
|
+
`❌ Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`,
|
|
77
|
+
)
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
if (tokenOrFamily.type === `atom_family`) {
|
|
81
|
+
const family = tokenOrFamily
|
|
82
|
+
family.subject.subscribe(`timeline:${options.key}`, (token) => {
|
|
83
|
+
if (!core.atoms.has(token.key)) {
|
|
84
|
+
addAtomToTimeline(token, tl, store)
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
} else {
|
|
88
|
+
const token = tokenOrFamily
|
|
89
|
+
if (`family` in token && token.family) {
|
|
90
|
+
const familyTimelineKey = core.timelineAtoms.getRelatedKey(
|
|
91
|
+
token.family.key,
|
|
92
|
+
)
|
|
93
|
+
if (familyTimelineKey) {
|
|
94
|
+
store.config.logger?.error(
|
|
95
|
+
`❌ Failed to add atom "${token.key}" to timeline "${options.key}" because its family "${token.family.key}" belongs to timeline "${familyTimelineKey}"`,
|
|
96
|
+
)
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
addAtomToTimeline(token, tl, store)
|
|
101
|
+
}
|
|
102
|
+
core.timelineAtoms = core.timelineAtoms.set({
|
|
103
|
+
atomKey: tokenOrFamily.key,
|
|
104
|
+
timelineKey: options.key,
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
store.timelines.set(options.key, tl)
|
|
109
|
+
const token: TimelineToken = {
|
|
110
|
+
key: options.key,
|
|
111
|
+
type: `timeline`,
|
|
112
|
+
}
|
|
113
|
+
store.subject.timelineCreation.next(token)
|
|
114
|
+
return token
|
|
115
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Store } from "../store"
|
|
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
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { AtomToken, ƒn } from "atom.io"
|
|
2
|
+
import { setState, transaction } from "atom.io"
|
|
3
|
+
|
|
4
|
+
import { withdraw } from "../store"
|
|
5
|
+
import type { Store } from "../store"
|
|
6
|
+
|
|
7
|
+
export const applyTransaction = <ƒ extends ƒn>(
|
|
8
|
+
output: ReturnType<ƒ>,
|
|
9
|
+
store: Store,
|
|
10
|
+
): void => {
|
|
11
|
+
if (store.transactionStatus.phase !== `building`) {
|
|
12
|
+
store.config.logger?.warn(
|
|
13
|
+
`abortTransaction called outside of a transaction. This is probably a bug.`,
|
|
14
|
+
)
|
|
15
|
+
return
|
|
16
|
+
}
|
|
17
|
+
store.transactionStatus.phase = `applying`
|
|
18
|
+
store.transactionStatus.output = output
|
|
19
|
+
const { atomUpdates } = store.transactionStatus
|
|
20
|
+
store.config.logger?.info(
|
|
21
|
+
`🛃 applying transaction "${store.transactionStatus.key}" with ${atomUpdates.length} updates.`,
|
|
22
|
+
)
|
|
23
|
+
store.config.logger?.info(`🛃 the updates are:`, atomUpdates)
|
|
24
|
+
for (const { key, newValue } of atomUpdates) {
|
|
25
|
+
const token: AtomToken<unknown> = { key, type: `atom` }
|
|
26
|
+
if (!store.valueMap.has(token.key)) {
|
|
27
|
+
if (token.family) {
|
|
28
|
+
const family = store.families.get(token.family.key)
|
|
29
|
+
if (family) {
|
|
30
|
+
family(token.family.subKey)
|
|
31
|
+
}
|
|
32
|
+
} else {
|
|
33
|
+
const newAtom = store.transactionStatus.core.atoms.get(token.key)
|
|
34
|
+
if (!newAtom) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Absurd Error: Atom "${token.key}" not found while copying updates from transaction "${store.transactionStatus.key}" to store "${store.config.name}"`,
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
store.atoms.set(newAtom.key, newAtom)
|
|
40
|
+
store.valueMap.set(newAtom.key, newAtom.default)
|
|
41
|
+
store.config.logger?.info(`🔧`, `add atom "${newAtom.key}"`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// if (store.transactionStatus.key === `dealCards`) debugger
|
|
45
|
+
setState(token, newValue, store)
|
|
46
|
+
}
|
|
47
|
+
const myTransaction = withdraw<ƒ>(
|
|
48
|
+
{ key: store.transactionStatus.key, type: `transaction` },
|
|
49
|
+
store,
|
|
50
|
+
)
|
|
51
|
+
if (myTransaction === null) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Transaction "${store.transactionStatus.key}" not found. Absurd. How is this running?`,
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
myTransaction.subject.next({
|
|
57
|
+
key: store.transactionStatus.key,
|
|
58
|
+
atomUpdates,
|
|
59
|
+
output,
|
|
60
|
+
params: store.transactionStatus.params as Parameters<ƒ>,
|
|
61
|
+
})
|
|
62
|
+
store.transactionStatus = { phase: `idle` }
|
|
63
|
+
store.config.logger?.info(`🛬`, `transaction "${myTransaction.key}" applied`)
|
|
64
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Junction } from "~/packages/rel8/junction/src"
|
|
2
|
+
|
|
3
|
+
import type { Store } from "../store"
|
|
4
|
+
|
|
5
|
+
export const buildTransaction = (
|
|
6
|
+
key: string,
|
|
7
|
+
params: any[],
|
|
8
|
+
store: Store,
|
|
9
|
+
): void => {
|
|
10
|
+
store.transactionStatus = {
|
|
11
|
+
key,
|
|
12
|
+
phase: `building`,
|
|
13
|
+
time: Date.now(),
|
|
14
|
+
core: {
|
|
15
|
+
atoms: new Map(store.atoms),
|
|
16
|
+
atomsThatAreDefault: new Set(store.atomsThatAreDefault),
|
|
17
|
+
families: new Map(store.families),
|
|
18
|
+
operation: { open: false },
|
|
19
|
+
readonlySelectors: new Map(store.readonlySelectors),
|
|
20
|
+
timelines: new Map(store.timelines),
|
|
21
|
+
timelineAtoms: new Junction(store.timelineAtoms.toJSON()),
|
|
22
|
+
trackers: new Map(),
|
|
23
|
+
transactions: new Map(store.transactions),
|
|
24
|
+
selectorAtoms: new Junction(store.selectorAtoms.toJSON()),
|
|
25
|
+
selectorGraph: new Junction(store.selectorGraph.toJSON(), {
|
|
26
|
+
makeContentKey: (...keys) => keys.sort().join(`:`),
|
|
27
|
+
}),
|
|
28
|
+
selectors: new Map(store.selectors),
|
|
29
|
+
valueMap: new Map(store.valueMap),
|
|
30
|
+
},
|
|
31
|
+
atomUpdates: [],
|
|
32
|
+
params,
|
|
33
|
+
output: undefined,
|
|
34
|
+
}
|
|
35
|
+
store.config.logger?.info(
|
|
36
|
+
`🛫`,
|
|
37
|
+
`transaction "${key}" building in store "${store.config.name}"`,
|
|
38
|
+
)
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TransactionUpdate, ƒn } from "atom.io"
|
|
2
|
+
|
|
3
|
+
import type { StoreCore } from ".."
|
|
4
|
+
|
|
5
|
+
export * from "./transaction-internal"
|
|
6
|
+
|
|
7
|
+
export * from "./abort-transaction"
|
|
8
|
+
export * from "./apply-transaction"
|
|
9
|
+
export * from "./build-transaction"
|
|
10
|
+
export * from "./redo-transaction"
|
|
11
|
+
export * from "./undo-transaction"
|
|
12
|
+
|
|
13
|
+
export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
|
|
14
|
+
export type TransactionPhase = typeof TRANSACTION_PHASES[number]
|
|
15
|
+
|
|
16
|
+
export type TransactionUpdateInProgress<ƒ extends ƒn> = TransactionUpdate<ƒ> & {
|
|
17
|
+
phase: `applying` | `building`
|
|
18
|
+
time: number
|
|
19
|
+
core: StoreCore
|
|
20
|
+
}
|
|
21
|
+
export type TransactionIdle = {
|
|
22
|
+
phase: `idle`
|
|
23
|
+
}
|
|
24
|
+
export type TransactionStatus<ƒ extends ƒn> =
|
|
25
|
+
| TransactionIdle
|
|
26
|
+
| TransactionUpdateInProgress<ƒ>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AtomToken, TransactionUpdate, ƒn } from "atom.io"
|
|
2
|
+
import { setState } from "atom.io"
|
|
3
|
+
|
|
4
|
+
import { withdraw } from "../store"
|
|
5
|
+
import type { Store } from "../store"
|
|
6
|
+
|
|
7
|
+
export const redoTransactionUpdate = <ƒ extends ƒn>(
|
|
8
|
+
update: TransactionUpdate<ƒ>,
|
|
9
|
+
store: Store,
|
|
10
|
+
): void => {
|
|
11
|
+
store.config.logger?.info(` ⏭ redo transaction "${update.key}" (redo)`)
|
|
12
|
+
for (const { key, newValue } of update.atomUpdates) {
|
|
13
|
+
const token: AtomToken<unknown> = { key, type: `atom` }
|
|
14
|
+
const state = withdraw(token, store)
|
|
15
|
+
if (state === null) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
setState(state, newValue, store)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TransactionOptions,
|
|
3
|
+
TransactionToken,
|
|
4
|
+
TransactionUpdate,
|
|
5
|
+
ƒn,
|
|
6
|
+
} from "atom.io"
|
|
7
|
+
import { getState, setState } from "atom.io"
|
|
8
|
+
|
|
9
|
+
import { IMPLICIT, type Store, type StoreCore, deposit } from "../store"
|
|
10
|
+
import { Subject } from "../subject"
|
|
11
|
+
import { abortTransaction } from "./abort-transaction"
|
|
12
|
+
import { applyTransaction } from "./apply-transaction"
|
|
13
|
+
import { buildTransaction } from "./build-transaction"
|
|
14
|
+
|
|
15
|
+
export type Transaction<ƒ extends ƒn> = {
|
|
16
|
+
key: string
|
|
17
|
+
type: `transaction`
|
|
18
|
+
install: (store: Store) => void
|
|
19
|
+
subject: Subject<TransactionUpdate<ƒ>>
|
|
20
|
+
run: (...parameters: Parameters<ƒ>) => ReturnType<ƒ>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function transaction__INTERNAL<ƒ extends ƒn>(
|
|
24
|
+
options: TransactionOptions<ƒ>,
|
|
25
|
+
store: Store = IMPLICIT.STORE,
|
|
26
|
+
): TransactionToken<ƒ> {
|
|
27
|
+
const newTransaction: Transaction<ƒ> = {
|
|
28
|
+
key: options.key,
|
|
29
|
+
type: `transaction`,
|
|
30
|
+
run: (...params: Parameters<ƒ>) => {
|
|
31
|
+
buildTransaction(options.key, params, store)
|
|
32
|
+
try {
|
|
33
|
+
const output = options.do(
|
|
34
|
+
{
|
|
35
|
+
get: (token) => getState(token, store),
|
|
36
|
+
set: (token, value) => setState(token, value, store),
|
|
37
|
+
},
|
|
38
|
+
...params,
|
|
39
|
+
)
|
|
40
|
+
applyTransaction(output, store)
|
|
41
|
+
return output
|
|
42
|
+
} catch (thrown) {
|
|
43
|
+
abortTransaction(store)
|
|
44
|
+
store.config.logger?.error(
|
|
45
|
+
`Transaction "${options.key}" failed in store "${store.config.name}":`,
|
|
46
|
+
thrown,
|
|
47
|
+
)
|
|
48
|
+
throw thrown
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
install: (store) => transaction__INTERNAL(options, store),
|
|
52
|
+
subject: new Subject(),
|
|
53
|
+
}
|
|
54
|
+
const core = target(store)
|
|
55
|
+
core.transactions.set(newTransaction.key, newTransaction)
|
|
56
|
+
const token = deposit(newTransaction)
|
|
57
|
+
store.subject.transactionCreation.next(token)
|
|
58
|
+
return token
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export const target = (store: Store = IMPLICIT.STORE): StoreCore =>
|
|
62
|
+
store.transactionStatus.phase === `building`
|
|
63
|
+
? store.transactionStatus.core
|
|
64
|
+
: store
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { AtomToken, TransactionUpdate, ƒn } from "atom.io"
|
|
2
|
+
import { setState } from "atom.io"
|
|
3
|
+
|
|
4
|
+
import { withdraw } from "../store"
|
|
5
|
+
import type { Store } from "../store"
|
|
6
|
+
|
|
7
|
+
export const undoTransactionUpdate = <ƒ extends ƒn>(
|
|
8
|
+
update: TransactionUpdate<ƒ>,
|
|
9
|
+
store: Store,
|
|
10
|
+
): void => {
|
|
11
|
+
store.config.logger?.info(` ⏮ undo transaction "${update.key}" (undo)`)
|
|
12
|
+
for (const { key, oldValue } of update.atomUpdates) {
|
|
13
|
+
const token: AtomToken<unknown> = { key, type: `atom` }
|
|
14
|
+
const state = withdraw(token, store)
|
|
15
|
+
if (state === null) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`State "${token.key}" not found in this store. This is surprising, because we are navigating the history of the store.`,
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
setState(state, oldValue, store)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,200 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
type Serializable = primitive | Readonly<{
|
|
6
|
-
[key: string]: Serializable;
|
|
7
|
-
}> | ReadonlyArray<Serializable>;
|
|
8
|
-
type Object$1<Key extends string = string, Value extends Serializable = Serializable> = Record<Key, Value>;
|
|
9
|
-
|
|
10
|
-
type Refinement<Unrefined, Refined extends Unrefined> = (value: Unrefined) => value is Refined;
|
|
11
|
-
type Cardinality = `1:1` | `1:n` | `n:n`;
|
|
12
|
-
|
|
13
|
-
interface JunctionEntries<Content extends Object$1 | null> extends Object$1 {
|
|
14
|
-
readonly relations: [string, string[]][];
|
|
15
|
-
readonly contents: [string, Content][];
|
|
16
|
-
}
|
|
17
|
-
interface JunctionSchema<ASide extends string, BSide extends string> extends Object$1 {
|
|
18
|
-
readonly between: [a: ASide, b: BSide];
|
|
19
|
-
readonly cardinality: Cardinality;
|
|
20
|
-
}
|
|
21
|
-
type JunctionAdvancedConfiguration<Content extends Object$1 | null> = {
|
|
22
|
-
externalStore?: (Content extends null ? {
|
|
23
|
-
getContent?: undefined;
|
|
24
|
-
setContent?: undefined;
|
|
25
|
-
deleteContent?: undefined;
|
|
26
|
-
} : {
|
|
27
|
-
getContent: (contentKey: string) => Content | undefined;
|
|
28
|
-
setContent: (contentKey: string, content: Content) => void;
|
|
29
|
-
deleteContent: (g: any) => void;
|
|
30
|
-
}) & {
|
|
31
|
-
addRelation: (a: string, b: string) => void;
|
|
32
|
-
deleteRelation: (a: string, b: string) => void;
|
|
33
|
-
getRelatedKeys: (key: string) => Set<string> | undefined;
|
|
34
|
-
has: (a: string, b?: string) => boolean;
|
|
35
|
-
};
|
|
36
|
-
isContent?: Refinement<unknown, Content>;
|
|
37
|
-
makeContentKey?: (a: string, b: string) => string;
|
|
38
|
-
};
|
|
39
|
-
type JunctionJSON<ASide extends string, BSide extends string, Content extends Object$1 | null> = JunctionEntries<Content> & JunctionSchema<ASide, BSide>;
|
|
40
|
-
declare class Junction<ASide extends string, BSide extends string, Content extends Object$1 | null = null> {
|
|
41
|
-
readonly a: ASide;
|
|
42
|
-
readonly b: BSide;
|
|
43
|
-
readonly cardinality: Cardinality;
|
|
44
|
-
readonly relations: Map<string, Set<string>>;
|
|
45
|
-
readonly contents: Map<string, Content>;
|
|
46
|
-
isContent: Refinement<unknown, Content> | null;
|
|
47
|
-
makeContentKey: (a: string, b: string) => string;
|
|
48
|
-
getRelatedKeys(key: string): Set<string> | undefined;
|
|
49
|
-
protected addRelation(a: string, b: string): void;
|
|
50
|
-
protected deleteRelation(a: string, b: string): void;
|
|
51
|
-
protected getContentInternal(contentKey: string): Content | undefined;
|
|
52
|
-
protected setContent(contentKey: string, content: Content): void;
|
|
53
|
-
protected deleteContent(contentKey: string): void;
|
|
54
|
-
constructor(data: JunctionSchema<ASide, BSide> & Partial<JunctionEntries<Content>>, config?: JunctionAdvancedConfiguration<Content>);
|
|
55
|
-
toJSON(): JunctionJSON<ASide, BSide, Content>;
|
|
56
|
-
set(a: string, ...rest: Content extends null ? [b: string] : [b: string, content: Content]): this;
|
|
57
|
-
set(relation: {
|
|
58
|
-
[Key in ASide | BSide]: string;
|
|
59
|
-
}, ...rest: Content extends null ? [] | [b?: undefined] : [content: Content]): this;
|
|
60
|
-
delete(a: string, b?: string): this;
|
|
61
|
-
delete(relation: Record<ASide | BSide, string> | Record<ASide, string> | Record<BSide, string>, b?: undefined): this;
|
|
62
|
-
getRelatedKey(key: string): string | undefined;
|
|
63
|
-
getContent(a: string, b: string): Content | undefined;
|
|
64
|
-
getRelationEntries(input: Record<ASide, string> | Record<BSide, string>): [string, Content][];
|
|
65
|
-
has(a: string, b?: string): boolean;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
type OperationProgress = {
|
|
69
|
-
open: false;
|
|
70
|
-
} | {
|
|
71
|
-
open: true;
|
|
72
|
-
done: Set<string>;
|
|
73
|
-
prev: Map<string, any>;
|
|
74
|
-
time: number;
|
|
75
|
-
token: StateToken<any>;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
type Subscriber<T> = (value: T) => void;
|
|
79
|
-
declare class Subject<T> {
|
|
80
|
-
subscribers: Map<string, Subscriber<T>>;
|
|
81
|
-
subscribe(key: string, subscriber: Subscriber<T>): () => void;
|
|
82
|
-
private unsubscribe;
|
|
83
|
-
next(value: T): void;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
type Selector<T> = {
|
|
87
|
-
key: string;
|
|
88
|
-
type: `selector`;
|
|
89
|
-
family?: FamilyMetadata;
|
|
90
|
-
install: (store: Store) => void;
|
|
91
|
-
subject: Subject<{
|
|
92
|
-
newValue: T;
|
|
93
|
-
oldValue: T;
|
|
94
|
-
}>;
|
|
95
|
-
get: () => T;
|
|
96
|
-
set: (newValue: T | ((oldValue: T) => T)) => void;
|
|
97
|
-
};
|
|
98
|
-
type ReadonlySelector<T> = {
|
|
99
|
-
key: string;
|
|
100
|
-
type: `readonly_selector`;
|
|
101
|
-
family?: FamilyMetadata;
|
|
102
|
-
install: (store: Store) => void;
|
|
103
|
-
subject: Subject<{
|
|
104
|
-
newValue: T;
|
|
105
|
-
oldValue: T;
|
|
106
|
-
}>;
|
|
107
|
-
get: () => T;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
type TimelineAtomUpdate = StateUpdate<unknown> & {
|
|
111
|
-
key: string;
|
|
112
|
-
type: `atom_update`;
|
|
113
|
-
timestamp: number;
|
|
114
|
-
family?: FamilyMetadata;
|
|
115
|
-
};
|
|
116
|
-
type TimelineSelectorUpdate = {
|
|
117
|
-
key: string;
|
|
118
|
-
type: `selector_update`;
|
|
119
|
-
timestamp: number;
|
|
120
|
-
atomUpdates: Omit<TimelineAtomUpdate, `timestamp`>[];
|
|
121
|
-
};
|
|
122
|
-
type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
|
|
123
|
-
key: string;
|
|
124
|
-
type: `transaction_update`;
|
|
125
|
-
timestamp: number;
|
|
126
|
-
};
|
|
127
|
-
type Timeline = {
|
|
128
|
-
type: `timeline`;
|
|
129
|
-
key: string;
|
|
130
|
-
at: number;
|
|
131
|
-
timeTraveling: `into_future` | `into_past` | null;
|
|
132
|
-
history: TimelineUpdate[];
|
|
133
|
-
selectorTime: number | null;
|
|
134
|
-
transactionKey: string | null;
|
|
135
|
-
install: (store: Store) => void;
|
|
136
|
-
subject: Subject<TimelineAtomUpdate | TimelineSelectorUpdate | TimelineTransactionUpdate | `redo` | `undo`>;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
type Transaction<ƒ extends ƒn> = {
|
|
140
|
-
key: string;
|
|
141
|
-
type: `transaction`;
|
|
142
|
-
install: (store: Store) => void;
|
|
143
|
-
subject: Subject<TransactionUpdate<ƒ>>;
|
|
144
|
-
run: (...parameters: Parameters<ƒ>) => ReturnType<ƒ>;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
type TransactionUpdateInProgress<ƒ extends ƒn> = TransactionUpdate<ƒ> & {
|
|
148
|
-
phase: `applying` | `building`;
|
|
149
|
-
time: number;
|
|
150
|
-
core: StoreCore;
|
|
151
|
-
};
|
|
152
|
-
type TransactionIdle = {
|
|
153
|
-
phase: `idle`;
|
|
154
|
-
};
|
|
155
|
-
type TransactionStatus<ƒ extends ƒn> = TransactionIdle | TransactionUpdateInProgress<ƒ>;
|
|
156
|
-
|
|
157
|
-
type StoreCore = Pick<Store, `atoms` | `atomsThatAreDefault` | `operation` | `readonlySelectors` | `selectorAtoms` | `selectorGraph` | `selectors` | `timelineAtoms` | `timelines` | `transactions` | `valueMap`>;
|
|
158
|
-
declare class Store {
|
|
159
|
-
valueMap: Map<string, any>;
|
|
160
|
-
atoms: Map<string, Atom<any>>;
|
|
161
|
-
selectors: Map<string, Selector<any>>;
|
|
162
|
-
readonlySelectors: Map<string, ReadonlySelector<any>>;
|
|
163
|
-
timelines: Map<string, Timeline>;
|
|
164
|
-
transactions: Map<string, Transaction<ƒn>>;
|
|
165
|
-
atomsThatAreDefault: Set<string>;
|
|
166
|
-
timelineAtoms: Junction<"timelineKey", "atomKey", null>;
|
|
167
|
-
selectorAtoms: Junction<"selectorKey", "atomKey", null>;
|
|
168
|
-
selectorGraph: Junction<"upstreamSelectorKey", "downstreamSelectorKey", {
|
|
169
|
-
source: string;
|
|
170
|
-
}>;
|
|
171
|
-
subject: {
|
|
172
|
-
atomCreation: Subject<AtomToken<unknown>>;
|
|
173
|
-
selectorCreation: Subject<ReadonlySelectorToken<unknown> | SelectorToken<unknown>>;
|
|
174
|
-
transactionCreation: Subject<TransactionToken<ƒn>>;
|
|
175
|
-
timelineCreation: Subject<TimelineToken>;
|
|
176
|
-
operationStatus: Subject<OperationProgress>;
|
|
177
|
-
};
|
|
178
|
-
operation: OperationProgress;
|
|
179
|
-
transactionStatus: TransactionStatus<ƒn>;
|
|
180
|
-
config: {
|
|
181
|
-
name: string;
|
|
182
|
-
logger: Logger | null;
|
|
183
|
-
logger__INTERNAL: Logger;
|
|
184
|
-
};
|
|
185
|
-
constructor(name: string, store?: Store | null);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
type Atom<T> = {
|
|
189
|
-
key: string;
|
|
190
|
-
type: `atom`;
|
|
191
|
-
family?: FamilyMetadata;
|
|
192
|
-
subject: Subject<{
|
|
193
|
-
newValue: T;
|
|
194
|
-
oldValue: T;
|
|
195
|
-
}>;
|
|
196
|
-
default: T;
|
|
197
|
-
};
|
|
1
|
+
import { AtomToken, ReadonlySelectorToken, SelectorToken, TransactionToken, ƒn, ReadonlySelectorFamily, TransactionUpdate, TimelineToken } from 'atom.io';
|
|
2
|
+
import * as __INTERNAL__ from 'atom.io/internal';
|
|
3
|
+
import { Timeline } from 'atom.io/internal';
|
|
198
4
|
|
|
199
5
|
type AtomTokenIndex = StateTokenIndex<AtomToken<unknown>>;
|
|
200
6
|
|