atom.io 0.16.1 → 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/data/dist/index.cjs +31 -14
- package/data/dist/index.cjs.map +1 -1
- package/data/dist/index.js +31 -14
- package/data/dist/index.js.map +1 -1
- package/data/src/join.ts +31 -14
- package/dist/chunk-H4Q5FTPZ.js +11 -0
- package/dist/chunk-H4Q5FTPZ.js.map +1 -0
- package/dist/index.cjs +7 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -7
- package/dist/index.js +8 -14
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +240 -193
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +30 -9
- package/internal/dist/index.js +233 -194
- 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 +37 -32
- 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 +23 -6
- 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 +17 -10
- 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 -62
- 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 -60
- 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 -39
- 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-server-action.ts +1 -1
- package/realtime-react/src/use-single-effect.ts +29 -0
- package/realtime-react/src/use-sync-server-action.ts +5 -8
- package/realtime-react/src/use-sync.ts +17 -0
- package/realtime-server/dist/index.cjs +242 -48
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +147 -9
- package/realtime-server/dist/index.js +232 -51
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +2 -0
- package/realtime-server/src/realtime-action-receiver.ts +4 -3
- package/realtime-server/src/realtime-action-synchronizer.ts +100 -13
- package/realtime-server/src/realtime-family-provider.ts +10 -6
- package/realtime-server/src/realtime-mutable-family-provider.ts +15 -18
- package/realtime-server/src/realtime-mutable-provider.ts +1 -0
- 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 +16 -8
- package/realtime-server/src/realtime-state-receiver.ts +1 -0
- 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 +16 -11
- package/src/transaction.ts +4 -4
- 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,20 +52,18 @@ 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
|
|
57
|
-
|
|
57
|
+
const subscriptionKey = `tracker:${target.config.name}:${
|
|
58
|
+
isChildStore(target) ? target.transactionMeta.update.key : `main`
|
|
59
|
+
}:${mutableState.key}`
|
|
60
|
+
const originalInnerValue = getState(mutableState, target)
|
|
58
61
|
this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
|
|
59
|
-
|
|
60
|
-
target.transactionMeta === null
|
|
61
|
-
? `main`
|
|
62
|
-
: target.transactionMeta.update.key
|
|
63
|
-
}`,
|
|
62
|
+
subscriptionKey,
|
|
64
63
|
(update) => {
|
|
65
64
|
if (target.operation.open) {
|
|
66
65
|
const unsubscribe = target.on.operationClose.subscribe(
|
|
67
|
-
|
|
66
|
+
subscriptionKey,
|
|
68
67
|
() => {
|
|
69
68
|
unsubscribe()
|
|
70
69
|
setState(latestUpdateState, update, target)
|
|
@@ -81,17 +80,12 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
81
80
|
(update) => {
|
|
82
81
|
if (update.newValue !== update.oldValue) {
|
|
83
82
|
this.unsubscribeFromInnerValue()
|
|
84
|
-
const target = newest(store)
|
|
85
83
|
this.unsubscribeFromInnerValue = update.newValue.subscribe(
|
|
86
|
-
|
|
87
|
-
target.transactionMeta === null
|
|
88
|
-
? `main`
|
|
89
|
-
: target.transactionMeta.update.key
|
|
90
|
-
}`,
|
|
84
|
+
subscriptionKey,
|
|
91
85
|
(update) => {
|
|
92
86
|
if (target.operation.open) {
|
|
93
87
|
const unsubscribe = target.on.operationClose.subscribe(
|
|
94
|
-
|
|
88
|
+
subscriptionKey,
|
|
95
89
|
() => {
|
|
96
90
|
unsubscribe()
|
|
97
91
|
setState(latestUpdateState, update, target)
|
|
@@ -105,24 +99,28 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
105
99
|
)
|
|
106
100
|
}
|
|
107
101
|
},
|
|
108
|
-
|
|
109
|
-
|
|
102
|
+
subscriptionKey,
|
|
103
|
+
target,
|
|
110
104
|
)
|
|
111
105
|
}
|
|
112
106
|
|
|
113
107
|
private updateCore<Core extends Transceiver<any>>(
|
|
114
108
|
mutableState: MutableAtomToken<Core, Json.Serializable>,
|
|
115
109
|
latestUpdateState: RegularAtomToken<typeof this.Update | null>,
|
|
116
|
-
|
|
110
|
+
target: Store,
|
|
117
111
|
): void {
|
|
112
|
+
const subscriptionKey = `tracker:${target.config.name}:${
|
|
113
|
+
isChildStore(target) ? target.transactionMeta.update.key : `main`
|
|
114
|
+
}:${mutableState.key}`
|
|
118
115
|
subscribeToState(
|
|
119
116
|
latestUpdateState,
|
|
120
117
|
({ newValue, oldValue }) => {
|
|
121
|
-
const timelineId =
|
|
118
|
+
const timelineId = target.timelineAtoms.getRelatedKey(
|
|
122
119
|
latestUpdateState.key,
|
|
123
120
|
)
|
|
121
|
+
|
|
124
122
|
if (timelineId) {
|
|
125
|
-
const timelineData =
|
|
123
|
+
const timelineData = target.timelines.get(timelineId)
|
|
126
124
|
if (timelineData?.timeTraveling) {
|
|
127
125
|
const unsubscribe = subscribeToTimeline(
|
|
128
126
|
{ key: timelineId, type: `timeline` },
|
|
@@ -138,38 +136,45 @@ export class Tracker<Mutable extends Transceiver<any>> {
|
|
|
138
136
|
}
|
|
139
137
|
return transceiver
|
|
140
138
|
},
|
|
141
|
-
|
|
139
|
+
target,
|
|
142
140
|
)
|
|
143
141
|
},
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
subscriptionKey,
|
|
143
|
+
target,
|
|
146
144
|
)
|
|
147
145
|
return
|
|
148
146
|
}
|
|
149
147
|
}
|
|
150
148
|
|
|
151
|
-
const unsubscribe =
|
|
152
|
-
|
|
149
|
+
const unsubscribe = target.on.operationClose.subscribe(
|
|
150
|
+
subscriptionKey,
|
|
153
151
|
() => {
|
|
154
152
|
unsubscribe()
|
|
155
|
-
const mutable = getState(mutableState,
|
|
156
|
-
// debugger
|
|
153
|
+
const mutable = getState(mutableState, target)
|
|
157
154
|
const updateNumber =
|
|
158
155
|
newValue === null ? -1 : mutable.getUpdateNumber(newValue)
|
|
159
156
|
const eventOffset = updateNumber - mutable.cacheUpdateNumber
|
|
160
157
|
if (newValue && eventOffset === 1) {
|
|
161
|
-
// ❗ new:"0=add:\"myHand\"",old:"0=add:\"deckId\""
|
|
162
158
|
setState(
|
|
163
159
|
mutableState,
|
|
164
160
|
(transceiver) => (transceiver.do(newValue), transceiver),
|
|
165
|
-
|
|
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}`,
|
|
166
171
|
)
|
|
167
172
|
}
|
|
168
173
|
},
|
|
169
174
|
)
|
|
170
175
|
},
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
subscriptionKey,
|
|
177
|
+
target,
|
|
173
178
|
)
|
|
174
179
|
}
|
|
175
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,14 +28,30 @@ 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
|
-
} else if (target.
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
} else if (target.parent) {
|
|
34
|
+
if (target.on.transactionApplying.state === null) {
|
|
35
|
+
stowUpdate(atom, update, target)
|
|
36
|
+
} else if (atom.key.startsWith(`*`)) {
|
|
35
37
|
const mutableKey = atom.key.slice(1)
|
|
36
|
-
const
|
|
37
|
-
mutable.
|
|
38
|
+
const mutableAtom = target.atoms.get(mutableKey) as Atom<any>
|
|
39
|
+
let mutable: Transceiver<any> = target.valueMap.get(mutableKey)
|
|
40
|
+
mutable = copyMutableIfWithinTransaction(mutable, mutableAtom, target)
|
|
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
|
+
}
|
|
38
55
|
}
|
|
39
56
|
}
|
|
40
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,
|
|
@@ -52,11 +55,14 @@ export const buildTransaction = (
|
|
|
52
55
|
transactors: {
|
|
53
56
|
get: (token) => getState(token, child),
|
|
54
57
|
set: (token, value) => setState(token, value, child),
|
|
55
|
-
run: (token) => runTransaction(token, child),
|
|
58
|
+
run: (token, id) => runTransaction(token, id, child),
|
|
56
59
|
find: ((token, key) => findInStore(token, key, child)) as typeof findState,
|
|
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
|
+
}
|