atom.io 0.17.0 → 0.18.1

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