atom.io 0.17.0 → 0.18.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/data/dist/index.cjs +62 -40
- package/data/dist/index.cjs.map +1 -1
- package/data/dist/index.d.ts +8 -2
- package/data/dist/index.js +64 -42
- package/data/dist/index.js.map +1 -1
- package/data/src/dict.ts +8 -4
- package/data/src/join.ts +74 -33
- package/data/src/struct-family.ts +18 -17
- package/dist/chunk-OEVFAUPE.js +289 -0
- package/dist/chunk-OEVFAUPE.js.map +1 -0
- package/dist/index.cjs +4 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +62 -51
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +163 -64
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +94 -70
- package/internal/dist/index.js +155 -59
- package/internal/dist/index.js.map +1 -1
- package/internal/src/arbitrary.ts +3 -0
- package/internal/src/caching.ts +8 -6
- package/internal/src/families/find-in-store.ts +16 -0
- package/internal/src/get-environment-data.ts +4 -7
- package/internal/src/index.ts +6 -5
- package/internal/src/ingest-updates/ingest-transaction-update.ts +0 -1
- package/internal/src/selector/create-standalone-selector.ts +0 -2
- package/internal/src/set-state/set-atom.ts +14 -18
- package/internal/src/store/store.ts +14 -2
- package/internal/src/store/withdraw.ts +72 -2
- package/internal/src/subscribe/subscribe-to-timeline.ts +2 -2
- package/internal/src/subscribe/subscribe-to-transaction.ts +2 -2
- package/internal/src/timeline/create-timeline.ts +12 -1
- package/internal/src/transaction/act-upon-store.ts +19 -0
- package/internal/src/transaction/apply-transaction.ts +7 -1
- package/internal/src/transaction/assign-transaction-to-continuity.ts +18 -0
- package/internal/src/transaction/build-transaction.ts +7 -6
- package/internal/src/transaction/create-transaction.ts +1 -1
- package/internal/src/transaction/get-epoch-number.ts +40 -0
- package/internal/src/transaction/index.ts +10 -1
- package/internal/src/transaction/set-epoch-number.ts +31 -0
- package/introspection/dist/index.cjs.map +1 -1
- package/introspection/dist/index.d.ts +3 -3
- package/introspection/dist/index.js.map +1 -1
- package/introspection/src/attach-introspection-states.ts +6 -2
- package/introspection/src/attach-timeline-family.ts +5 -2
- package/introspection/src/attach-transaction-logs.ts +2 -2
- package/json/dist/index.d.ts +3 -1
- package/json/src/index.ts +6 -2
- package/package.json +24 -13
- package/react/dist/index.cjs.map +1 -1
- package/react/dist/index.d.ts +1 -1
- package/react/dist/index.js.map +1 -1
- package/react/src/use-json.ts +1 -1
- package/react-devtools/dist/index.cjs +131 -134
- package/react-devtools/dist/index.cjs.map +1 -1
- package/react-devtools/dist/index.css +2 -2
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.ts +3 -3
- package/react-devtools/dist/index.js +103 -106
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/src/StateEditor.tsx +6 -6
- package/react-devtools/src/StateIndex.tsx +2 -5
- package/react-devtools/src/TimelineIndex.tsx +3 -3
- package/react-devtools/src/TransactionIndex.tsx +9 -8
- package/react-devtools/src/Updates.tsx +1 -1
- package/react-devtools/src/index.ts +4 -4
- package/realtime/dist/index.cjs +72 -0
- package/realtime/dist/index.cjs.map +1 -0
- package/realtime/dist/index.d.ts +39 -0
- package/realtime/dist/index.js +68 -0
- package/realtime/dist/index.js.map +1 -0
- package/realtime/package.json +16 -0
- package/realtime/src/index.ts +1 -0
- package/realtime/src/realtime-continuity.ts +152 -0
- package/realtime-client/dist/index.cjs +389 -48
- package/realtime-client/dist/index.cjs.map +1 -1
- package/realtime-client/dist/index.d.ts +16 -9
- package/realtime-client/dist/index.js +100 -37
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/src/index.ts +8 -5
- package/realtime-client/src/{pull-family-member.ts → pull-atom-family-member.ts} +2 -2
- package/realtime-client/src/{pull-state.ts → pull-atom.ts} +2 -2
- package/realtime-client/src/{pull-mutable-family-member.ts → pull-mutable-atom-family-member.ts} +1 -1
- package/realtime-client/src/{pull-mutable.ts → pull-mutable-atom.ts} +1 -1
- package/realtime-client/src/pull-selector-family-member.ts +42 -0
- package/realtime-client/src/pull-selector.ts +38 -0
- package/realtime-client/src/realtime-client-stores/client-main-store.ts +2 -2
- package/realtime-client/src/realtime-client-stores/client-sync-store.ts +7 -7
- package/realtime-client/src/sync-continuity.ts +321 -0
- package/realtime-client/src/sync-server-action.ts +18 -20
- package/realtime-react/dist/index.cjs +330 -15
- package/realtime-react/dist/index.cjs.map +1 -1
- package/realtime-react/dist/index.d.ts +26 -6
- package/realtime-react/dist/index.js +43 -12
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/src/index.ts +6 -3
- package/realtime-react/src/use-pull-atom-family-member.ts +21 -0
- package/realtime-react/src/{use-pull-family-member.ts → use-pull-atom.ts} +6 -5
- package/realtime-react/src/{use-pull-mutable.ts → use-pull-mutable-atom.ts} +4 -3
- package/realtime-react/src/use-pull-mutable-family-member.ts +9 -4
- package/realtime-react/src/use-pull-selector-family-member.ts +21 -0
- package/realtime-react/src/{use-pull.ts → use-pull-selector.ts} +7 -5
- package/realtime-react/src/use-push.ts +3 -2
- package/realtime-react/src/use-server-action.ts +3 -2
- package/realtime-react/src/use-sync-continuity.ts +12 -0
- package/realtime-react/src/use-sync-server-action.ts +3 -2
- package/realtime-server/dist/index.cjs +568 -242
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +124 -49
- package/realtime-server/dist/index.js +555 -238
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +18 -2
- package/realtime-server/src/ipc-socket.ts +230 -0
- package/realtime-server/src/realtime-action-receiver.ts +8 -5
- package/realtime-server/src/realtime-action-synchronizer.ts +40 -28
- package/realtime-server/src/realtime-continuity-synchronizer.ts +247 -0
- package/realtime-server/src/realtime-family-provider.ts +30 -71
- package/realtime-server/src/realtime-mutable-family-provider.ts +24 -86
- package/realtime-server/src/realtime-server-stores/index.ts +3 -1
- package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +90 -0
- package/realtime-server/src/realtime-server-stores/server-room-store.ts +97 -0
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +2 -72
- package/realtime-server/src/realtime-server-stores/server-user-store.ts +14 -29
- package/realtime-server/src/realtime-state-receiver.ts +0 -1
- package/realtime-testing/dist/index.cjs +28 -28
- package/realtime-testing/dist/index.cjs.map +1 -1
- package/realtime-testing/dist/index.js +28 -27
- package/realtime-testing/dist/index.js.map +1 -1
- package/realtime-testing/src/setup-realtime-test.tsx +38 -28
- package/src/atom.ts +49 -31
- package/src/logger.ts +10 -5
- package/src/selector.ts +44 -25
- package/src/subscribe.ts +2 -1
- package/src/timeline.ts +4 -4
- package/src/transaction.ts +13 -17
- package/src/validators.ts +15 -9
- package/dist/chunk-H4Q5FTPZ.js +0 -11
- package/dist/chunk-H4Q5FTPZ.js.map +0 -1
- package/internal/src/set-state/copy-mutable-in-transaction.ts +0 -19
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type * as AtomIO from "atom.io"
|
|
2
|
+
import type { Store } from "atom.io/internal"
|
|
3
|
+
import type { Socket } from "socket.io-client"
|
|
4
|
+
|
|
5
|
+
import { pullAtom } from "./pull-atom"
|
|
6
|
+
import { pullMutableAtom } from "./pull-mutable-atom"
|
|
7
|
+
|
|
8
|
+
export function pullSelector<T>(
|
|
9
|
+
token: AtomIO.SelectorToken<T>,
|
|
10
|
+
socket: Socket,
|
|
11
|
+
store: Store,
|
|
12
|
+
): () => void {
|
|
13
|
+
const atomKeys = store.selectorAtoms.getRelatedKeys(token.key)
|
|
14
|
+
const unsubscribes: Array<() => void> = []
|
|
15
|
+
if (atomKeys) {
|
|
16
|
+
for (const atomKey of atomKeys) {
|
|
17
|
+
const atom = store.atoms.get(atomKey)
|
|
18
|
+
if (!atom) {
|
|
19
|
+
continue
|
|
20
|
+
}
|
|
21
|
+
switch (atom.type) {
|
|
22
|
+
case `atom`: {
|
|
23
|
+
unsubscribes.push(pullAtom(atom, socket, store))
|
|
24
|
+
break
|
|
25
|
+
}
|
|
26
|
+
case `mutable_atom`: {
|
|
27
|
+
unsubscribes.push(pullMutableAtom(atom, socket, store))
|
|
28
|
+
break
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return () => {
|
|
34
|
+
for (const unsubscribe of unsubscribes) {
|
|
35
|
+
unsubscribe()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as AtomIO from "atom.io"
|
|
2
2
|
|
|
3
3
|
export const myIdState__INTERNAL = AtomIO.atom<string | undefined>({
|
|
4
|
-
key: `
|
|
4
|
+
key: `mySocketId__INTERNAL`,
|
|
5
5
|
default: undefined,
|
|
6
6
|
})
|
|
7
7
|
export const myIdState = AtomIO.selector<string | undefined>({
|
|
8
|
-
key: `
|
|
8
|
+
key: `mySocketId`,
|
|
9
9
|
get: ({ get }) => get(myIdState__INTERNAL),
|
|
10
10
|
})
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import * as AtomIO from "atom.io"
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const optimisticUpdateQueue = AtomIO.atom<
|
|
4
4
|
AtomIO.TransactionUpdate<any>[]
|
|
5
5
|
>({
|
|
6
6
|
key: `updateQueue`,
|
|
7
7
|
default: [],
|
|
8
8
|
})
|
|
9
9
|
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export const confirmedUpdateQueue = AtomIO.atom<AtomIO.TransactionUpdate<any>[]>(
|
|
11
|
+
{
|
|
12
|
+
key: `serverConfirmedUpdateQueue`,
|
|
13
|
+
default: [],
|
|
14
|
+
},
|
|
15
|
+
)
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import type * as AtomIO from "atom.io"
|
|
2
|
+
import type { Store } from "atom.io/internal"
|
|
3
|
+
import {
|
|
4
|
+
actUponStore,
|
|
5
|
+
assignTransactionToContinuity,
|
|
6
|
+
getEpochNumberOfContinuity,
|
|
7
|
+
getFromStore,
|
|
8
|
+
ingestTransactionUpdate,
|
|
9
|
+
isRootStore,
|
|
10
|
+
setEpochNumberOfContinuity,
|
|
11
|
+
setIntoStore,
|
|
12
|
+
subscribeToTransaction,
|
|
13
|
+
} from "atom.io/internal"
|
|
14
|
+
import type { Json } from "atom.io/json"
|
|
15
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
16
|
+
import {
|
|
17
|
+
confirmedUpdateQueue,
|
|
18
|
+
optimisticUpdateQueue,
|
|
19
|
+
} from "atom.io/realtime-client"
|
|
20
|
+
import type { Socket } from "socket.io-client"
|
|
21
|
+
|
|
22
|
+
export function syncContinuity<ƒ extends AtomIO.ƒn>(
|
|
23
|
+
continuity: ContinuityToken,
|
|
24
|
+
socket: Socket,
|
|
25
|
+
store: Store,
|
|
26
|
+
): () => void {
|
|
27
|
+
const continuityKey = continuity.key
|
|
28
|
+
const optimisticUpdates = getFromStore(optimisticUpdateQueue, store)
|
|
29
|
+
const confirmedUpdates = getFromStore(confirmedUpdateQueue, store)
|
|
30
|
+
|
|
31
|
+
const initializeContinuity = (epoch: number, payload: Json.Array) => {
|
|
32
|
+
let i = 0
|
|
33
|
+
let k: any = ``
|
|
34
|
+
let v: any = null
|
|
35
|
+
for (const x of payload) {
|
|
36
|
+
if (i % 2 === 0) {
|
|
37
|
+
k = x
|
|
38
|
+
} else {
|
|
39
|
+
v = x
|
|
40
|
+
setIntoStore(k, v, store)
|
|
41
|
+
}
|
|
42
|
+
i++
|
|
43
|
+
}
|
|
44
|
+
setEpochNumberOfContinuity(continuityKey, epoch, store)
|
|
45
|
+
}
|
|
46
|
+
socket.off(`continuity-init:${continuityKey}`)
|
|
47
|
+
socket.on(`continuity-init:${continuityKey}`, initializeContinuity)
|
|
48
|
+
|
|
49
|
+
const registerAndAttemptConfirmedUpdate = (
|
|
50
|
+
confirmedUpdate: AtomIO.TransactionUpdate<ƒ>,
|
|
51
|
+
) => {
|
|
52
|
+
function reconcileEpoch(
|
|
53
|
+
optimisticUpdate: AtomIO.TransactionUpdate<any>,
|
|
54
|
+
confirmedUpdate: AtomIO.TransactionUpdate<any>,
|
|
55
|
+
): void {
|
|
56
|
+
store.logger.info(`⚖️`, `continuity`, continuityKey, `reconciling updates`)
|
|
57
|
+
setIntoStore(
|
|
58
|
+
optimisticUpdateQueue,
|
|
59
|
+
(queue) => {
|
|
60
|
+
queue.shift()
|
|
61
|
+
return queue
|
|
62
|
+
},
|
|
63
|
+
store,
|
|
64
|
+
)
|
|
65
|
+
if (optimisticUpdate.id === confirmedUpdate.id) {
|
|
66
|
+
const clientResult = JSON.stringify(optimisticUpdate.updates)
|
|
67
|
+
const serverResult = JSON.stringify(confirmedUpdate.updates)
|
|
68
|
+
if (clientResult === serverResult) {
|
|
69
|
+
store.logger.info(
|
|
70
|
+
`✅`,
|
|
71
|
+
`continuity`,
|
|
72
|
+
continuityKey,
|
|
73
|
+
`results for ${optimisticUpdate.id} match between client and server`,
|
|
74
|
+
)
|
|
75
|
+
socket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
} else {
|
|
79
|
+
// id mismatch
|
|
80
|
+
store.logger.info(
|
|
81
|
+
`❌`,
|
|
82
|
+
`continuity`,
|
|
83
|
+
continuityKey,
|
|
84
|
+
`thought update #${confirmedUpdate.epoch} was ${optimisticUpdate.key}:${optimisticUpdate.id}, but it was actually ${confirmedUpdate.key}:${confirmedUpdate.id}`,
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
const reversedOptimisticUpdates = optimisticUpdates.toReversed()
|
|
88
|
+
for (const subsequentOptimistic of reversedOptimisticUpdates) {
|
|
89
|
+
ingestTransactionUpdate(`oldValue`, subsequentOptimistic, store)
|
|
90
|
+
}
|
|
91
|
+
store.logger.info(
|
|
92
|
+
`⏪`,
|
|
93
|
+
`continuity`,
|
|
94
|
+
continuityKey,
|
|
95
|
+
`undid optimistic updates:`,
|
|
96
|
+
reversedOptimisticUpdates,
|
|
97
|
+
)
|
|
98
|
+
ingestTransactionUpdate(`oldValue`, optimisticUpdate, store)
|
|
99
|
+
store.logger.info(
|
|
100
|
+
`⏪`,
|
|
101
|
+
`continuity`,
|
|
102
|
+
continuityKey,
|
|
103
|
+
`undid zeroth optimistic update`,
|
|
104
|
+
optimisticUpdate,
|
|
105
|
+
)
|
|
106
|
+
ingestTransactionUpdate(`newValue`, confirmedUpdate, store)
|
|
107
|
+
store.logger.info(
|
|
108
|
+
`⏩`,
|
|
109
|
+
`continuity`,
|
|
110
|
+
continuityKey,
|
|
111
|
+
`applied confirmed update`,
|
|
112
|
+
confirmedUpdate,
|
|
113
|
+
)
|
|
114
|
+
socket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)
|
|
115
|
+
|
|
116
|
+
for (const subsequentOptimistic of optimisticUpdates) {
|
|
117
|
+
const token = {
|
|
118
|
+
type: `transaction`,
|
|
119
|
+
key: subsequentOptimistic.key,
|
|
120
|
+
} as const
|
|
121
|
+
const { id, params } = subsequentOptimistic
|
|
122
|
+
actUponStore(token, id, store)(...params)
|
|
123
|
+
}
|
|
124
|
+
store.logger.info(
|
|
125
|
+
`⏩`,
|
|
126
|
+
`continuity`,
|
|
127
|
+
continuityKey,
|
|
128
|
+
`reapplied subsequent optimistic updates:`,
|
|
129
|
+
optimisticUpdates,
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
store.logger.info(
|
|
134
|
+
`⚖️`,
|
|
135
|
+
`continuity`,
|
|
136
|
+
continuityKey,
|
|
137
|
+
`integrating confirmed update`,
|
|
138
|
+
{ confirmedUpdate, confirmedUpdates, optimisticUpdates },
|
|
139
|
+
)
|
|
140
|
+
const zerothOptimisticUpdate = optimisticUpdates[0]
|
|
141
|
+
if (zerothOptimisticUpdate) {
|
|
142
|
+
store.logger.info(
|
|
143
|
+
`⚖️`,
|
|
144
|
+
`continuity`,
|
|
145
|
+
continuityKey,
|
|
146
|
+
`has optimistic updates to reconcile`,
|
|
147
|
+
)
|
|
148
|
+
if (confirmedUpdate.epoch === zerothOptimisticUpdate.epoch) {
|
|
149
|
+
store.logger.info(
|
|
150
|
+
`⚖️`,
|
|
151
|
+
`continuity`,
|
|
152
|
+
continuityKey,
|
|
153
|
+
`epoch of confirmed update #${confirmedUpdate.epoch} matches zeroth optimistic update`,
|
|
154
|
+
)
|
|
155
|
+
reconcileEpoch(zerothOptimisticUpdate, confirmedUpdate)
|
|
156
|
+
for (const nextConfirmed of confirmedUpdates) {
|
|
157
|
+
const nextOptimistic = optimisticUpdates[0]
|
|
158
|
+
if (nextConfirmed.epoch === nextOptimistic?.epoch) {
|
|
159
|
+
reconcileEpoch(nextOptimistic, nextConfirmed)
|
|
160
|
+
} else {
|
|
161
|
+
break
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} else {
|
|
165
|
+
// epoch mismatch
|
|
166
|
+
store.logger.info(
|
|
167
|
+
`⚖️`,
|
|
168
|
+
`continuity`,
|
|
169
|
+
continuityKey,
|
|
170
|
+
`epoch of confirmed update #${confirmedUpdate.epoch} does not match zeroth optimistic update #${zerothOptimisticUpdate.epoch}`,
|
|
171
|
+
)
|
|
172
|
+
const confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(
|
|
173
|
+
(update) => update.epoch === confirmedUpdate.epoch,
|
|
174
|
+
)
|
|
175
|
+
if (!confirmedUpdateIsAlreadyEnqueued) {
|
|
176
|
+
store.logger.info(
|
|
177
|
+
`👈`,
|
|
178
|
+
`continuity`,
|
|
179
|
+
continuityKey,
|
|
180
|
+
`pushing confirmed update to queue`,
|
|
181
|
+
confirmedUpdate,
|
|
182
|
+
)
|
|
183
|
+
setIntoStore(
|
|
184
|
+
confirmedUpdateQueue,
|
|
185
|
+
(queue) => {
|
|
186
|
+
queue.push(confirmedUpdate)
|
|
187
|
+
queue.sort((a, b) => a.epoch - b.epoch)
|
|
188
|
+
return queue
|
|
189
|
+
},
|
|
190
|
+
store,
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
store.logger.info(
|
|
196
|
+
`⚖️`,
|
|
197
|
+
`continuity`,
|
|
198
|
+
continuityKey,
|
|
199
|
+
`has no optimistic updates to deal with`,
|
|
200
|
+
)
|
|
201
|
+
const continuityEpoch = getEpochNumberOfContinuity(continuityKey, store)
|
|
202
|
+
const isRoot = isRootStore(store)
|
|
203
|
+
|
|
204
|
+
if (isRoot && continuityEpoch === confirmedUpdate.epoch - 1) {
|
|
205
|
+
store.logger.info(
|
|
206
|
+
`✅`,
|
|
207
|
+
`continuity`,
|
|
208
|
+
continuityKey,
|
|
209
|
+
`integrating update #${confirmedUpdate.epoch} (${confirmedUpdate.key} ${confirmedUpdate.id})`,
|
|
210
|
+
)
|
|
211
|
+
ingestTransactionUpdate(`newValue`, confirmedUpdate, store)
|
|
212
|
+
socket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch)
|
|
213
|
+
setEpochNumberOfContinuity(continuityKey, confirmedUpdate.epoch, store)
|
|
214
|
+
} else if (isRoot && continuityEpoch !== undefined) {
|
|
215
|
+
store.logger.info(
|
|
216
|
+
`⚖️`,
|
|
217
|
+
`continuity`,
|
|
218
|
+
continuityKey,
|
|
219
|
+
`received update #${
|
|
220
|
+
confirmedUpdate.epoch
|
|
221
|
+
} but still waiting for update #${continuityEpoch + 1}`,
|
|
222
|
+
{
|
|
223
|
+
clientEpoch: continuityEpoch,
|
|
224
|
+
serverEpoch: confirmedUpdate.epoch,
|
|
225
|
+
},
|
|
226
|
+
)
|
|
227
|
+
const confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(
|
|
228
|
+
(update) => update.epoch === confirmedUpdate.epoch,
|
|
229
|
+
)
|
|
230
|
+
if (confirmedUpdateIsAlreadyEnqueued) {
|
|
231
|
+
store.logger.info(
|
|
232
|
+
`👍`,
|
|
233
|
+
`continuity`,
|
|
234
|
+
continuityKey,
|
|
235
|
+
`confirmed update #${confirmedUpdate.epoch} is already enqueued`,
|
|
236
|
+
)
|
|
237
|
+
} else {
|
|
238
|
+
store.logger.info(
|
|
239
|
+
`👈`,
|
|
240
|
+
`continuity`,
|
|
241
|
+
continuityKey,
|
|
242
|
+
`pushing confirmed update #${confirmedUpdate.epoch} to queue`,
|
|
243
|
+
)
|
|
244
|
+
setIntoStore(
|
|
245
|
+
confirmedUpdateQueue,
|
|
246
|
+
(queue) => {
|
|
247
|
+
queue.push(confirmedUpdate)
|
|
248
|
+
queue.sort((a, b) => a.epoch - b.epoch)
|
|
249
|
+
return queue
|
|
250
|
+
},
|
|
251
|
+
store,
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
socket.off(`tx-new:${continuityKey}`)
|
|
258
|
+
socket.on(`tx-new:${continuityKey}`, registerAndAttemptConfirmedUpdate)
|
|
259
|
+
|
|
260
|
+
const unsubscribeFunctions = continuity.actions.map((transaction) => {
|
|
261
|
+
assignTransactionToContinuity(continuityKey, transaction.key, store)
|
|
262
|
+
const unsubscribeFromTransactionUpdates = subscribeToTransaction(
|
|
263
|
+
transaction,
|
|
264
|
+
(clientUpdate) => {
|
|
265
|
+
store.logger.info(
|
|
266
|
+
`🤞`,
|
|
267
|
+
`continuity`,
|
|
268
|
+
continuityKey,
|
|
269
|
+
`enqueuing optimistic update`,
|
|
270
|
+
)
|
|
271
|
+
const optimisticUpdateIndex = optimisticUpdates.findIndex(
|
|
272
|
+
(update) => update.id === clientUpdate.id,
|
|
273
|
+
)
|
|
274
|
+
if (optimisticUpdateIndex === -1) {
|
|
275
|
+
store.logger.info(
|
|
276
|
+
`🤞`,
|
|
277
|
+
`continuity`,
|
|
278
|
+
continuityKey,
|
|
279
|
+
`enqueuing new optimistic update`,
|
|
280
|
+
)
|
|
281
|
+
setIntoStore(
|
|
282
|
+
optimisticUpdateQueue,
|
|
283
|
+
(queue) => {
|
|
284
|
+
queue.push(clientUpdate)
|
|
285
|
+
queue.sort((a, b) => a.epoch - b.epoch)
|
|
286
|
+
return queue
|
|
287
|
+
},
|
|
288
|
+
store,
|
|
289
|
+
)
|
|
290
|
+
} else {
|
|
291
|
+
store.logger.info(
|
|
292
|
+
`🤞`,
|
|
293
|
+
`continuity`,
|
|
294
|
+
continuityKey,
|
|
295
|
+
`replacing existing optimistic update at index ${optimisticUpdateIndex}`,
|
|
296
|
+
)
|
|
297
|
+
setIntoStore(
|
|
298
|
+
optimisticUpdateQueue,
|
|
299
|
+
(queue) => {
|
|
300
|
+
queue[optimisticUpdateIndex] = clientUpdate
|
|
301
|
+
return queue
|
|
302
|
+
},
|
|
303
|
+
store,
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
socket.emit(`tx-run:${continuityKey}`, clientUpdate)
|
|
307
|
+
},
|
|
308
|
+
`tx-run:${continuityKey}`,
|
|
309
|
+
store,
|
|
310
|
+
)
|
|
311
|
+
return unsubscribeFromTransactionUpdates
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
socket.emit(`get:${continuityKey}`)
|
|
315
|
+
return () => {
|
|
316
|
+
socket.off(`continuity-init:${continuityKey}`)
|
|
317
|
+
socket.off(`tx-new:${continuityKey}`)
|
|
318
|
+
for (const unsubscribe of unsubscribeFunctions) unsubscribe()
|
|
319
|
+
socket.emit(`unsub:${continuityKey}`)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import * as AtomIO from "atom.io"
|
|
1
|
+
import type * as AtomIO from "atom.io"
|
|
2
2
|
import * as Internal from "atom.io/internal"
|
|
3
3
|
import type { Socket } from "socket.io-client"
|
|
4
4
|
|
|
5
|
-
import { isRootStore } from "../../internal/src/transaction/is-root-store"
|
|
6
5
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
confirmedUpdateQueue,
|
|
7
|
+
optimisticUpdateQueue,
|
|
9
8
|
} from "./realtime-client-stores"
|
|
10
9
|
|
|
11
10
|
export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
@@ -13,11 +12,10 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
13
12
|
socket: Socket,
|
|
14
13
|
store: Internal.Store,
|
|
15
14
|
): () => void {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
)
|
|
20
|
-
const confirmedQueue = Internal.getFromStore(confirmedUpdateQueueState, store)
|
|
15
|
+
Internal.assignTransactionToContinuity(`default`, token.key, store)
|
|
16
|
+
|
|
17
|
+
const optimisticQueue = Internal.getFromStore(optimisticUpdateQueue, store)
|
|
18
|
+
const confirmedQueue = Internal.getFromStore(confirmedUpdateQueue, store)
|
|
21
19
|
|
|
22
20
|
const unsubscribeFromLocalUpdates = Internal.subscribeToTransaction(
|
|
23
21
|
token,
|
|
@@ -27,7 +25,7 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
27
25
|
)
|
|
28
26
|
if (optimisticUpdateQueueIndex === -1) {
|
|
29
27
|
Internal.setIntoStore(
|
|
30
|
-
|
|
28
|
+
optimisticUpdateQueue,
|
|
31
29
|
(queue) => {
|
|
32
30
|
queue.push(clientUpdate)
|
|
33
31
|
queue.sort((a, b) => a.epoch - b.epoch)
|
|
@@ -35,18 +33,17 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
35
33
|
},
|
|
36
34
|
store,
|
|
37
35
|
)
|
|
38
|
-
socket.emit(`tx-run:${token.key}`, clientUpdate)
|
|
39
36
|
} else {
|
|
40
37
|
Internal.setIntoStore(
|
|
41
|
-
|
|
38
|
+
optimisticUpdateQueue,
|
|
42
39
|
(queue) => {
|
|
43
40
|
queue[optimisticUpdateQueueIndex] = clientUpdate
|
|
44
41
|
return queue
|
|
45
42
|
},
|
|
46
43
|
store,
|
|
47
44
|
)
|
|
48
|
-
socket.emit(`tx-run:${token.key}`, clientUpdate)
|
|
49
45
|
}
|
|
46
|
+
socket.emit(`tx-run:${token.key}`, clientUpdate)
|
|
50
47
|
},
|
|
51
48
|
`tx-run:${token.key}`,
|
|
52
49
|
store,
|
|
@@ -56,7 +53,7 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
56
53
|
confirmedUpdate: AtomIO.TransactionUpdate<ƒ>,
|
|
57
54
|
) => {
|
|
58
55
|
Internal.setIntoStore(
|
|
59
|
-
|
|
56
|
+
optimisticUpdateQueue,
|
|
60
57
|
(queue) => {
|
|
61
58
|
queue.shift()
|
|
62
59
|
return queue
|
|
@@ -97,7 +94,7 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
97
94
|
subsequentOptimistic,
|
|
98
95
|
)
|
|
99
96
|
const { id, params } = subsequentOptimistic
|
|
100
|
-
|
|
97
|
+
Internal.actUponStore(token, id, store)(...params)
|
|
101
98
|
}
|
|
102
99
|
}
|
|
103
100
|
|
|
@@ -124,7 +121,7 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
124
121
|
)
|
|
125
122
|
if (hasEnqueuedOptimisticUpdate) {
|
|
126
123
|
Internal.setIntoStore(
|
|
127
|
-
|
|
124
|
+
confirmedUpdateQueue,
|
|
128
125
|
(queue) => {
|
|
129
126
|
queue.push(confirmedUpdate)
|
|
130
127
|
queue.sort((a, b) => a.epoch - b.epoch)
|
|
@@ -135,14 +132,15 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
|
|
|
135
132
|
}
|
|
136
133
|
}
|
|
137
134
|
} else {
|
|
135
|
+
const continuityEpoch = Internal.getEpochNumberOfAction(token.key, store)
|
|
138
136
|
if (
|
|
139
|
-
isRootStore(store) &&
|
|
140
|
-
|
|
137
|
+
Internal.isRootStore(store) &&
|
|
138
|
+
continuityEpoch === confirmedUpdate.epoch - 1
|
|
141
139
|
) {
|
|
142
140
|
Internal.ingestTransactionUpdate(`newValue`, confirmedUpdate, store)
|
|
143
141
|
socket.emit(`tx-ack:${token.key}`, confirmedUpdate.epoch)
|
|
144
|
-
|
|
145
|
-
} else if (isRootStore(store)) {
|
|
142
|
+
Internal.setEpochNumberOfAction(token.key, confirmedUpdate.epoch, store)
|
|
143
|
+
} else if (Internal.isRootStore(store)) {
|
|
146
144
|
store.logger.info(
|
|
147
145
|
`❌`,
|
|
148
146
|
`transaction`,
|