atom.io 0.30.2 → 0.30.4
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/package.json +22 -22
- package/react-devtools/dist/index.js +1 -1
- package/react-devtools/src/AtomIODevtools.tsx +1 -1
- package/react-devtools/src/elastic-input/NumberInput.tsx +0 -1
- package/react-devtools/src/elastic-input/TextInput.tsx +0 -1
- package/realtime/dist/index.d.ts +2 -1
- package/realtime/src/realtime-continuity.ts +3 -2
- package/realtime-server/dist/index.d.ts +9 -8
- package/realtime-server/dist/index.js +282 -237
- package/realtime-server/src/continuity/prepare-to-send-initial-payload.ts +54 -0
- package/realtime-server/src/continuity/prepare-to-serve-transaction-request.ts +53 -0
- package/realtime-server/src/continuity/prepare-to-sync-realtime-continuity.ts +145 -0
- package/realtime-server/src/continuity/prepare-to-track-client-acknowledgement.ts +38 -0
- package/realtime-server/src/continuity/subscribe-to-continuity-actions.ts +106 -0
- package/realtime-server/src/continuity/subscribe-to-continuity-perpectives.ts +60 -0
- package/realtime-server/src/index.ts +1 -1
- package/realtime-server/src/ipc-sockets/child-socket.ts +1 -1
- package/realtime-server/src/ipc-sockets/parent-socket.ts +1 -1
- package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +1 -1
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +11 -5
- package/realtime-server/src/realtime-continuity-synchronizer.ts +0 -343
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { TransactionUpdate } from "atom.io"
|
|
2
|
+
import type { Store } from "atom.io/internal"
|
|
3
|
+
import { actUponStore } from "atom.io/internal"
|
|
4
|
+
import type { JsonIO } from "atom.io/json"
|
|
5
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
6
|
+
|
|
7
|
+
export function prepareToServeTransactionRequest(
|
|
8
|
+
store: Store,
|
|
9
|
+
continuity: ContinuityToken,
|
|
10
|
+
userKey: string,
|
|
11
|
+
): (update: Pick<TransactionUpdate<JsonIO>, `id` | `key` | `params`>) => void {
|
|
12
|
+
const continuityKey = continuity.key
|
|
13
|
+
return function serveTransactionRequest(update) {
|
|
14
|
+
store.logger.info(`🛎️`, `continuity`, continuityKey, `received`, update)
|
|
15
|
+
const transactionKey = update.key
|
|
16
|
+
const updateId = update.id
|
|
17
|
+
const performanceKey = `tx-run:${transactionKey}:${updateId}`
|
|
18
|
+
const performanceKeyStart = `${performanceKey}:start`
|
|
19
|
+
const performanceKeyEnd = `${performanceKey}:end`
|
|
20
|
+
performance.mark(performanceKeyStart)
|
|
21
|
+
try {
|
|
22
|
+
actUponStore(
|
|
23
|
+
{ type: `transaction`, key: transactionKey },
|
|
24
|
+
updateId,
|
|
25
|
+
store,
|
|
26
|
+
)(...update.params)
|
|
27
|
+
} catch (thrown) {
|
|
28
|
+
if (thrown instanceof Error) {
|
|
29
|
+
store.logger.error(
|
|
30
|
+
`❌`,
|
|
31
|
+
`continuity`,
|
|
32
|
+
continuityKey,
|
|
33
|
+
`failed to run transaction ${transactionKey} from ${userKey} with update ${updateId}`,
|
|
34
|
+
thrown.message,
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
performance.mark(performanceKeyEnd)
|
|
39
|
+
const metric = performance.measure(
|
|
40
|
+
performanceKey,
|
|
41
|
+
performanceKeyStart,
|
|
42
|
+
performanceKeyEnd,
|
|
43
|
+
)
|
|
44
|
+
store?.logger.info(
|
|
45
|
+
`🚀`,
|
|
46
|
+
`transaction`,
|
|
47
|
+
transactionKey,
|
|
48
|
+
updateId,
|
|
49
|
+
userKey,
|
|
50
|
+
metric.duration,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { findRelationsInStore } from "atom.io/data"
|
|
2
|
+
import {
|
|
3
|
+
findInStore,
|
|
4
|
+
getFromStore,
|
|
5
|
+
IMPLICIT,
|
|
6
|
+
subscribeToState,
|
|
7
|
+
} from "atom.io/internal"
|
|
8
|
+
import type { Json } from "atom.io/json"
|
|
9
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
10
|
+
|
|
11
|
+
import type { ServerConfig, Socket } from ".."
|
|
12
|
+
import { socketAtoms, usersOfSockets } from ".."
|
|
13
|
+
import { userUnacknowledgedQueues } from "../realtime-server-stores"
|
|
14
|
+
import { prepareToSendInitialPayload } from "./prepare-to-send-initial-payload"
|
|
15
|
+
import { prepareToServeTransactionRequest } from "./prepare-to-serve-transaction-request"
|
|
16
|
+
import { prepareToTrackClientAcknowledgement } from "./prepare-to-track-client-acknowledgement"
|
|
17
|
+
import { subscribeToContinuityActions } from "./subscribe-to-continuity-actions"
|
|
18
|
+
import { subscribeToContinuityPerspectives } from "./subscribe-to-continuity-perpectives"
|
|
19
|
+
|
|
20
|
+
export type ExposeRealtimeContinuity = (
|
|
21
|
+
continuity: ContinuityToken,
|
|
22
|
+
) => () => void
|
|
23
|
+
export function prepareToExposeRealtimeContinuity({
|
|
24
|
+
socket: initialSocket,
|
|
25
|
+
store = IMPLICIT.STORE,
|
|
26
|
+
}: ServerConfig): ExposeRealtimeContinuity {
|
|
27
|
+
return function syncRealtimeContinuity(continuity) {
|
|
28
|
+
let socket: Socket | null = initialSocket
|
|
29
|
+
|
|
30
|
+
const continuityKey = continuity.key
|
|
31
|
+
const userKeyState = findRelationsInStore(
|
|
32
|
+
usersOfSockets,
|
|
33
|
+
`socket::${socket.id}`,
|
|
34
|
+
store,
|
|
35
|
+
).userKeyOfSocket
|
|
36
|
+
const userKey = getFromStore(store, userKeyState)
|
|
37
|
+
if (!userKey) {
|
|
38
|
+
store.logger.error(
|
|
39
|
+
`❌`,
|
|
40
|
+
`continuity`,
|
|
41
|
+
continuityKey,
|
|
42
|
+
`Tried to create a synchronizer for a socket (${socket.id}) that is not connected to a user.`,
|
|
43
|
+
)
|
|
44
|
+
return () => {}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const socketKeyState = findRelationsInStore(
|
|
48
|
+
usersOfSockets,
|
|
49
|
+
userKey,
|
|
50
|
+
store,
|
|
51
|
+
).socketKeyOfUser
|
|
52
|
+
const unsubscribeFromSocketTracking = subscribeToState(
|
|
53
|
+
socketKeyState,
|
|
54
|
+
({ newValue: newSocketKey }) => {
|
|
55
|
+
store.logger.info(
|
|
56
|
+
`👋`,
|
|
57
|
+
`continuity`,
|
|
58
|
+
continuityKey,
|
|
59
|
+
`seeing ${userKey} on new socket ${newSocketKey}`,
|
|
60
|
+
)
|
|
61
|
+
if (newSocketKey === null) {
|
|
62
|
+
store.logger.warn(
|
|
63
|
+
`❌`,
|
|
64
|
+
`continuity`,
|
|
65
|
+
continuityKey,
|
|
66
|
+
`User (${userKey}) is not connected to a socket, waiting for them to reappear.`,
|
|
67
|
+
)
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
const newSocketState = findInStore(store, socketAtoms, newSocketKey)
|
|
71
|
+
const newSocket = getFromStore(store, newSocketState)
|
|
72
|
+
socket = newSocket
|
|
73
|
+
for (const unacknowledgedUpdate of userUnacknowledgedUpdates) {
|
|
74
|
+
socket?.emit(
|
|
75
|
+
`tx-new:${continuityKey}`,
|
|
76
|
+
unacknowledgedUpdate as Json.Serializable,
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
`sync-continuity:${continuityKey}:${userKey}`,
|
|
81
|
+
store,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
const userUnacknowledgedUpdates = getFromStore(
|
|
85
|
+
store,
|
|
86
|
+
userUnacknowledgedQueues,
|
|
87
|
+
userKey,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
const unsubscribeFunctions: (() => void)[] = []
|
|
91
|
+
|
|
92
|
+
const unsubscribeFromPerspectives = subscribeToContinuityPerspectives(
|
|
93
|
+
store,
|
|
94
|
+
continuity,
|
|
95
|
+
userKey,
|
|
96
|
+
socket,
|
|
97
|
+
)
|
|
98
|
+
const unsubscribeFromTransactions = subscribeToContinuityActions(
|
|
99
|
+
store,
|
|
100
|
+
continuity,
|
|
101
|
+
userKey,
|
|
102
|
+
socket,
|
|
103
|
+
)
|
|
104
|
+
unsubscribeFunctions.push(
|
|
105
|
+
...unsubscribeFromPerspectives,
|
|
106
|
+
...unsubscribeFromTransactions,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
const sendInitialPayload = prepareToSendInitialPayload(
|
|
110
|
+
store,
|
|
111
|
+
continuity,
|
|
112
|
+
userKey,
|
|
113
|
+
initialSocket,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
socket.off(`get:${continuityKey}`, sendInitialPayload)
|
|
117
|
+
socket.on(`get:${continuityKey}`, sendInitialPayload)
|
|
118
|
+
|
|
119
|
+
const fillTransactionRequest = prepareToServeTransactionRequest(
|
|
120
|
+
store,
|
|
121
|
+
continuity,
|
|
122
|
+
userKey,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
socket.off(`tx-run:${continuityKey}`, fillTransactionRequest)
|
|
126
|
+
socket.on(`tx-run:${continuityKey}`, fillTransactionRequest)
|
|
127
|
+
|
|
128
|
+
const trackClientAcknowledgement = prepareToTrackClientAcknowledgement(
|
|
129
|
+
store,
|
|
130
|
+
continuity,
|
|
131
|
+
userKey,
|
|
132
|
+
userUnacknowledgedUpdates,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
socket?.on(`ack:${continuityKey}`, trackClientAcknowledgement)
|
|
136
|
+
|
|
137
|
+
return () => {
|
|
138
|
+
// clearInterval(retryTimeout)
|
|
139
|
+
for (const unsubscribe of unsubscribeFunctions) unsubscribe()
|
|
140
|
+
socket?.off(`ack:${continuityKey}`, trackClientAcknowledgement)
|
|
141
|
+
socket?.off(`get:${continuityKey}`, sendInitialPayload)
|
|
142
|
+
socket?.off(`tx-run:${continuityKey}`, fillTransactionRequest)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Store } from "atom.io/internal"
|
|
2
|
+
import { setIntoStore } from "atom.io/internal"
|
|
3
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
4
|
+
|
|
5
|
+
import type { ContinuitySyncTransactionUpdate } from "../realtime-server-stores"
|
|
6
|
+
import { userUnacknowledgedQueues } from "../realtime-server-stores"
|
|
7
|
+
|
|
8
|
+
export function prepareToTrackClientAcknowledgement(
|
|
9
|
+
store: Store,
|
|
10
|
+
continuity: ContinuityToken,
|
|
11
|
+
userKey: string,
|
|
12
|
+
userUnacknowledgedUpdates: ContinuitySyncTransactionUpdate[],
|
|
13
|
+
): (epoch: number) => void {
|
|
14
|
+
const continuityKey = continuity.key
|
|
15
|
+
return function trackClientAcknowledgement(epoch) {
|
|
16
|
+
store.logger.info(
|
|
17
|
+
`👍`,
|
|
18
|
+
`continuity`,
|
|
19
|
+
continuityKey,
|
|
20
|
+
`${userKey} acknowledged epoch ${epoch}`,
|
|
21
|
+
)
|
|
22
|
+
const isUnacknowledged = userUnacknowledgedUpdates[0]?.epoch === epoch
|
|
23
|
+
if (isUnacknowledged) {
|
|
24
|
+
setIntoStore(store, userUnacknowledgedQueues, userKey, (updates) => {
|
|
25
|
+
updates.shift()
|
|
26
|
+
store.logger.info(
|
|
27
|
+
`👍`,
|
|
28
|
+
`continuity`,
|
|
29
|
+
continuityKey,
|
|
30
|
+
`${userKey} unacknowledged update queue now has`,
|
|
31
|
+
updates.length,
|
|
32
|
+
`items`,
|
|
33
|
+
)
|
|
34
|
+
return updates
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Store } from "atom.io/internal"
|
|
2
|
+
import {
|
|
3
|
+
findInStore,
|
|
4
|
+
getFromStore,
|
|
5
|
+
getJsonToken,
|
|
6
|
+
getUpdateToken,
|
|
7
|
+
isRootStore,
|
|
8
|
+
setIntoStore,
|
|
9
|
+
subscribeToTransaction,
|
|
10
|
+
} from "atom.io/internal"
|
|
11
|
+
import type { Json } from "atom.io/json"
|
|
12
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
13
|
+
|
|
14
|
+
import type { Socket, UserKey } from ".."
|
|
15
|
+
import {
|
|
16
|
+
redactTransactionUpdateContent,
|
|
17
|
+
userUnacknowledgedQueues,
|
|
18
|
+
} from "../realtime-server-stores"
|
|
19
|
+
|
|
20
|
+
export function subscribeToContinuityActions(
|
|
21
|
+
store: Store,
|
|
22
|
+
continuity: ContinuityToken,
|
|
23
|
+
userKey: UserKey,
|
|
24
|
+
socket: Socket | null,
|
|
25
|
+
): (() => void)[] {
|
|
26
|
+
const continuityKey = continuity.key
|
|
27
|
+
const unsubscribeFunctions: (() => void)[] = []
|
|
28
|
+
|
|
29
|
+
for (const transaction of continuity.actions) {
|
|
30
|
+
const unsubscribeFromTransaction = subscribeToTransaction(
|
|
31
|
+
transaction,
|
|
32
|
+
(update) => {
|
|
33
|
+
try {
|
|
34
|
+
const visibleKeys = continuity.globals
|
|
35
|
+
.map((atom) => {
|
|
36
|
+
if (atom.type === `atom`) {
|
|
37
|
+
return atom.key
|
|
38
|
+
}
|
|
39
|
+
return getUpdateToken(atom).key
|
|
40
|
+
})
|
|
41
|
+
.concat(
|
|
42
|
+
continuity.perspectives.flatMap((perspective) => {
|
|
43
|
+
const { viewAtoms } = perspective
|
|
44
|
+
const userPerspectiveTokenState = findInStore(
|
|
45
|
+
store,
|
|
46
|
+
viewAtoms,
|
|
47
|
+
userKey,
|
|
48
|
+
)
|
|
49
|
+
const visibleTokens = getFromStore(
|
|
50
|
+
store,
|
|
51
|
+
userPerspectiveTokenState,
|
|
52
|
+
)
|
|
53
|
+
return visibleTokens.map((token) => {
|
|
54
|
+
const key =
|
|
55
|
+
token.type === `mutable_atom` ? `*` + token.key : token.key
|
|
56
|
+
return key
|
|
57
|
+
})
|
|
58
|
+
}),
|
|
59
|
+
)
|
|
60
|
+
const redactedUpdates = redactTransactionUpdateContent(
|
|
61
|
+
visibleKeys,
|
|
62
|
+
update.updates,
|
|
63
|
+
)
|
|
64
|
+
const redactedUpdate = {
|
|
65
|
+
...update,
|
|
66
|
+
updates: redactedUpdates,
|
|
67
|
+
}
|
|
68
|
+
setIntoStore(store, userUnacknowledgedQueues, userKey, (updates) => {
|
|
69
|
+
if (redactedUpdate) {
|
|
70
|
+
updates.push(redactedUpdate)
|
|
71
|
+
updates.sort((a, b) => a.epoch - b.epoch)
|
|
72
|
+
store.logger.info(
|
|
73
|
+
`👍`,
|
|
74
|
+
`continuity`,
|
|
75
|
+
continuityKey,
|
|
76
|
+
`${userKey} unacknowledged update queue now has`,
|
|
77
|
+
updates.length,
|
|
78
|
+
`items`,
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
return updates
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
socket?.emit(
|
|
85
|
+
`tx-new:${continuityKey}`,
|
|
86
|
+
redactedUpdate as Json.Serializable,
|
|
87
|
+
)
|
|
88
|
+
} catch (thrown) {
|
|
89
|
+
if (thrown instanceof Error) {
|
|
90
|
+
store.logger.error(
|
|
91
|
+
`❌`,
|
|
92
|
+
`continuity`,
|
|
93
|
+
continuityKey,
|
|
94
|
+
`${userKey} failed to send update from transaction ${transaction.key} to ${userKey}`,
|
|
95
|
+
thrown.message,
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
`sync-continuity:${continuityKey}:${userKey}`,
|
|
101
|
+
store,
|
|
102
|
+
)
|
|
103
|
+
unsubscribeFunctions.push(unsubscribeFromTransaction)
|
|
104
|
+
}
|
|
105
|
+
return unsubscribeFunctions
|
|
106
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Store } from "atom.io/internal"
|
|
2
|
+
import {
|
|
3
|
+
findInStore,
|
|
4
|
+
getFromStore,
|
|
5
|
+
getJsonToken,
|
|
6
|
+
subscribeToState,
|
|
7
|
+
} from "atom.io/internal"
|
|
8
|
+
import type { ContinuityToken } from "atom.io/realtime"
|
|
9
|
+
|
|
10
|
+
import type { Socket } from ".."
|
|
11
|
+
import type { UserKey } from "../realtime-server-stores"
|
|
12
|
+
|
|
13
|
+
export function subscribeToContinuityPerspectives(
|
|
14
|
+
store: Store,
|
|
15
|
+
continuity: ContinuityToken,
|
|
16
|
+
userKey: UserKey,
|
|
17
|
+
socket: Socket | null,
|
|
18
|
+
): (() => void)[] {
|
|
19
|
+
const continuityKey = continuity.key
|
|
20
|
+
const unsubFns: (() => void)[] = []
|
|
21
|
+
for (const perspective of continuity.perspectives) {
|
|
22
|
+
const { viewAtoms } = perspective
|
|
23
|
+
const userViewState = findInStore(store, viewAtoms, userKey)
|
|
24
|
+
const unsubscribeFromUserView = subscribeToState(
|
|
25
|
+
userViewState,
|
|
26
|
+
({ oldValue, newValue }) => {
|
|
27
|
+
const oldKeys = oldValue.map((token) => token.key)
|
|
28
|
+
const newKeys = newValue.map((token) => token.key)
|
|
29
|
+
const concealed = oldValue.filter(
|
|
30
|
+
(token) => !newKeys.includes(token.key),
|
|
31
|
+
)
|
|
32
|
+
const revealed = newValue
|
|
33
|
+
.filter((token) => !oldKeys.includes(token.key))
|
|
34
|
+
.flatMap((token) => {
|
|
35
|
+
const resourceToken =
|
|
36
|
+
token.type === `mutable_atom` ? getJsonToken(store, token) : token
|
|
37
|
+
const resource = getFromStore(store, resourceToken)
|
|
38
|
+
return [resourceToken, resource]
|
|
39
|
+
})
|
|
40
|
+
store.logger.info(
|
|
41
|
+
`👁`,
|
|
42
|
+
`atom`,
|
|
43
|
+
perspective.resourceAtoms.key,
|
|
44
|
+
`${userKey} has a new perspective`,
|
|
45
|
+
{ oldKeys, newKeys, revealed, concealed },
|
|
46
|
+
)
|
|
47
|
+
if (revealed.length > 0) {
|
|
48
|
+
socket?.emit(`reveal:${continuityKey}`, revealed)
|
|
49
|
+
}
|
|
50
|
+
if (concealed.length > 0) {
|
|
51
|
+
socket?.emit(`conceal:${continuityKey}`, concealed)
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
`sync-continuity:${continuityKey}:${userKey}:perspective:${perspective.resourceAtoms.key}`,
|
|
55
|
+
store,
|
|
56
|
+
)
|
|
57
|
+
unsubFns.push(unsubscribeFromUserView)
|
|
58
|
+
}
|
|
59
|
+
return unsubFns
|
|
60
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Store } from "atom.io/internal"
|
|
2
2
|
import type { Json } from "atom.io/json"
|
|
3
3
|
|
|
4
|
+
export * from "./continuity/prepare-to-sync-realtime-continuity"
|
|
4
5
|
export * from "./ipc-sockets"
|
|
5
6
|
export * from "./realtime-action-receiver"
|
|
6
|
-
export * from "./realtime-continuity-synchronizer"
|
|
7
7
|
export * from "./realtime-family-provider"
|
|
8
8
|
export * from "./realtime-mutable-family-provider"
|
|
9
9
|
export * from "./realtime-mutable-provider"
|
|
@@ -30,7 +30,7 @@ export const roomSelectors = selectorFamily<
|
|
|
30
30
|
(resolve) => {
|
|
31
31
|
const room = spawn(script, options, { env: process.env })
|
|
32
32
|
const resolver = (data: Buffer) => {
|
|
33
|
-
if (data.toString() ===
|
|
33
|
+
if (data.toString() === `ALIVE`) {
|
|
34
34
|
room.stdout.off(`data`, resolver)
|
|
35
35
|
resolve(room)
|
|
36
36
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { TransactionUpdate, TransactionUpdateContent } from "atom.io"
|
|
2
2
|
import { atomFamily } from "atom.io"
|
|
3
3
|
|
|
4
|
+
import type { UserKey } from "./server-user-store"
|
|
5
|
+
|
|
4
6
|
// export const completeUpdateAtoms = atomFamily<
|
|
5
7
|
// TransactionUpdate<any> | null,
|
|
6
8
|
// string
|
|
@@ -42,13 +44,13 @@ export function redactTransactionUpdateContent(
|
|
|
42
44
|
})
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
export const
|
|
47
|
+
export const redactorAtoms = atomFamily<
|
|
46
48
|
{
|
|
47
49
|
occlude: (updates: TransactionUpdateContent[]) => TransactionUpdateContent[]
|
|
48
50
|
},
|
|
49
|
-
|
|
51
|
+
UserKey
|
|
50
52
|
>({
|
|
51
|
-
key: `
|
|
53
|
+
key: `redactor`,
|
|
52
54
|
default: { occlude: (updates) => updates },
|
|
53
55
|
})
|
|
54
56
|
// export const redactedUpdateSelectors = selectorFamily<
|
|
@@ -69,9 +71,13 @@ export const actionOcclusionAtoms = atomFamily<
|
|
|
69
71
|
// },
|
|
70
72
|
// })
|
|
71
73
|
|
|
74
|
+
export type ContinuitySyncTransactionUpdate = Pick<
|
|
75
|
+
TransactionUpdate<any>,
|
|
76
|
+
`epoch` | `id` | `key` | `output` | `updates`
|
|
77
|
+
>
|
|
72
78
|
export const userUnacknowledgedQueues = atomFamily<
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
ContinuitySyncTransactionUpdate[],
|
|
80
|
+
UserKey
|
|
75
81
|
>({
|
|
76
82
|
key: `unacknowledgedUpdates`,
|
|
77
83
|
default: () => [],
|