atom.io 0.16.3 → 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.
Files changed (162) 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-OEVFAUPE.js +289 -0
  10. package/dist/chunk-OEVFAUPE.js.map +1 -0
  11. package/dist/index.cjs +36 -57
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts +64 -53
  14. package/dist/index.js +15 -36
  15. package/dist/index.js.map +1 -1
  16. package/internal/dist/index.cjs +211 -81
  17. package/internal/dist/index.cjs.map +1 -1
  18. package/internal/dist/index.d.ts +100 -72
  19. package/internal/dist/index.js +200 -75
  20. package/internal/dist/index.js.map +1 -1
  21. package/internal/src/arbitrary.ts +3 -0
  22. package/internal/src/atom/create-regular-atom.ts +2 -3
  23. package/internal/src/caching.ts +8 -6
  24. package/internal/src/families/find-in-store.ts +16 -0
  25. package/internal/src/get-environment-data.ts +4 -7
  26. package/internal/src/get-state/get-from-store.ts +14 -0
  27. package/internal/src/get-state/index.ts +2 -0
  28. package/internal/src/{read-or-compute-value.ts → get-state/read-or-compute-value.ts} +3 -3
  29. package/internal/src/index.ts +7 -6
  30. package/internal/src/ingest-updates/ingest-atom-update.ts +2 -2
  31. package/internal/src/ingest-updates/ingest-transaction-update.ts +0 -1
  32. package/internal/src/mutable/create-mutable-atom.ts +3 -4
  33. package/internal/src/mutable/tracker.ts +18 -13
  34. package/internal/src/selector/create-standalone-selector.ts +0 -2
  35. package/internal/src/selector/register-selector.ts +1 -1
  36. package/internal/src/set-state/index.ts +1 -0
  37. package/internal/src/set-state/set-atom.ts +15 -19
  38. package/internal/src/set-state/set-into-store.ts +24 -0
  39. package/internal/src/store/store.ts +14 -2
  40. package/internal/src/store/withdraw.ts +72 -2
  41. package/internal/src/subscribe/subscribe-to-root-atoms.ts +1 -1
  42. package/internal/src/subscribe/subscribe-to-timeline.ts +2 -2
  43. package/internal/src/subscribe/subscribe-to-transaction.ts +2 -2
  44. package/internal/src/timeline/create-timeline.ts +12 -1
  45. package/internal/src/transaction/act-upon-store.ts +19 -0
  46. package/internal/src/transaction/apply-transaction.ts +7 -1
  47. package/internal/src/transaction/assign-transaction-to-continuity.ts +18 -0
  48. package/internal/src/transaction/build-transaction.ts +11 -8
  49. package/internal/src/transaction/create-transaction.ts +1 -1
  50. package/internal/src/transaction/get-epoch-number.ts +40 -0
  51. package/internal/src/transaction/index.ts +10 -1
  52. package/internal/src/transaction/set-epoch-number.ts +31 -0
  53. package/introspection/dist/index.cjs.map +1 -1
  54. package/introspection/dist/index.d.ts +3 -3
  55. package/introspection/dist/index.js.map +1 -1
  56. package/introspection/src/attach-introspection-states.ts +6 -2
  57. package/introspection/src/attach-timeline-family.ts +5 -2
  58. package/introspection/src/attach-transaction-logs.ts +2 -2
  59. package/json/dist/index.d.ts +3 -1
  60. package/json/src/index.ts +6 -2
  61. package/package.json +24 -13
  62. package/react/dist/index.cjs +3 -3
  63. package/react/dist/index.cjs.map +1 -1
  64. package/react/dist/index.d.ts +1 -1
  65. package/react/dist/index.js +5 -5
  66. package/react/dist/index.js.map +1 -1
  67. package/react/src/use-i.ts +2 -3
  68. package/react/src/use-json.ts +1 -1
  69. package/react/src/use-o.ts +3 -4
  70. package/react-devtools/dist/index.cjs +131 -134
  71. package/react-devtools/dist/index.cjs.map +1 -1
  72. package/react-devtools/dist/index.css +2 -2
  73. package/react-devtools/dist/index.css.map +1 -1
  74. package/react-devtools/dist/index.d.ts +3 -3
  75. package/react-devtools/dist/index.js +103 -106
  76. package/react-devtools/dist/index.js.map +1 -1
  77. package/react-devtools/src/StateEditor.tsx +6 -6
  78. package/react-devtools/src/StateIndex.tsx +2 -5
  79. package/react-devtools/src/TimelineIndex.tsx +3 -3
  80. package/react-devtools/src/TransactionIndex.tsx +9 -8
  81. package/react-devtools/src/Updates.tsx +1 -1
  82. package/react-devtools/src/index.ts +4 -4
  83. package/realtime/dist/index.cjs +72 -0
  84. package/realtime/dist/index.cjs.map +1 -0
  85. package/realtime/dist/index.d.ts +39 -0
  86. package/realtime/dist/index.js +68 -0
  87. package/realtime/dist/index.js.map +1 -0
  88. package/realtime/package.json +16 -0
  89. package/realtime/src/index.ts +1 -0
  90. package/realtime/src/realtime-continuity.ts +152 -0
  91. package/realtime-client/dist/index.cjs +403 -59
  92. package/realtime-client/dist/index.cjs.map +1 -1
  93. package/realtime-client/dist/index.d.ts +16 -9
  94. package/realtime-client/dist/index.js +114 -48
  95. package/realtime-client/dist/index.js.map +1 -1
  96. package/realtime-client/src/index.ts +8 -5
  97. package/realtime-client/src/{pull-family-member.ts → pull-atom-family-member.ts} +5 -5
  98. package/realtime-client/src/{pull-state.ts → pull-atom.ts} +5 -5
  99. package/realtime-client/src/{pull-mutable-family-member.ts → pull-mutable-atom-family-member.ts} +5 -5
  100. package/realtime-client/src/{pull-mutable.ts → pull-mutable-atom.ts} +5 -5
  101. package/realtime-client/src/pull-selector-family-member.ts +42 -0
  102. package/realtime-client/src/pull-selector.ts +38 -0
  103. package/realtime-client/src/realtime-client-stores/client-main-store.ts +2 -2
  104. package/realtime-client/src/realtime-client-stores/client-sync-store.ts +7 -7
  105. package/realtime-client/src/sync-continuity.ts +321 -0
  106. package/realtime-client/src/sync-server-action.ts +22 -21
  107. package/realtime-client/src/sync-state.ts +3 -3
  108. package/realtime-react/dist/index.cjs +330 -15
  109. package/realtime-react/dist/index.cjs.map +1 -1
  110. package/realtime-react/dist/index.d.ts +26 -6
  111. package/realtime-react/dist/index.js +43 -12
  112. package/realtime-react/dist/index.js.map +1 -1
  113. package/realtime-react/src/index.ts +6 -3
  114. package/realtime-react/src/use-pull-atom-family-member.ts +21 -0
  115. package/realtime-react/src/{use-pull.ts → use-pull-atom.ts} +6 -5
  116. package/realtime-react/src/{use-pull-mutable.ts → use-pull-mutable-atom.ts} +4 -3
  117. package/realtime-react/src/use-pull-mutable-family-member.ts +9 -4
  118. package/realtime-react/src/use-pull-selector-family-member.ts +21 -0
  119. package/realtime-react/src/{use-pull-family-member.ts → use-pull-selector.ts} +7 -5
  120. package/realtime-react/src/use-push.ts +3 -2
  121. package/realtime-react/src/use-server-action.ts +3 -2
  122. package/realtime-react/src/use-sync-continuity.ts +12 -0
  123. package/realtime-react/src/use-sync-server-action.ts +3 -2
  124. package/realtime-server/dist/index.cjs +582 -256
  125. package/realtime-server/dist/index.cjs.map +1 -1
  126. package/realtime-server/dist/index.d.ts +124 -49
  127. package/realtime-server/dist/index.js +566 -249
  128. package/realtime-server/dist/index.js.map +1 -1
  129. package/realtime-server/src/index.ts +18 -2
  130. package/realtime-server/src/ipc-socket.ts +230 -0
  131. package/realtime-server/src/realtime-action-receiver.ts +8 -5
  132. package/realtime-server/src/realtime-action-synchronizer.ts +53 -35
  133. package/realtime-server/src/realtime-continuity-synchronizer.ts +247 -0
  134. package/realtime-server/src/realtime-family-provider.ts +37 -73
  135. package/realtime-server/src/realtime-mutable-family-provider.ts +26 -87
  136. package/realtime-server/src/realtime-mutable-provider.ts +3 -2
  137. package/realtime-server/src/realtime-server-stores/index.ts +3 -1
  138. package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +90 -0
  139. package/realtime-server/src/realtime-server-stores/server-room-store.ts +97 -0
  140. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +2 -72
  141. package/realtime-server/src/realtime-server-stores/server-user-store.ts +14 -29
  142. package/realtime-server/src/realtime-state-provider.ts +3 -3
  143. package/realtime-server/src/realtime-state-receiver.ts +2 -3
  144. package/realtime-server/src/realtime-state-synchronizer.ts +3 -3
  145. package/realtime-testing/dist/index.cjs +28 -28
  146. package/realtime-testing/dist/index.cjs.map +1 -1
  147. package/realtime-testing/dist/index.js +28 -27
  148. package/realtime-testing/dist/index.js.map +1 -1
  149. package/realtime-testing/src/setup-realtime-test.tsx +38 -28
  150. package/src/atom.ts +49 -31
  151. package/src/get-state.ts +2 -11
  152. package/src/logger.ts +10 -5
  153. package/src/selector.ts +44 -25
  154. package/src/set-state.ts +1 -13
  155. package/src/silo.ts +7 -3
  156. package/src/subscribe.ts +2 -1
  157. package/src/timeline.ts +4 -4
  158. package/src/transaction.ts +13 -17
  159. package/src/validators.ts +15 -9
  160. package/dist/chunk-H4Q5FTPZ.js +0 -11
  161. package/dist/chunk-H4Q5FTPZ.js.map +0 -1
  162. package/internal/src/set-state/copy-mutable-in-transaction.ts +0 -19
