atom.io 0.16.2 → 0.16.3
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/chunk-H4Q5FTPZ.js +11 -0
- package/dist/chunk-H4Q5FTPZ.js.map +1 -0
- package/dist/index.cjs +1 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +2 -11
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +225 -183
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +30 -9
- package/internal/dist/index.js +218 -184
- package/internal/dist/index.js.map +1 -1
- package/internal/src/families/find-in-store.ts +74 -0
- package/internal/src/families/index.ts +1 -0
- package/internal/src/ingest-updates/ingest-transaction-update.ts +1 -0
- package/internal/src/mutable/tracker.ts +28 -25
- package/internal/src/mutable/transceiver.ts +1 -1
- package/internal/src/not-found-error.ts +14 -3
- package/internal/src/operation.ts +2 -1
- package/internal/src/selector/create-writable-selector.ts +2 -1
- package/internal/src/selector/register-selector.ts +5 -4
- package/internal/src/set-state/set-atom.ts +16 -2
- package/internal/src/set-state/stow-update.ts +2 -4
- package/internal/src/store/store.ts +13 -4
- package/internal/src/timeline/add-atom-to-timeline.ts +5 -5
- package/internal/src/transaction/abort-transaction.ts +2 -1
- package/internal/src/transaction/apply-transaction.ts +5 -3
- package/internal/src/transaction/build-transaction.ts +16 -9
- package/internal/src/transaction/create-transaction.ts +2 -3
- package/internal/src/transaction/index.ts +3 -2
- package/internal/src/transaction/is-root-store.ts +23 -0
- package/package.json +10 -10
- package/react/dist/index.cjs +27 -21
- package/react/dist/index.cjs.map +1 -1
- package/react/dist/index.d.ts +8 -2
- package/react/dist/index.js +27 -21
- package/react/dist/index.js.map +1 -1
- package/react/src/index.ts +4 -1
- package/react/src/use-i.ts +36 -0
- package/react/src/use-json.ts +38 -0
- package/react/src/use-o.ts +34 -0
- package/react/src/use-tl.ts +45 -0
- package/realtime-client/dist/index.cjs +163 -63
- package/realtime-client/dist/index.cjs.map +1 -1
- package/realtime-client/dist/index.d.ts +10 -6
- package/realtime-client/dist/index.js +153 -61
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/src/index.ts +2 -1
- package/realtime-client/src/pull-state.ts +4 -3
- package/realtime-client/src/{realtime-client-store.ts → realtime-client-stores/client-main-store.ts} +0 -8
- package/realtime-client/src/realtime-client-stores/client-sync-store.ts +15 -0
- package/realtime-client/src/realtime-client-stores/index.ts +2 -0
- package/realtime-client/src/sync-server-action.ts +131 -40
- package/realtime-client/src/sync-state.ts +19 -0
- package/realtime-react/dist/index.cjs +43 -26
- package/realtime-react/dist/index.cjs.map +1 -1
- package/realtime-react/dist/index.d.ts +3 -1
- package/realtime-react/dist/index.js +41 -25
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/src/index.ts +1 -0
- package/realtime-react/src/on-mount.ts +3 -21
- package/realtime-react/src/use-realtime-service.ts +1 -1
- package/realtime-react/src/use-single-effect.ts +29 -0
- package/realtime-react/src/use-sync-server-action.ts +4 -7
- package/realtime-react/src/use-sync.ts +17 -0
- package/realtime-server/dist/index.cjs +223 -40
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +140 -9
- package/realtime-server/dist/index.js +213 -43
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +2 -0
- package/realtime-server/src/realtime-action-synchronizer.ts +87 -12
- package/realtime-server/src/realtime-family-provider.ts +2 -2
- package/realtime-server/src/realtime-mutable-family-provider.ts +2 -1
- package/realtime-server/src/realtime-server-stores/index.ts +2 -0
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +115 -0
- package/realtime-server/src/realtime-server-stores/server-user-store.ts +45 -0
- package/realtime-server/src/realtime-state-provider.ts +15 -8
- package/realtime-server/src/realtime-state-synchronizer.ts +23 -0
- package/realtime-testing/dist/index.cjs +65 -26
- package/realtime-testing/dist/index.cjs.map +1 -1
- package/realtime-testing/dist/index.d.ts +11 -7
- package/realtime-testing/dist/index.js +64 -26
- package/realtime-testing/dist/index.js.map +1 -1
- package/realtime-testing/src/setup-realtime-test.tsx +83 -43
- package/src/find-state.ts +8 -16
- package/src/logger.ts +1 -0
- package/src/transaction.ts +3 -3
- package/react/src/store-hooks.ts +0 -87
- package/realtime-server/src/realtime-server-store.ts +0 -39
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Json } from "atom.io/json"
|
|
2
|
+
|
|
3
|
+
import type {
|
|
4
|
+
MutableAtomFamilyToken,
|
|
5
|
+
MutableAtomToken,
|
|
6
|
+
ReadableFamilyToken,
|
|
7
|
+
ReadableToken,
|
|
8
|
+
ReadonlySelectorFamilyToken,
|
|
9
|
+
ReadonlySelectorToken,
|
|
10
|
+
RegularAtomFamilyToken,
|
|
11
|
+
RegularAtomToken,
|
|
12
|
+
WritableFamilyToken,
|
|
13
|
+
WritableSelectorFamilyToken,
|
|
14
|
+
WritableSelectorToken,
|
|
15
|
+
WritableToken,
|
|
16
|
+
} from "atom.io"
|
|
17
|
+
import type { Transceiver } from "../mutable"
|
|
18
|
+
import { NotFoundError } from "../not-found-error"
|
|
19
|
+
import type { Store } from "../store"
|
|
20
|
+
|
|
21
|
+
export function findInStore<
|
|
22
|
+
T extends Transceiver<any>,
|
|
23
|
+
J extends Json.Serializable,
|
|
24
|
+
K extends Json.Serializable,
|
|
25
|
+
Key extends K,
|
|
26
|
+
>(
|
|
27
|
+
token: MutableAtomFamilyToken<T, J, K>,
|
|
28
|
+
key: Key,
|
|
29
|
+
store: Store,
|
|
30
|
+
): MutableAtomToken<T, J>
|
|
31
|
+
|
|
32
|
+
export function findInStore<T, K extends Json.Serializable, Key extends K>(
|
|
33
|
+
token: RegularAtomFamilyToken<T, K>,
|
|
34
|
+
key: Key,
|
|
35
|
+
store: Store,
|
|
36
|
+
): RegularAtomToken<T>
|
|
37
|
+
|
|
38
|
+
export function findInStore<T, K extends Json.Serializable, Key extends K>(
|
|
39
|
+
token: WritableSelectorFamilyToken<T, K>,
|
|
40
|
+
key: Key,
|
|
41
|
+
store: Store,
|
|
42
|
+
): WritableSelectorToken<T>
|
|
43
|
+
|
|
44
|
+
export function findInStore<T, K extends Json.Serializable, Key extends K>(
|
|
45
|
+
token: ReadonlySelectorFamilyToken<T, K>,
|
|
46
|
+
key: Key,
|
|
47
|
+
store: Store,
|
|
48
|
+
): ReadonlySelectorToken<T>
|
|
49
|
+
|
|
50
|
+
export function findInStore<T, K extends Json.Serializable, Key extends K>(
|
|
51
|
+
token: WritableFamilyToken<T, K>,
|
|
52
|
+
key: Key,
|
|
53
|
+
store: Store,
|
|
54
|
+
): WritableToken<T>
|
|
55
|
+
|
|
56
|
+
export function findInStore<T, K extends Json.Serializable, Key extends K>(
|
|
57
|
+
token: ReadableFamilyToken<T, K>,
|
|
58
|
+
key: Key,
|
|
59
|
+
store: Store,
|
|
60
|
+
): ReadableToken<T>
|
|
61
|
+
|
|
62
|
+
export function findInStore(
|
|
63
|
+
token: ReadableFamilyToken<any, any>,
|
|
64
|
+
key: Json.Serializable,
|
|
65
|
+
store: Store,
|
|
66
|
+
): ReadableToken<any> {
|
|
67
|
+
const familyKey = token.key
|
|
68
|
+
const family = store.families.get(familyKey)
|
|
69
|
+
if (family === undefined) {
|
|
70
|
+
throw new NotFoundError(token, store)
|
|
71
|
+
}
|
|
72
|
+
const state = family(key)
|
|
73
|
+
return state
|
|
74
|
+
}
|
|
@@ -5,6 +5,7 @@ import type { Json } from "atom.io/json"
|
|
|
5
5
|
import type { Store } from ".."
|
|
6
6
|
import { newest, subscribeToState, subscribeToTimeline } from ".."
|
|
7
7
|
import { createRegularAtom } from "../atom"
|
|
8
|
+
import { isChildStore, isRootStore } from "../transaction/is-root-store"
|
|
8
9
|
import type { Transceiver } from "./transceiver"
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -51,19 +52,14 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
51
52
|
private observeCore(
|
|
52
53
|
mutableState: MutableAtomToken<Mutable, any>,
|
|
53
54
|
latestUpdateState: RegularAtomToken<typeof this.Update | null>,
|
|
54
|
-
|
|
55
|
+
target: Store,
|
|
55
56
|
): void {
|
|
56
|
-
const subscriptionKey = `tracker:${
|
|
57
|
-
|
|
57
|
+
const subscriptionKey = `tracker:${target.config.name}:${
|
|
58
|
+
isChildStore(target) ? target.transactionMeta.update.key : `main`
|
|
58
59
|
}:${mutableState.key}`
|
|
59
|
-
const originalInnerValue = getState(mutableState,
|
|
60
|
-
const target = newest(store)
|
|
60
|
+
const originalInnerValue = getState(mutableState, target)
|
|
61
61
|
this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
|
|
62
|
-
|
|
63
|
-
target.transactionMeta === null
|
|
64
|
-
? `main`
|
|
65
|
-
: target.transactionMeta.update.key
|
|
66
|
-
}`,
|
|
62
|
+
subscriptionKey,
|
|
67
63
|
(update) => {
|
|
68
64
|
if (target.operation.open) {
|
|
69
65
|
const unsubscribe = target.on.operationClose.subscribe(
|
|
@@ -84,7 +80,6 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
84
80
|
(update) => {
|
|
85
81
|
if (update.newValue !== update.oldValue) {
|
|
86
82
|
this.unsubscribeFromInnerValue()
|
|
87
|
-
const target = newest(store)
|
|
88
83
|
this.unsubscribeFromInnerValue = update.newValue.subscribe(
|
|
89
84
|
subscriptionKey,
|
|
90
85
|
(update) => {
|
|
@@ -105,26 +100,27 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
105
100
|
}
|
|
106
101
|
},
|
|
107
102
|
subscriptionKey,
|
|
108
|
-
|
|
103
|
+
target,
|
|
109
104
|
)
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
private updateCore<Core extends Transceiver<any>>(
|
|
113
108
|
mutableState: MutableAtomToken<Core, Json.Serializable>,
|
|
114
109
|
latestUpdateState: RegularAtomToken<typeof this.Update | null>,
|
|
115
|
-
|
|
110
|
+
target: Store,
|
|
116
111
|
): void {
|
|
117
|
-
const subscriptionKey = `tracker:${
|
|
118
|
-
|
|
112
|
+
const subscriptionKey = `tracker:${target.config.name}:${
|
|
113
|
+
isChildStore(target) ? target.transactionMeta.update.key : `main`
|
|
119
114
|
}:${mutableState.key}`
|
|
120
115
|
subscribeToState(
|
|
121
116
|
latestUpdateState,
|
|
122
117
|
({ newValue, oldValue }) => {
|
|
123
|
-
const timelineId =
|
|
118
|
+
const timelineId = target.timelineAtoms.getRelatedKey(
|
|
124
119
|
latestUpdateState.key,
|
|
125
120
|
)
|
|
121
|
+
|
|
126
122
|
if (timelineId) {
|
|
127
|
-
const timelineData =
|
|
123
|
+
const timelineData = target.timelines.get(timelineId)
|
|
128
124
|
if (timelineData?.timeTraveling) {
|
|
129
125
|
const unsubscribe = subscribeToTimeline(
|
|
130
126
|
{ key: timelineId, type: `timeline` },
|
|
@@ -140,38 +136,45 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
140
136
|
}
|
|
141
137
|
return transceiver
|
|
142
138
|
},
|
|
143
|
-
|
|
139
|
+
target,
|
|
144
140
|
)
|
|
145
141
|
},
|
|
146
142
|
subscriptionKey,
|
|
147
|
-
|
|
143
|
+
target,
|
|
148
144
|
)
|
|
149
145
|
return
|
|
150
146
|
}
|
|
151
147
|
}
|
|
152
148
|
|
|
153
|
-
const unsubscribe =
|
|
149
|
+
const unsubscribe = target.on.operationClose.subscribe(
|
|
154
150
|
subscriptionKey,
|
|
155
151
|
() => {
|
|
156
152
|
unsubscribe()
|
|
157
|
-
const mutable = getState(mutableState,
|
|
158
|
-
// debugger
|
|
153
|
+
const mutable = getState(mutableState, target)
|
|
159
154
|
const updateNumber =
|
|
160
155
|
newValue === null ? -1 : mutable.getUpdateNumber(newValue)
|
|
161
156
|
const eventOffset = updateNumber - mutable.cacheUpdateNumber
|
|
162
157
|
if (newValue && eventOffset === 1) {
|
|
163
|
-
// ❗ new:"0=add:\"myHand\"",old:"0=add:\"deckId\""
|
|
164
158
|
setState(
|
|
165
159
|
mutableState,
|
|
166
160
|
(transceiver) => (transceiver.do(newValue), transceiver),
|
|
167
|
-
|
|
161
|
+
target,
|
|
162
|
+
)
|
|
163
|
+
} else {
|
|
164
|
+
target.logger.info(
|
|
165
|
+
`❌`,
|
|
166
|
+
`mutable_atom`,
|
|
167
|
+
mutableState.key,
|
|
168
|
+
`could not be updated. Expected update number ${
|
|
169
|
+
mutable.cacheUpdateNumber + 1
|
|
170
|
+
}, but got ${updateNumber}`,
|
|
168
171
|
)
|
|
169
172
|
}
|
|
170
173
|
},
|
|
171
174
|
)
|
|
172
175
|
},
|
|
173
176
|
subscriptionKey,
|
|
174
|
-
|
|
177
|
+
target,
|
|
175
178
|
)
|
|
176
179
|
}
|
|
177
180
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Json } from "atom.io/json"
|
|
2
2
|
|
|
3
3
|
export interface Transceiver<Signal extends Json.Serializable> {
|
|
4
|
-
do: (update: Signal) =>
|
|
4
|
+
do: (update: Signal) => number | `OUT_OF_RANGE` | null
|
|
5
5
|
undo: (update: Signal) => void
|
|
6
6
|
subscribe: (key: string, fn: (update: Signal) => void) => () => void
|
|
7
7
|
cacheUpdateNumber: number
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
ReadableFamilyToken,
|
|
3
|
+
ReadableToken,
|
|
4
|
+
TimelineToken,
|
|
5
|
+
TransactionToken,
|
|
6
|
+
} from "atom.io"
|
|
2
7
|
|
|
3
8
|
import type { Store } from "./store"
|
|
4
9
|
|
|
5
10
|
const capitalize = (str: string) => str[0].toUpperCase() + str.slice(1)
|
|
6
11
|
|
|
7
|
-
|
|
12
|
+
type AtomIOToken =
|
|
13
|
+
| ReadableFamilyToken<any, any>
|
|
14
|
+
| ReadableToken<any>
|
|
15
|
+
| TimelineToken<any>
|
|
16
|
+
| TransactionToken<any>
|
|
17
|
+
|
|
18
|
+
function prettyPrintTokenType(token: AtomIOToken) {
|
|
8
19
|
if (token.type === `readonly_selector`) {
|
|
9
20
|
return `Readonly Selector`
|
|
10
21
|
}
|
|
@@ -12,7 +23,7 @@ function prettyPrintTokenType(token: ReadableToken<any>) {
|
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
export class NotFoundError extends Error {
|
|
15
|
-
public constructor(token:
|
|
26
|
+
public constructor(token: AtomIOToken, store: Store) {
|
|
16
27
|
super(
|
|
17
28
|
`${prettyPrintTokenType(token)} "${token.key}" not found in store "${
|
|
18
29
|
store.config.name
|
|
@@ -2,6 +2,7 @@ import type { WritableToken } from "atom.io"
|
|
|
2
2
|
|
|
3
3
|
import { newest } from "./lineage"
|
|
4
4
|
import type { Store } from "./store"
|
|
5
|
+
import { isChildStore } from "./transaction/is-root-store"
|
|
5
6
|
|
|
6
7
|
export type OperationProgress =
|
|
7
8
|
| {
|
|
@@ -40,7 +41,7 @@ export const openOperation = (
|
|
|
40
41
|
token.type,
|
|
41
42
|
token.key,
|
|
42
43
|
`operation start in store "${store.config.name}"${
|
|
43
|
-
store
|
|
44
|
+
!isChildStore(store)
|
|
44
45
|
? ``
|
|
45
46
|
: ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`
|
|
46
47
|
}`,
|
|
@@ -11,6 +11,7 @@ import { markDone } from "../operation"
|
|
|
11
11
|
import { become } from "../set-state/become"
|
|
12
12
|
import type { Store } from "../store"
|
|
13
13
|
import { Subject } from "../subject"
|
|
14
|
+
import { isRootStore } from "../transaction/is-root-store"
|
|
14
15
|
import { registerSelector } from "./register-selector"
|
|
15
16
|
|
|
16
17
|
export const createWritableSelector = <T>(
|
|
@@ -45,7 +46,7 @@ export const createWritableSelector = <T>(
|
|
|
45
46
|
)
|
|
46
47
|
cacheValue(options.key, newValue, subject, store)
|
|
47
48
|
markDone(options.key, store)
|
|
48
|
-
if (target
|
|
49
|
+
if (isRootStore(target)) {
|
|
49
50
|
subject.next({ newValue, oldValue })
|
|
50
51
|
}
|
|
51
52
|
options.set(transactors, newValue)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Transactors, findState } from "atom.io"
|
|
2
|
-
import { findInStore } from "atom.io"
|
|
3
2
|
|
|
3
|
+
import { findInStore } from "../families"
|
|
4
4
|
import { newest } from "../lineage"
|
|
5
5
|
import { readOrComputeValue } from "../read-or-compute-value"
|
|
6
6
|
import { setAtomOrSelector } from "../set-state"
|
|
7
7
|
import type { Store } from "../store"
|
|
8
|
-
import { withdraw } from "../store"
|
|
8
|
+
import { withdraw, withdrawNewFamilyMember } from "../store"
|
|
9
9
|
import { updateSelectorAtoms } from "./update-selector-atoms"
|
|
10
10
|
|
|
11
11
|
export const registerSelector = (
|
|
@@ -15,10 +15,11 @@ export const registerSelector = (
|
|
|
15
15
|
get: (dependency) => {
|
|
16
16
|
const target = newest(store)
|
|
17
17
|
|
|
18
|
-
const dependencyState =
|
|
18
|
+
const dependencyState =
|
|
19
|
+
withdraw(dependency, store) ?? withdrawNewFamilyMember(dependency, store)
|
|
19
20
|
if (dependencyState === undefined) {
|
|
20
21
|
throw new Error(
|
|
21
|
-
`State "${dependency.key}" not found in
|
|
22
|
+
`State "${dependency.key}" not found in store "${store.config.name}".`,
|
|
22
23
|
)
|
|
23
24
|
}
|
|
24
25
|
const dependencyValue = readOrComputeValue(dependencyState, store)
|
|
@@ -5,6 +5,7 @@ import type { Transceiver } from "../mutable"
|
|
|
5
5
|
import { markDone } from "../operation"
|
|
6
6
|
import { readOrComputeValue } from "../read-or-compute-value"
|
|
7
7
|
import type { Store } from "../store"
|
|
8
|
+
import { isRootStore } from "../transaction/is-root-store"
|
|
8
9
|
import { become } from "./become"
|
|
9
10
|
import { copyMutableIfWithinTransaction } from "./copy-mutable-in-transaction"
|
|
10
11
|
import { emitUpdate } from "./emit-update"
|
|
@@ -27,7 +28,7 @@ export const setAtom = <T>(
|
|
|
27
28
|
markDone(atom.key, target)
|
|
28
29
|
evictDownStream(atom, target)
|
|
29
30
|
const update = { oldValue, newValue }
|
|
30
|
-
if (target
|
|
31
|
+
if (isRootStore(target)) {
|
|
31
32
|
emitUpdate(atom, update, target)
|
|
32
33
|
} else if (target.parent) {
|
|
33
34
|
if (target.on.transactionApplying.state === null) {
|
|
@@ -37,7 +38,20 @@ export const setAtom = <T>(
|
|
|
37
38
|
const mutableAtom = target.atoms.get(mutableKey) as Atom<any>
|
|
38
39
|
let mutable: Transceiver<any> = target.valueMap.get(mutableKey)
|
|
39
40
|
mutable = copyMutableIfWithinTransaction(mutable, mutableAtom, target)
|
|
40
|
-
mutable.do(update.newValue)
|
|
41
|
+
const output = mutable.do(update.newValue)
|
|
42
|
+
if (output !== null) {
|
|
43
|
+
target.logger.warn(
|
|
44
|
+
`❌`,
|
|
45
|
+
`mutable_atom`,
|
|
46
|
+
mutableKey,
|
|
47
|
+
`could not be updated.`,
|
|
48
|
+
typeof output === `number`
|
|
49
|
+
? `Expected update number ${
|
|
50
|
+
mutable.cacheUpdateNumber + 1
|
|
51
|
+
}, but got ${output}`
|
|
52
|
+
: output,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
41
55
|
}
|
|
42
56
|
}
|
|
43
57
|
}
|
|
@@ -4,6 +4,7 @@ import type { Atom } from ".."
|
|
|
4
4
|
import { newest } from "../lineage"
|
|
5
5
|
import { isTransceiver } from "../mutable"
|
|
6
6
|
import type { Store } from "../store"
|
|
7
|
+
import { isChildStore } from "../transaction/is-root-store"
|
|
7
8
|
|
|
8
9
|
function shouldUpdateBeStowed(key: string, update: StateUpdate<any>): boolean {
|
|
9
10
|
// do not stow updates that aren't json
|
|
@@ -24,10 +25,7 @@ export const stowUpdate = <T>(
|
|
|
24
25
|
): void => {
|
|
25
26
|
const { key } = state
|
|
26
27
|
const target = newest(store)
|
|
27
|
-
if (
|
|
28
|
-
target.transactionMeta === null ||
|
|
29
|
-
target.transactionMeta.phase !== `building`
|
|
30
|
-
) {
|
|
28
|
+
if (!isChildStore(target) || target.transactionMeta.phase !== `building`) {
|
|
31
29
|
store.logger.error(
|
|
32
30
|
`🐞`,
|
|
33
31
|
`atom`,
|
|
@@ -27,7 +27,11 @@ import { getJsonToken, getUpdateToken } from "../mutable"
|
|
|
27
27
|
import type { OperationProgress } from "../operation"
|
|
28
28
|
import { StatefulSubject, Subject } from "../subject"
|
|
29
29
|
import type { Timeline } from "../timeline"
|
|
30
|
-
import type {
|
|
30
|
+
import type {
|
|
31
|
+
Transaction,
|
|
32
|
+
TransactionEpoch,
|
|
33
|
+
TransactionProgress,
|
|
34
|
+
} from "../transaction"
|
|
31
35
|
|
|
32
36
|
export class Store implements Lineage {
|
|
33
37
|
public parent: Store | null = null
|
|
@@ -82,11 +86,15 @@ export class Store implements Lineage {
|
|
|
82
86
|
>(),
|
|
83
87
|
transactionCreation: new Subject<TransactionToken<ƒn>>(),
|
|
84
88
|
timelineCreation: new Subject<TimelineToken<unknown>>(),
|
|
85
|
-
transactionApplying: new StatefulSubject<
|
|
89
|
+
transactionApplying: new StatefulSubject<TransactionProgress<ƒn> | null>(
|
|
90
|
+
null,
|
|
91
|
+
),
|
|
86
92
|
operationClose: new Subject<OperationProgress>(),
|
|
87
93
|
}
|
|
88
94
|
public operation: OperationProgress = { open: false }
|
|
89
|
-
public transactionMeta:
|
|
95
|
+
public transactionMeta: TransactionEpoch | TransactionProgress<ƒn> = {
|
|
96
|
+
epoch: -1,
|
|
97
|
+
}
|
|
90
98
|
|
|
91
99
|
public config: {
|
|
92
100
|
name: string
|
|
@@ -113,7 +121,8 @@ export class Store implements Lineage {
|
|
|
113
121
|
if (store !== null) {
|
|
114
122
|
this.valueMap = new Map(store?.valueMap)
|
|
115
123
|
this.operation = { ...store?.operation }
|
|
116
|
-
this.transactionMeta =
|
|
124
|
+
this.transactionMeta = { ...store?.transactionMeta }
|
|
125
|
+
|
|
117
126
|
this.config = {
|
|
118
127
|
...store?.config,
|
|
119
128
|
name,
|
|
@@ -30,7 +30,6 @@ export const addAtomToTimeline = (
|
|
|
30
30
|
store.timelineAtoms.set({ atomKey: atom.key, timelineKey: tl.key })
|
|
31
31
|
|
|
32
32
|
atom.subject.subscribe(`timeline`, (update) => {
|
|
33
|
-
// debugger
|
|
34
33
|
const target = newest(store)
|
|
35
34
|
const currentSelectorKey =
|
|
36
35
|
store.operation.open && store.operation.token.type === `selector`
|
|
@@ -40,8 +39,9 @@ export const addAtomToTimeline = (
|
|
|
40
39
|
store.operation.open && store.operation.token.type === `selector`
|
|
41
40
|
? store.operation.time
|
|
42
41
|
: null
|
|
43
|
-
const
|
|
44
|
-
const
|
|
42
|
+
const { transactionApplying } = target.on
|
|
43
|
+
const currentTransactionKey = transactionApplying.state?.update.key
|
|
44
|
+
const currentTransactionInstanceId = transactionApplying.state?.update.id
|
|
45
45
|
|
|
46
46
|
store.logger.info(
|
|
47
47
|
`⏳`,
|
|
@@ -93,7 +93,7 @@ export const addAtomToTimeline = (
|
|
|
93
93
|
`timeline:${tl.key}`,
|
|
94
94
|
(update) => {
|
|
95
95
|
unsubscribe()
|
|
96
|
-
if (tl.timeTraveling === null &&
|
|
96
|
+
if (tl.timeTraveling === null && currentTransactionInstanceId) {
|
|
97
97
|
if (tl.at !== tl.history.length) {
|
|
98
98
|
tl.history.splice(tl.at)
|
|
99
99
|
}
|
|
@@ -132,7 +132,7 @@ export const addAtomToTimeline = (
|
|
|
132
132
|
|
|
133
133
|
const timelineTransactionUpdate: TimelineTransactionUpdate = {
|
|
134
134
|
type: `transaction_update`,
|
|
135
|
-
timestamp:
|
|
135
|
+
timestamp: Date.now(),
|
|
136
136
|
...update,
|
|
137
137
|
updates,
|
|
138
138
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { newest } from "../lineage"
|
|
2
2
|
import type { Store } from "../store"
|
|
3
|
+
import { isChildStore } from "./is-root-store"
|
|
3
4
|
|
|
4
5
|
export const abortTransaction = (store: Store): void => {
|
|
5
6
|
const target = newest(store)
|
|
6
|
-
if (target
|
|
7
|
+
if (!isChildStore(target)) {
|
|
7
8
|
store.logger.warn(
|
|
8
9
|
`🐞`,
|
|
9
10
|
`transaction`,
|
|
@@ -4,6 +4,7 @@ import { ingestTransactionUpdate } from "../ingest-updates"
|
|
|
4
4
|
import { newest } from "../lineage"
|
|
5
5
|
import { withdraw } from "../store"
|
|
6
6
|
import type { Store } from "../store"
|
|
7
|
+
import { isChildStore, isRootStore } from "./is-root-store"
|
|
7
8
|
|
|
8
9
|
export const applyTransaction = <ƒ extends ƒn>(
|
|
9
10
|
output: ReturnType<ƒ>,
|
|
@@ -13,7 +14,7 @@ export const applyTransaction = <ƒ extends ƒn>(
|
|
|
13
14
|
const { parent } = child
|
|
14
15
|
if (
|
|
15
16
|
parent === null ||
|
|
16
|
-
child
|
|
17
|
+
!isChildStore(child) ||
|
|
17
18
|
child.transactionMeta?.phase !== `building`
|
|
18
19
|
) {
|
|
19
20
|
store.logger.warn(
|
|
@@ -57,7 +58,8 @@ export const applyTransaction = <ƒ extends ƒn>(
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
ingestTransactionUpdate(`newValue`, child.transactionMeta.update, parent)
|
|
60
|
-
if (parent
|
|
61
|
+
if (isRootStore(parent)) {
|
|
62
|
+
parent.transactionMeta.epoch = child.transactionMeta.update.epoch
|
|
61
63
|
const myTransaction = withdraw<ƒ>(
|
|
62
64
|
{ key: child.transactionMeta.update.key, type: `transaction` },
|
|
63
65
|
store,
|
|
@@ -69,7 +71,7 @@ export const applyTransaction = <ƒ extends ƒn>(
|
|
|
69
71
|
child.transactionMeta.update.key,
|
|
70
72
|
`Finished applying transaction.`,
|
|
71
73
|
)
|
|
72
|
-
} else {
|
|
74
|
+
} else if (isChildStore(parent)) {
|
|
73
75
|
parent.transactionMeta.update.updates.push(child.transactionMeta.update)
|
|
74
76
|
}
|
|
75
77
|
parent.on.transactionApplying.next(null)
|
|
@@ -1,28 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { findState } from "atom.io"
|
|
1
|
+
import { getState, runTransaction, setState } from "atom.io"
|
|
2
|
+
import type { findState, ƒn } from "atom.io"
|
|
3
3
|
|
|
4
4
|
import { Junction } from "~/packages/rel8/junction/src"
|
|
5
5
|
|
|
6
|
+
import type { TransactionProgress } from "."
|
|
7
|
+
import { findInStore } from "../families"
|
|
6
8
|
import { getEnvironmentData } from "../get-environment-data"
|
|
7
9
|
import { LazyMap } from "../lazy-map"
|
|
8
10
|
import { newest } from "../lineage"
|
|
9
11
|
import type { Store } from "../store"
|
|
12
|
+
import type { ChildStore, RootStore } from "./is-root-store"
|
|
13
|
+
import { isRootStore } from "./is-root-store"
|
|
10
14
|
|
|
11
15
|
export const buildTransaction = (
|
|
12
16
|
key: string,
|
|
13
17
|
params: any[],
|
|
14
18
|
store: Store,
|
|
15
19
|
id?: string,
|
|
16
|
-
):
|
|
17
|
-
const parent = newest(store)
|
|
18
|
-
const
|
|
20
|
+
): ChildStore => {
|
|
21
|
+
const parent = newest(store) as ChildStore | RootStore
|
|
22
|
+
const childBase: Omit<ChildStore, `transactionMeta`> = {
|
|
19
23
|
parent,
|
|
20
24
|
child: null,
|
|
21
25
|
on: parent.on,
|
|
22
26
|
loggers: parent.loggers,
|
|
23
27
|
logger: parent.logger,
|
|
24
28
|
config: parent.config,
|
|
25
|
-
transactionMeta: null,
|
|
26
29
|
atoms: new LazyMap(parent.atoms),
|
|
27
30
|
atomsThatAreDefault: new Set(parent.atomsThatAreDefault),
|
|
28
31
|
families: new LazyMap(parent.families),
|
|
@@ -39,12 +42,12 @@ export const buildTransaction = (
|
|
|
39
42
|
selectors: new LazyMap(parent.selectors),
|
|
40
43
|
valueMap: new LazyMap(parent.valueMap),
|
|
41
44
|
}
|
|
42
|
-
|
|
43
|
-
phase: `building
|
|
44
|
-
time: Date.now(),
|
|
45
|
+
const transactionMeta: TransactionProgress<ƒn> = {
|
|
46
|
+
phase: `building` as const,
|
|
45
47
|
update: {
|
|
46
48
|
key,
|
|
47
49
|
id: id ?? Math.random().toString(36).slice(2),
|
|
50
|
+
epoch: isRootStore(parent) ? parent.transactionMeta.epoch + 1 : NaN,
|
|
48
51
|
updates: [],
|
|
49
52
|
params,
|
|
50
53
|
output: undefined,
|
|
@@ -57,6 +60,9 @@ export const buildTransaction = (
|
|
|
57
60
|
env: () => getEnvironmentData(child),
|
|
58
61
|
},
|
|
59
62
|
}
|
|
63
|
+
const child: ChildStore = Object.assign(childBase, {
|
|
64
|
+
transactionMeta,
|
|
65
|
+
})
|
|
60
66
|
parent.child = child
|
|
61
67
|
store.logger.info(
|
|
62
68
|
`🛫`,
|
|
@@ -65,4 +71,5 @@ export const buildTransaction = (
|
|
|
65
71
|
`Building transaction with params:`,
|
|
66
72
|
params,
|
|
67
73
|
)
|
|
74
|
+
return child
|
|
68
75
|
}
|
|
@@ -29,11 +29,10 @@ export function createTransaction<ƒ extends ƒn>(
|
|
|
29
29
|
key: options.key,
|
|
30
30
|
type: `transaction`,
|
|
31
31
|
run: (params: Parameters<ƒ>, id?: string) => {
|
|
32
|
-
buildTransaction(options.key, params, store, id)
|
|
32
|
+
const childStore = buildTransaction(options.key, params, store, id)
|
|
33
33
|
try {
|
|
34
34
|
const target = newest(store)
|
|
35
|
-
|
|
36
|
-
const { transactors } = target.transactionMeta!
|
|
35
|
+
const { transactors } = childStore.transactionMeta
|
|
37
36
|
const output = options.do(transactors, ...params)
|
|
38
37
|
applyTransaction(output, target)
|
|
39
38
|
return output
|
|
@@ -8,9 +8,10 @@ export * from "./create-transaction"
|
|
|
8
8
|
export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
|
|
9
9
|
export type TransactionPhase = (typeof TRANSACTION_PHASES)[number]
|
|
10
10
|
|
|
11
|
-
export type
|
|
11
|
+
export type TransactionProgress<ƒ extends ƒn> = {
|
|
12
12
|
phase: `applying` | `building`
|
|
13
|
-
time: number
|
|
14
13
|
update: TransactionUpdate<ƒ>
|
|
15
14
|
transactors: TransactorsWithRunAndEnv
|
|
16
15
|
}
|
|
16
|
+
|
|
17
|
+
export type TransactionEpoch = { epoch: number }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ƒn } from "atom.io"
|
|
2
|
+
|
|
3
|
+
import type { TransactionEpoch, TransactionProgress } from "."
|
|
4
|
+
import type { Store } from "../store"
|
|
5
|
+
|
|
6
|
+
export interface RootStore extends Store {
|
|
7
|
+
transactionMeta: TransactionEpoch
|
|
8
|
+
parent: null
|
|
9
|
+
child: ChildStore | null
|
|
10
|
+
}
|
|
11
|
+
export interface ChildStore extends Store {
|
|
12
|
+
transactionMeta: TransactionProgress<ƒn>
|
|
13
|
+
parent: ChildStore | RootStore
|
|
14
|
+
child: ChildStore | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isRootStore(store: Store): store is RootStore {
|
|
18
|
+
return `epoch` in store.transactionMeta
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isChildStore(store: Store): store is ChildStore {
|
|
22
|
+
return `phase` in store.transactionMeta
|
|
23
|
+
}
|