@@ -1,15 +1,15 @@
1
- import * as AtomIO from "atom.io"
2
- import type { Store } from "atom.io/internal"
1
+ import type * as AtomIO from "atom.io"
2
+ import { type Store, setIntoStore } from "atom.io/internal"
3
3
  import type { Json } from "atom.io/json"
4
4
  import type { Socket } from "socket.io-client"
5
5
 
6
- export function pullState<J extends Json.Serializable>(
7
- token: AtomIO.WritableToken<J>,
6
+ export function pullAtom<J extends Json.Serializable>(
7
+ token: AtomIO.RegularAtomToken<J>,
8
8
  socket: Socket,
9
9
  store: Store,
10
10
  ): () => void {
11
11
  const setServedValue = (data: J) => {
12
- AtomIO.setState(token, data, store)
12
+ setIntoStore(token, data, store)
13
13
  }
14
14
  socket.on(`serve:${token.key}`, setServedValue)
15
15
  socket.emit(`sub:${token.key}`)
@@ -1,11 +1,11 @@
1
- import * as AtomIO from "atom.io"
2
- import { getJsonToken, getUpdateToken } from "atom.io/internal"
1
+ import type * as AtomIO from "atom.io"
2
+ import { getJsonToken, getUpdateToken, setIntoStore } from "atom.io/internal"
3
3
  import type { Store, Transceiver } from "atom.io/internal"
4
4
  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
  >(
@@ -21,13 +21,13 @@ export function pullMutableFamilyMember<
21
21
  const subKey = parseJson(serializedSubKey)
22
22
  socket?.on(`init:${token.key}`, (data: J) => {
23
23
  const jsonToken = getJsonToken(token)
24
- AtomIO.setState(jsonToken, data, store)
24
+ setIntoStore(jsonToken, data, store)
25
25
  })
26
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
- AtomIO.setState(trackerToken, data, store)
30
+ setIntoStore(trackerToken, data, store)
31
31
  },
32
32
  )
33
33
  socket?.emit(`sub:${familyKey}`, subKey)
@@ -1,10 +1,10 @@
1
- import * as AtomIO from "atom.io"
1
+ import type * as AtomIO from "atom.io"
2
2
  import type { Store, Transceiver } from "atom.io/internal"
3
- import { getJsonToken, getUpdateToken } from "atom.io/internal"
3
+ 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
  >(
@@ -15,12 +15,12 @@ export function pullMutableState<
15
15
  const jsonToken = getJsonToken(token)
16
16
  const updateToken = getUpdateToken(token)
17
17
  socket.on(`init:${token.key}`, (data: J) => {
18
- AtomIO.setState(jsonToken, data, store)
18
+ setIntoStore(jsonToken, data, store)
19
19
  })
20
20
  socket.on(
21
21
  `next:${token.key}`,
22
22
  (data: T extends Transceiver<infer Update> ? Update : never) => {
23
- AtomIO.setState(updateToken, data, store)
23
+ setIntoStore(updateToken, data, store)
24
24
  },
25
25
  )
26
26
  socket.emit(`sub:${token.key}`)
@@ -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,10 @@
1
1
  import * as AtomIO from "atom.io"
2
2
 
3
3
  export const myIdState__INTERNAL = AtomIO.atom<string | undefined>({
4
- key: `myId__INTERNAL`,
4
+ key: `mySocketId__INTERNAL`,
5
5
  default: undefined,
6
6
  })
7
7
  export const myIdState = AtomIO.selector<string | undefined>({
8
- key: `myId`,
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 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,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
- confirmedUpdateQueueState,
8
- optimisticUpdateQueueState,
6
+ confirmedUpdateQueue,
7
+ optimisticUpdateQueue,
9
8
  } from "./realtime-client-stores"
10
9
 
11
10
  export function syncAction<ƒ extends AtomIO.ƒn>(
@@ -13,8 +12,10 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
13
12
  socket: Socket,
14
13
  store: Internal.Store,
15
14
  ): () => void {
16
- const optimisticQueue = AtomIO.getState(optimisticUpdateQueueState, store)
17
- const confirmedQueue = AtomIO.getState(confirmedUpdateQueueState, store)
15
+ Internal.assignTransactionToContinuity(`default`, token.key, store)
16
+
17
+ const optimisticQueue = Internal.getFromStore(optimisticUpdateQueue, store)
18
+ const confirmedQueue = Internal.getFromStore(confirmedUpdateQueue, store)
18
19
 
19
20
  const unsubscribeFromLocalUpdates = Internal.subscribeToTransaction(
20
21
  token,
@@ -23,8 +24,8 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
23
24
  (update) => update.id === clientUpdate.id,
24
25
  )
25
26
  if (optimisticUpdateQueueIndex === -1) {
26
- AtomIO.setState(
27
- optimisticUpdateQueueState,
27
+ Internal.setIntoStore(
28
+ optimisticUpdateQueue,
28
29
  (queue) => {
29
30
  queue.push(clientUpdate)
30
31
  queue.sort((a, b) => a.epoch - b.epoch)
@@ -32,18 +33,17 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
32
33
  },
33
34
  store,
34
35
  )
35
- socket.emit(`tx-run:${token.key}`, clientUpdate)
36
36
  } else {
37
- AtomIO.setState(
38
- optimisticUpdateQueueState,
37
+ Internal.setIntoStore(
38
+ optimisticUpdateQueue,
39
39
  (queue) => {
40
40
  queue[optimisticUpdateQueueIndex] = clientUpdate
41
41
  return queue
42
42
  },
43
43
  store,
44
44
  )
45
- socket.emit(`tx-run:${token.key}`, clientUpdate)
46
45
  }
46
+ socket.emit(`tx-run:${token.key}`, clientUpdate)
47
47
  },
48
48
  `tx-run:${token.key}`,
49
49
  store,
@@ -52,8 +52,8 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
52
52
  optimisticUpdate: AtomIO.TransactionUpdate<ƒ>,
53
53
  confirmedUpdate: AtomIO.TransactionUpdate<ƒ>,
54
54
  ) => {
55
- AtomIO.setState(
56
- optimisticUpdateQueueState,
55
+ Internal.setIntoStore(
56
+ optimisticUpdateQueue,
57
57
  (queue) => {
58
58
  queue.shift()
59
59
  return queue
@@ -94,7 +94,7 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
94
94
  subsequentOptimistic,
95
95
  )
96
96
  const { id, params } = subsequentOptimistic
97
- AtomIO.runTransaction(token, id, store)(...params)
97
+ Internal.actUponStore(token, id, store)(...params)
98
98
  }
99
99
  }
100
100
 
@@ -120,8 +120,8 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
120
120
  (update) => update.epoch === confirmedUpdate.epoch,
121
121
  )
122
122
  if (hasEnqueuedOptimisticUpdate) {
123
- AtomIO.setState(
124
- confirmedUpdateQueueState,
123
+ Internal.setIntoStore(
124
+ confirmedUpdateQueue,
125
125
  (queue) => {
126
126
  queue.push(confirmedUpdate)
127
127
  queue.sort((a, b) => a.epoch - b.epoch)
@@ -132,14 +132,15 @@ export function syncAction<ƒ extends AtomIO.ƒn>(
132
132
  }
133
133
  }
134
134
  } else {
135
+ const continuityEpoch = Internal.getEpochNumberOfAction(token.key, store)
135
136
  if (
136
- isRootStore(store) &&
137
- store.transactionMeta.epoch === confirmedUpdate.epoch - 1
137
+ Internal.isRootStore(store) &&
138
+ continuityEpoch === confirmedUpdate.epoch - 1
138
139
  ) {
139
140
  Internal.ingestTransactionUpdate(`newValue`, confirmedUpdate, store)
140
141
  socket.emit(`tx-ack:${token.key}`, confirmedUpdate.epoch)
141
- store.transactionMeta.epoch = confirmedUpdate.epoch
142
- } else if (isRootStore(store)) {
142
+ Internal.setEpochNumberOfAction(token.key, confirmedUpdate.epoch, store)
143
+ } else if (Internal.isRootStore(store)) {
143
144
  store.logger.info(
144
145
  `❌`,
145
146
  `transaction`,
@@ -1,5 +1,5 @@
1
- import * as AtomIO from "atom.io"
2
- import type { Store } from "atom.io/internal"
1
+ import type * as AtomIO from "atom.io"
2
+ import { type Store, setIntoStore } from "atom.io/internal"
3
3
  import type { Json } from "atom.io/json"
4
4
  import type { Socket } from "socket.io-client"
5
5
 
@@ -9,7 +9,7 @@ export function syncState<J extends Json.Serializable>(
9
9
  store: Store,
10
10
  ): () => void {
11
11
  const setServedValue = (data: J) => {
12
- AtomIO.setState(token, data, store)
12
+ setIntoStore(token, data, store)
13
13
  }
14
14
  socket.on(`value:${token.key}`, setServedValue)
15
15
  socket.emit(`get:${token.key}`)