cojson 0.15.7 → 0.15.9

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 (218) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/IncomingMessagesQueue.d.ts +27 -0
  4. package/dist/IncomingMessagesQueue.d.ts.map +1 -0
  5. package/dist/IncomingMessagesQueue.js +114 -0
  6. package/dist/IncomingMessagesQueue.js.map +1 -0
  7. package/dist/PeerState.d.ts +2 -10
  8. package/dist/PeerState.d.ts.map +1 -1
  9. package/dist/PeerState.js +9 -90
  10. package/dist/PeerState.js.map +1 -1
  11. package/dist/PriorityBasedMessageQueue.d.ts +2 -1
  12. package/dist/PriorityBasedMessageQueue.d.ts.map +1 -1
  13. package/dist/PriorityBasedMessageQueue.js +9 -6
  14. package/dist/PriorityBasedMessageQueue.js.map +1 -1
  15. package/dist/SyncStateManager.d.ts +1 -0
  16. package/dist/SyncStateManager.d.ts.map +1 -1
  17. package/dist/SyncStateManager.js +1 -1
  18. package/dist/SyncStateManager.js.map +1 -1
  19. package/dist/coValue.d.ts +1 -1
  20. package/dist/coValueCore/coValueCore.d.ts +9 -17
  21. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  22. package/dist/coValueCore/coValueCore.js +75 -50
  23. package/dist/coValueCore/coValueCore.js.map +1 -1
  24. package/dist/coValueCore/verifiedState.d.ts +10 -3
  25. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  26. package/dist/coValueCore/verifiedState.js +73 -14
  27. package/dist/coValueCore/verifiedState.js.map +1 -1
  28. package/dist/coValues/coMap.d.ts +3 -3
  29. package/dist/coValues/coStream.d.ts +2 -2
  30. package/dist/coValues/group.d.ts +1 -1
  31. package/dist/coValues/group.d.ts.map +1 -1
  32. package/dist/coValues/group.js +2 -4
  33. package/dist/coValues/group.js.map +1 -1
  34. package/dist/config.d.ts +19 -0
  35. package/dist/config.d.ts.map +1 -0
  36. package/dist/config.js +23 -0
  37. package/dist/config.js.map +1 -0
  38. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  39. package/dist/crypto/WasmCrypto.js +2 -1
  40. package/dist/crypto/WasmCrypto.js.map +1 -1
  41. package/dist/exports.d.ts +18 -7
  42. package/dist/exports.d.ts.map +1 -1
  43. package/dist/exports.js +11 -8
  44. package/dist/exports.js.map +1 -1
  45. package/dist/localNode.d.ts +8 -2
  46. package/dist/localNode.d.ts.map +1 -1
  47. package/dist/localNode.js +19 -12
  48. package/dist/localNode.js.map +1 -1
  49. package/dist/storage/StoreQueue.d.ts +15 -0
  50. package/dist/storage/StoreQueue.d.ts.map +1 -0
  51. package/dist/storage/StoreQueue.js +35 -0
  52. package/dist/storage/StoreQueue.js.map +1 -0
  53. package/dist/storage/index.d.ts +6 -0
  54. package/dist/storage/index.d.ts.map +1 -0
  55. package/dist/storage/index.js +6 -0
  56. package/dist/storage/index.js.map +1 -0
  57. package/dist/storage/knownState.d.ts +18 -0
  58. package/dist/storage/knownState.d.ts.map +1 -0
  59. package/dist/storage/knownState.js +63 -0
  60. package/dist/storage/knownState.js.map +1 -0
  61. package/dist/storage/sqlite/client.d.ts +37 -0
  62. package/dist/storage/sqlite/client.d.ts.map +1 -0
  63. package/dist/storage/sqlite/client.js +89 -0
  64. package/dist/storage/sqlite/client.js.map +1 -0
  65. package/dist/storage/sqlite/index.d.ts +5 -0
  66. package/dist/storage/sqlite/index.d.ts.map +1 -0
  67. package/dist/storage/sqlite/index.js +13 -0
  68. package/dist/storage/sqlite/index.js.map +1 -0
  69. package/dist/storage/sqlite/sqliteMigrations.d.ts +3 -0
  70. package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -0
  71. package/dist/storage/sqlite/sqliteMigrations.js +44 -0
  72. package/dist/storage/sqlite/sqliteMigrations.js.map +1 -0
  73. package/dist/storage/sqlite/types.d.ts +8 -0
  74. package/dist/storage/sqlite/types.d.ts.map +1 -0
  75. package/dist/storage/sqlite/types.js +2 -0
  76. package/dist/storage/sqlite/types.js.map +1 -0
  77. package/dist/storage/sqliteAsync/client.d.ts +37 -0
  78. package/dist/storage/sqliteAsync/client.d.ts.map +1 -0
  79. package/dist/storage/sqliteAsync/client.js +88 -0
  80. package/dist/storage/sqliteAsync/client.js.map +1 -0
  81. package/dist/storage/sqliteAsync/index.d.ts +6 -0
  82. package/dist/storage/sqliteAsync/index.d.ts.map +1 -0
  83. package/dist/storage/sqliteAsync/index.js +15 -0
  84. package/dist/storage/sqliteAsync/index.js.map +1 -0
  85. package/dist/storage/sqliteAsync/types.d.ts +9 -0
  86. package/dist/storage/sqliteAsync/types.d.ts.map +1 -0
  87. package/dist/storage/sqliteAsync/types.js +2 -0
  88. package/dist/storage/sqliteAsync/types.js.map +1 -0
  89. package/dist/storage/storageAsync.d.ts +22 -0
  90. package/dist/storage/storageAsync.d.ts.map +1 -0
  91. package/dist/storage/storageAsync.js +214 -0
  92. package/dist/storage/storageAsync.js.map +1 -0
  93. package/dist/storage/storageSync.d.ts +21 -0
  94. package/dist/storage/storageSync.d.ts.map +1 -0
  95. package/dist/storage/storageSync.js +206 -0
  96. package/dist/storage/storageSync.js.map +1 -0
  97. package/dist/storage/syncUtils.d.ts +13 -0
  98. package/dist/storage/syncUtils.d.ts.map +1 -0
  99. package/dist/storage/syncUtils.js +25 -0
  100. package/dist/storage/syncUtils.js.map +1 -0
  101. package/dist/storage/types.d.ts +82 -0
  102. package/dist/storage/types.d.ts.map +1 -0
  103. package/dist/storage/types.js +2 -0
  104. package/dist/storage/types.js.map +1 -0
  105. package/dist/streamUtils.d.ts +13 -9
  106. package/dist/streamUtils.d.ts.map +1 -1
  107. package/dist/streamUtils.js +46 -13
  108. package/dist/streamUtils.js.map +1 -1
  109. package/dist/sync.d.ts +22 -14
  110. package/dist/sync.d.ts.map +1 -1
  111. package/dist/sync.js +143 -125
  112. package/dist/sync.js.map +1 -1
  113. package/dist/tests/IncomingMessagesQueue.test.d.ts +2 -0
  114. package/dist/tests/IncomingMessagesQueue.test.d.ts.map +1 -0
  115. package/dist/tests/IncomingMessagesQueue.test.js +437 -0
  116. package/dist/tests/IncomingMessagesQueue.test.js.map +1 -0
  117. package/dist/tests/PeerState.test.js +6 -94
  118. package/dist/tests/PeerState.test.js.map +1 -1
  119. package/dist/tests/PriorityBasedMessageQueue.test.js +14 -14
  120. package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -1
  121. package/dist/tests/StoreQueue.test.d.ts +2 -0
  122. package/dist/tests/StoreQueue.test.d.ts.map +1 -0
  123. package/dist/tests/StoreQueue.test.js +208 -0
  124. package/dist/tests/StoreQueue.test.js.map +1 -0
  125. package/dist/tests/SyncStateManager.test.js +3 -1
  126. package/dist/tests/SyncStateManager.test.js.map +1 -1
  127. package/dist/tests/account.test.js +9 -9
  128. package/dist/tests/account.test.js.map +1 -1
  129. package/dist/tests/coStream.test.js +1 -1
  130. package/dist/tests/coStream.test.js.map +1 -1
  131. package/dist/tests/coValueCore.test.js +208 -1
  132. package/dist/tests/coValueCore.test.js.map +1 -1
  133. package/dist/tests/coValueCoreLoadingState.test.js +2 -2
  134. package/dist/tests/coValueCoreLoadingState.test.js.map +1 -1
  135. package/dist/tests/group.addMember.test.js.map +1 -1
  136. package/dist/tests/group.removeMember.test.js +1 -1
  137. package/dist/tests/group.removeMember.test.js.map +1 -1
  138. package/dist/tests/messagesTestUtils.js +1 -1
  139. package/dist/tests/messagesTestUtils.js.map +1 -1
  140. package/dist/tests/sync.auth.test.js +23 -15
  141. package/dist/tests/sync.auth.test.js.map +1 -1
  142. package/dist/tests/sync.invite.test.js +10 -16
  143. package/dist/tests/sync.invite.test.js.map +1 -1
  144. package/dist/tests/sync.load.test.js +52 -50
  145. package/dist/tests/sync.load.test.js.map +1 -1
  146. package/dist/tests/sync.mesh.test.js +173 -56
  147. package/dist/tests/sync.mesh.test.js.map +1 -1
  148. package/dist/tests/sync.peerReconciliation.test.js +42 -32
  149. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  150. package/dist/tests/sync.storage.test.js +162 -62
  151. package/dist/tests/sync.storage.test.js.map +1 -1
  152. package/dist/tests/sync.storageAsync.test.d.ts +2 -0
  153. package/dist/tests/sync.storageAsync.test.d.ts.map +1 -0
  154. package/dist/tests/sync.storageAsync.test.js +361 -0
  155. package/dist/tests/sync.storageAsync.test.js.map +1 -0
  156. package/dist/tests/sync.test.js +16 -21
  157. package/dist/tests/sync.test.js.map +1 -1
  158. package/dist/tests/sync.upload.test.js +28 -25
  159. package/dist/tests/sync.upload.test.js.map +1 -1
  160. package/dist/tests/testStorage.d.ts +12 -0
  161. package/dist/tests/testStorage.d.ts.map +1 -0
  162. package/dist/tests/testStorage.js +151 -0
  163. package/dist/tests/testStorage.js.map +1 -0
  164. package/dist/tests/testUtils.d.ts +20 -15
  165. package/dist/tests/testUtils.d.ts.map +1 -1
  166. package/dist/tests/testUtils.js +79 -45
  167. package/dist/tests/testUtils.js.map +1 -1
  168. package/package.json +2 -2
  169. package/src/IncomingMessagesQueue.ts +142 -0
  170. package/src/PeerState.ts +11 -110
  171. package/src/PriorityBasedMessageQueue.ts +13 -5
  172. package/src/SyncStateManager.ts +1 -1
  173. package/src/coValueCore/coValueCore.ts +100 -66
  174. package/src/coValueCore/verifiedState.ts +91 -21
  175. package/src/coValues/group.ts +2 -4
  176. package/src/config.ts +26 -0
  177. package/src/crypto/WasmCrypto.ts +3 -1
  178. package/src/exports.ts +20 -27
  179. package/src/localNode.ts +27 -12
  180. package/src/storage/StoreQueue.ts +56 -0
  181. package/src/storage/index.ts +5 -0
  182. package/src/storage/knownState.ts +88 -0
  183. package/src/storage/sqlite/client.ts +180 -0
  184. package/src/storage/sqlite/index.ts +19 -0
  185. package/src/storage/sqlite/sqliteMigrations.ts +44 -0
  186. package/src/storage/sqlite/types.ts +7 -0
  187. package/src/storage/sqliteAsync/client.ts +179 -0
  188. package/src/storage/sqliteAsync/index.ts +25 -0
  189. package/src/storage/sqliteAsync/types.ts +8 -0
  190. package/src/storage/storageAsync.ts +367 -0
  191. package/src/storage/storageSync.ts +343 -0
  192. package/src/storage/syncUtils.ts +50 -0
  193. package/src/storage/types.ts +162 -0
  194. package/src/streamUtils.ts +61 -19
  195. package/src/sync.ts +191 -160
  196. package/src/tests/IncomingMessagesQueue.test.ts +626 -0
  197. package/src/tests/PeerState.test.ts +6 -118
  198. package/src/tests/PriorityBasedMessageQueue.test.ts +18 -14
  199. package/src/tests/StoreQueue.test.ts +283 -0
  200. package/src/tests/SyncStateManager.test.ts +4 -1
  201. package/src/tests/account.test.ts +11 -12
  202. package/src/tests/coStream.test.ts +1 -3
  203. package/src/tests/coValueCore.test.ts +270 -1
  204. package/src/tests/coValueCoreLoadingState.test.ts +2 -2
  205. package/src/tests/group.addMember.test.ts +1 -0
  206. package/src/tests/group.removeMember.test.ts +2 -8
  207. package/src/tests/messagesTestUtils.ts +2 -2
  208. package/src/tests/sync.auth.test.ts +24 -14
  209. package/src/tests/sync.invite.test.ts +11 -17
  210. package/src/tests/sync.load.test.ts +53 -49
  211. package/src/tests/sync.mesh.test.ts +198 -56
  212. package/src/tests/sync.peerReconciliation.test.ts +44 -34
  213. package/src/tests/sync.storage.test.ts +231 -64
  214. package/src/tests/sync.storageAsync.test.ts +486 -0
  215. package/src/tests/sync.test.ts +17 -23
  216. package/src/tests/sync.upload.test.ts +29 -24
  217. package/src/tests/testStorage.ts +216 -0
  218. package/src/tests/testUtils.ts +89 -54
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, test, vi } from "vitest";
2
2
  import { PeerState } from "../PeerState.js";
3
3
  import { CO_VALUE_PRIORITY } from "../priority.js";
4
+ import { ConnectedPeerChannel } from "../streamUtils.js";
4
5
  import { CoValueKnownState, Peer, SyncMessage } from "../sync.js";
5
6
  import { waitFor } from "./testUtils.js";
6
7
 
@@ -9,13 +10,12 @@ function setup() {
9
10
  id: "test-peer",
10
11
  role: "client",
11
12
  priority: 1,
12
- crashOnClose: false,
13
- incoming: (async function* () {})(),
14
- outgoing: {
15
- push: vi.fn().mockResolvedValue(undefined),
16
- close: vi.fn(),
17
- },
13
+ incoming: new ConnectedPeerChannel(),
14
+ outgoing: new ConnectedPeerChannel(),
18
15
  };
16
+ vi.spyOn(mockPeer.outgoing, "push");
17
+ vi.spyOn(mockPeer.incoming, "close");
18
+ vi.spyOn(mockPeer.outgoing, "close");
19
19
  const peerState = new PeerState(mockPeer, undefined);
20
20
  return { mockPeer, peerState };
21
21
  }
@@ -38,15 +38,6 @@ describe("PeerState", () => {
38
38
  expect(peerState.incoming).toBe(mockPeer.incoming);
39
39
  });
40
40
 
41
- test("should return Disconnected when closed", async () => {
42
- const { peerState } = setup();
43
- peerState.gracefulShutdown();
44
- const incomingIterator = peerState.incoming[Symbol.asyncIterator]();
45
- const { value, done } = await incomingIterator.next();
46
- expect(value).toBe("Disconnected");
47
- expect(done).toBe(false);
48
- });
49
-
50
41
  test("should perform graceful shutdown", () => {
51
42
  const { mockPeer, peerState } = setup();
52
43
  peerState.gracefulShutdown();
@@ -54,109 +45,6 @@ describe("PeerState", () => {
54
45
  expect(peerState.closed).toBe(true);
55
46
  });
56
47
 
57
- test("should empty the queue when closing", async () => {
58
- const { mockPeer, peerState } = setup();
59
-
60
- mockPeer.outgoing.push = vi.fn().mockImplementation((message) => {
61
- return new Promise<void>((resolve) => {
62
- setTimeout(resolve, 100);
63
- });
64
- });
65
-
66
- peerState.pushOutgoingMessage({
67
- action: "content",
68
- id: "co_z1",
69
- new: {},
70
- priority: CO_VALUE_PRIORITY.HIGH,
71
- });
72
- peerState.pushOutgoingMessage({
73
- action: "content",
74
- id: "co_z1",
75
- new: {},
76
- priority: CO_VALUE_PRIORITY.HIGH,
77
- });
78
- peerState.pushOutgoingMessage({
79
- action: "content",
80
- id: "co_z1",
81
- new: {},
82
- priority: CO_VALUE_PRIORITY.HIGH,
83
- });
84
-
85
- peerState.gracefulShutdown();
86
-
87
- await waitFor(() => {
88
- expect(peerState.isProcessing()).toBe(false);
89
- });
90
-
91
- expect(mockPeer.outgoing.push).toHaveBeenCalledTimes(1);
92
- });
93
-
94
- test("should schedule outgoing messages based on their priority", async () => {
95
- const { peerState, mockPeer } = setup();
96
-
97
- mockPeer.outgoing.push = vi.fn().mockImplementation((message) => {
98
- return new Promise<void>((resolve) => {
99
- setTimeout(resolve, 0);
100
- });
101
- });
102
-
103
- const loadMessage: SyncMessage = {
104
- action: "load",
105
- id: "co_zhigh",
106
- header: false,
107
- sessions: {},
108
- };
109
- const contentMessageHigh: SyncMessage = {
110
- action: "content",
111
- id: "co_zhigh",
112
- new: {},
113
- priority: CO_VALUE_PRIORITY.HIGH,
114
- };
115
- const contentMessageMid: SyncMessage = {
116
- action: "content",
117
- id: "co_zmid",
118
- new: {},
119
- priority: CO_VALUE_PRIORITY.MEDIUM,
120
- };
121
- const contentMessageLow: SyncMessage = {
122
- action: "content",
123
- id: "co_zlow",
124
- new: {},
125
- priority: CO_VALUE_PRIORITY.LOW,
126
- };
127
-
128
- peerState.pushOutgoingMessage(contentMessageLow);
129
- peerState.pushOutgoingMessage(contentMessageMid);
130
- peerState.pushOutgoingMessage(contentMessageHigh);
131
- peerState.pushOutgoingMessage(loadMessage);
132
-
133
- await waitFor(() => {
134
- expect(peerState.isProcessing()).toBe(false);
135
- });
136
-
137
- // The first message is pushed directly, the other three are queued because are waiting
138
- // for the first push to be completed.
139
- expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
140
- 1,
141
- contentMessageLow,
142
- );
143
-
144
- // Load message are managed as high priority messages and having the same priority as the content message
145
- // they follow the push order.
146
- expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
147
- 2,
148
- contentMessageHigh,
149
- );
150
- expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
151
- 3,
152
- loadMessage,
153
- );
154
- expect(peerState["peer"].outgoing.push).toHaveBeenNthCalledWith(
155
- 4,
156
- contentMessageMid,
157
- );
158
- });
159
-
160
48
  test("should clone the knownStates into optimisticKnownStates and knownStates when passed as argument", () => {
161
49
  const { peerState, mockPeer } = setup();
162
50
  peerState.setKnownState("co_z1", {
@@ -9,7 +9,11 @@ import {
9
9
 
10
10
  function setup(attrs?: Record<string, string | number>) {
11
11
  const metricReader = createTestMetricReader();
12
- const queue = new PriorityBasedMessageQueue(CO_VALUE_PRIORITY.MEDIUM, attrs);
12
+ const queue = new PriorityBasedMessageQueue(
13
+ CO_VALUE_PRIORITY.MEDIUM,
14
+ "outgoing",
15
+ attrs,
16
+ );
13
17
  return { queue, metricReader };
14
18
  }
15
19
 
@@ -29,21 +33,21 @@ describe("PriorityBasedMessageQueue", () => {
29
33
  };
30
34
 
31
35
  expect(
32
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
36
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
33
37
  priority: CO_VALUE_PRIORITY.MEDIUM,
34
38
  }),
35
39
  ).toBe(0);
36
40
 
37
41
  void queue.push(message);
38
42
  expect(
39
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
43
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
40
44
  priority: CO_VALUE_PRIORITY.MEDIUM,
41
45
  }),
42
46
  ).toBe(1);
43
47
 
44
48
  void queue.push(message);
45
49
  expect(
46
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
50
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
47
51
  priority: CO_VALUE_PRIORITY.MEDIUM,
48
52
  }),
49
53
  ).toBe(2);
@@ -59,14 +63,14 @@ describe("PriorityBasedMessageQueue", () => {
59
63
  };
60
64
 
61
65
  expect(
62
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
66
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
63
67
  priority: CO_VALUE_PRIORITY.MEDIUM,
64
68
  }),
65
69
  ).toBe(0);
66
70
 
67
71
  void queue.push(message);
68
72
  expect(
69
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
73
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
70
74
  priority: CO_VALUE_PRIORITY.MEDIUM,
71
75
  }),
72
76
  ).toBe(0);
@@ -74,7 +78,7 @@ describe("PriorityBasedMessageQueue", () => {
74
78
  void queue.pull();
75
79
 
76
80
  expect(
77
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
81
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
78
82
  priority: CO_VALUE_PRIORITY.MEDIUM,
79
83
  }),
80
84
  ).toBe(1);
@@ -82,7 +86,7 @@ describe("PriorityBasedMessageQueue", () => {
82
86
  // We only have one item in the queue, so this should not change the metric value
83
87
  void queue.pull();
84
88
  expect(
85
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
89
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
86
90
  priority: CO_VALUE_PRIORITY.MEDIUM,
87
91
  }),
88
92
  ).toBe(1);
@@ -98,13 +102,13 @@ describe("PriorityBasedMessageQueue", () => {
98
102
  };
99
103
 
100
104
  expect(
101
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
105
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
102
106
  priority: CO_VALUE_PRIORITY.MEDIUM,
103
107
  role: "server",
104
108
  }),
105
109
  ).toBe(0);
106
110
  expect(
107
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
111
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
108
112
  priority: CO_VALUE_PRIORITY.MEDIUM,
109
113
  role: "client",
110
114
  }),
@@ -112,13 +116,13 @@ describe("PriorityBasedMessageQueue", () => {
112
116
 
113
117
  void queue.push(message);
114
118
  expect(
115
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
119
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
116
120
  priority: CO_VALUE_PRIORITY.MEDIUM,
117
121
  role: "server",
118
122
  }),
119
123
  ).toBe(1);
120
124
  expect(
121
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
125
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
122
126
  priority: CO_VALUE_PRIORITY.MEDIUM,
123
127
  role: "server",
124
128
  }),
@@ -127,13 +131,13 @@ describe("PriorityBasedMessageQueue", () => {
127
131
  void queue.pull();
128
132
 
129
133
  expect(
130
- await metricReader.getMetricValue("jazz.messagequeue.pushed", {
134
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pushed", {
131
135
  priority: CO_VALUE_PRIORITY.MEDIUM,
132
136
  role: "server",
133
137
  }),
134
138
  ).toBe(1);
135
139
  expect(
136
- await metricReader.getMetricValue("jazz.messagequeue.pulled", {
140
+ await metricReader.getMetricValue("jazz.messagequeue.outgoing.pulled", {
137
141
  priority: CO_VALUE_PRIORITY.MEDIUM,
138
142
  role: "server",
139
143
  }),
@@ -0,0 +1,283 @@
1
+ import { beforeEach, describe, expect, test, vi } from "vitest";
2
+ import { StoreQueue } from "../storage/StoreQueue.js";
3
+ import type { CoValueKnownState, NewContentMessage } from "../sync.js";
4
+
5
+ function createMockNewContentMessage(id: string): NewContentMessage[] {
6
+ return [
7
+ {
8
+ action: "content",
9
+ id: id as any,
10
+ priority: 0,
11
+ new: {},
12
+ },
13
+ ];
14
+ }
15
+
16
+ function setup() {
17
+ const storeQueue = new StoreQueue();
18
+ const mockCallback = vi.fn();
19
+ const mockCorrectionCallback = vi.fn();
20
+
21
+ return { storeQueue, mockCallback, mockCorrectionCallback };
22
+ }
23
+
24
+ describe("StoreQueue", () => {
25
+ describe("push and pull", () => {
26
+ test("should push and pull entries in FIFO order", () => {
27
+ const { storeQueue, mockCorrectionCallback } = setup();
28
+ const data1 = createMockNewContentMessage("co1");
29
+ const data2 = createMockNewContentMessage("co2");
30
+
31
+ storeQueue.push(data1, mockCorrectionCallback);
32
+ storeQueue.push(data2, mockCorrectionCallback);
33
+
34
+ const entry1 = storeQueue.pull();
35
+ const entry2 = storeQueue.pull();
36
+ const entry3 = storeQueue.pull(); // Should be undefined
37
+
38
+ expect(entry1).toEqual({
39
+ data: data1,
40
+ correctionCallback: mockCorrectionCallback,
41
+ });
42
+ expect(entry2).toEqual({
43
+ data: data2,
44
+ correctionCallback: mockCorrectionCallback,
45
+ });
46
+ expect(entry3).toBeUndefined();
47
+ });
48
+
49
+ test("should handle empty queue", () => {
50
+ const { storeQueue } = setup();
51
+ const entry = storeQueue.pull();
52
+ expect(entry).toBeUndefined();
53
+ });
54
+
55
+ test("should handle single entry", () => {
56
+ const { storeQueue, mockCorrectionCallback } = setup();
57
+ const data = createMockNewContentMessage("co1");
58
+
59
+ storeQueue.push(data, mockCorrectionCallback);
60
+ const entry = storeQueue.pull();
61
+
62
+ expect(entry).toEqual({
63
+ data,
64
+ correctionCallback: mockCorrectionCallback,
65
+ });
66
+ expect(storeQueue.pull()).toBeUndefined();
67
+ });
68
+ });
69
+
70
+ describe("processQueue", () => {
71
+ test("should process all entries in queue", async () => {
72
+ const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
73
+ const data1 = createMockNewContentMessage("co1");
74
+ const data2 = createMockNewContentMessage("co2");
75
+
76
+ storeQueue.push(data1, mockCorrectionCallback);
77
+ storeQueue.push(data2, mockCorrectionCallback);
78
+
79
+ await storeQueue.processQueue(mockCallback);
80
+
81
+ expect(mockCallback).toHaveBeenCalledTimes(2);
82
+ expect(mockCallback).toHaveBeenNthCalledWith(
83
+ 1,
84
+ data1,
85
+ mockCorrectionCallback,
86
+ );
87
+ expect(mockCallback).toHaveBeenNthCalledWith(
88
+ 2,
89
+ data2,
90
+ mockCorrectionCallback,
91
+ );
92
+ });
93
+
94
+ test("should not process if already processing", async () => {
95
+ const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
96
+ const data = createMockNewContentMessage("co1");
97
+
98
+ storeQueue.push(data, mockCorrectionCallback);
99
+
100
+ // Start processing
101
+ const processPromise1 = storeQueue.processQueue(mockCallback);
102
+
103
+ // Try to process again while already processing
104
+ const processPromise2 = storeQueue.processQueue(mockCallback);
105
+
106
+ await Promise.all([processPromise1, processPromise2]);
107
+
108
+ // Should only be called once
109
+ expect(mockCallback).toHaveBeenCalledTimes(1);
110
+ });
111
+
112
+ test("should process entries pushed after a first processing round is done", async () => {
113
+ const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
114
+ const data = createMockNewContentMessage("co1");
115
+
116
+ storeQueue.push(data, mockCorrectionCallback);
117
+
118
+ await storeQueue.processQueue(mockCallback);
119
+
120
+ storeQueue.push(data, mockCorrectionCallback);
121
+
122
+ await storeQueue.processQueue(mockCallback);
123
+
124
+ expect(mockCallback).toHaveBeenCalledTimes(2);
125
+ });
126
+
127
+ test("should handle empty queue during processing", async () => {
128
+ const { storeQueue, mockCallback } = setup();
129
+ await storeQueue.processQueue(mockCallback);
130
+
131
+ expect(mockCallback).not.toHaveBeenCalled();
132
+ expect(storeQueue.processing).toBe(false);
133
+ });
134
+
135
+ test("should handle async callback that throws", async () => {
136
+ const { storeQueue, mockCorrectionCallback } = setup();
137
+ const data = createMockNewContentMessage("co1");
138
+
139
+ storeQueue.push(data, mockCorrectionCallback);
140
+
141
+ const errorCallback = vi.fn().mockRejectedValue(new Error("Test error"));
142
+
143
+ await storeQueue.processQueue(errorCallback);
144
+ expect(storeQueue.processing).toBe(false);
145
+ });
146
+ });
147
+
148
+ describe("drain", () => {
149
+ test("should remove all entries from queue", () => {
150
+ const { storeQueue, mockCorrectionCallback } = setup();
151
+ const data1 = createMockNewContentMessage("co1");
152
+ const data2 = createMockNewContentMessage("co2");
153
+
154
+ storeQueue.push(data1, mockCorrectionCallback);
155
+ storeQueue.push(data2, mockCorrectionCallback);
156
+
157
+ storeQueue.drain();
158
+
159
+ expect(storeQueue.pull()).toBeUndefined();
160
+ });
161
+
162
+ test("should handle empty queue", () => {
163
+ const { storeQueue } = setup();
164
+ expect(() => storeQueue.drain()).not.toThrow();
165
+ expect(storeQueue.pull()).toBeUndefined();
166
+ });
167
+ });
168
+
169
+ describe("integration scenarios", () => {
170
+ test("should handle complex workflow with multiple operations", async () => {
171
+ const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
172
+ const data1 = createMockNewContentMessage("co1");
173
+ const data2 = createMockNewContentMessage("co2");
174
+
175
+ // Push entries
176
+ storeQueue.push(data1, mockCorrectionCallback);
177
+ storeQueue.push(data2, mockCorrectionCallback);
178
+
179
+ // Process queue
180
+ await storeQueue.processQueue(mockCallback);
181
+
182
+ // Verify all entries were processed
183
+ expect(mockCallback).toHaveBeenCalledTimes(2);
184
+ expect(storeQueue.pull()).toBeUndefined();
185
+
186
+ // Add more entries and process again
187
+ const data3 = createMockNewContentMessage("co3");
188
+ storeQueue.push(data3, mockCorrectionCallback);
189
+
190
+ await storeQueue.processQueue(mockCallback);
191
+
192
+ expect(mockCallback).toHaveBeenCalledTimes(3);
193
+ expect(mockCallback).toHaveBeenLastCalledWith(
194
+ data3,
195
+ mockCorrectionCallback,
196
+ );
197
+ });
198
+
199
+ test("should handle correction callback with known state", async () => {
200
+ const { storeQueue, mockCorrectionCallback } = setup();
201
+ const sessionId = "account1_session_z123" as any;
202
+ const knownState: CoValueKnownState = {
203
+ id: "co1" as any,
204
+ header: true,
205
+ sessions: { [sessionId]: 5 },
206
+ };
207
+
208
+ const data = createMockNewContentMessage("co1");
209
+
210
+ storeQueue.push(data, mockCorrectionCallback);
211
+
212
+ await storeQueue.processQueue(async (data, correctionCallback) => {
213
+ // Simulate some processing
214
+ await new Promise((resolve) => setTimeout(resolve, 10));
215
+ // Call the correction callback
216
+ correctionCallback(knownState);
217
+ });
218
+
219
+ expect(mockCorrectionCallback).toHaveBeenCalledWith(knownState);
220
+ });
221
+
222
+ test("should handle concurrent processing attempts", async () => {
223
+ const { storeQueue, mockCallback, mockCorrectionCallback } = setup();
224
+ const data = createMockNewContentMessage("co1");
225
+
226
+ storeQueue.push(data, mockCorrectionCallback);
227
+
228
+ // Start multiple processing attempts concurrently
229
+ const promises = [
230
+ storeQueue.processQueue(mockCallback),
231
+ storeQueue.processQueue(mockCallback),
232
+ storeQueue.processQueue(mockCallback),
233
+ ];
234
+
235
+ await Promise.all(promises);
236
+
237
+ // Should only process once
238
+ expect(mockCallback).toHaveBeenCalledTimes(1);
239
+ });
240
+ });
241
+
242
+ describe("edge cases", () => {
243
+ test("should handle undefined data", () => {
244
+ const { storeQueue, mockCorrectionCallback } = setup();
245
+ const data: NewContentMessage[] = [];
246
+ storeQueue.push(data, mockCorrectionCallback);
247
+
248
+ const entry = storeQueue.pull();
249
+ expect(entry).toEqual({
250
+ data,
251
+ correctionCallback: mockCorrectionCallback,
252
+ });
253
+ });
254
+
255
+ test("should handle null correction callback", () => {
256
+ const { storeQueue } = setup();
257
+ const data = createMockNewContentMessage("co1");
258
+
259
+ const nullCallback = () => {};
260
+ storeQueue.push(data, nullCallback);
261
+
262
+ const entry = storeQueue.pull();
263
+ expect(entry).toEqual({ data, correctionCallback: nullCallback });
264
+ });
265
+
266
+ test("should handle very large number of entries", () => {
267
+ const { storeQueue, mockCorrectionCallback } = setup();
268
+ const entries = 1000;
269
+
270
+ for (let i = 0; i < entries; i++) {
271
+ const data = createMockNewContentMessage(`co${i}`);
272
+ storeQueue.push(data, mockCorrectionCallback);
273
+ }
274
+
275
+ let count = 0;
276
+ while (storeQueue.pull()) {
277
+ count++;
278
+ }
279
+
280
+ expect(count).toBe(entries);
281
+ });
282
+ });
283
+ });
@@ -11,8 +11,11 @@ import {
11
11
  setupTestNode,
12
12
  waitFor,
13
13
  } from "./testUtils.js";
14
+ import { TEST_NODE_CONFIG } from "./testUtils.js";
14
15
 
15
- let jazzCloud = setupTestNode({ isSyncServer: true });
16
+ TEST_NODE_CONFIG.withAsyncPeers = true;
17
+
18
+ let jazzCloud: ReturnType<typeof setupTestNode>;
16
19
 
17
20
  beforeEach(async () => {
18
21
  SyncMessagesLog.clear();
@@ -3,7 +3,7 @@ import { expectAccount } from "../coValues/account.js";
3
3
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
4
4
  import { LocalNode } from "../localNode.js";
5
5
  import { connectedPeers } from "../streamUtils.js";
6
- import { createMockStoragePeer } from "./testUtils.js";
6
+ import { createAsyncStorage } from "./testStorage.js";
7
7
 
8
8
  const Crypto = await WasmCrypto.create();
9
9
 
@@ -89,23 +89,22 @@ test("throws an error if the user tried to create an invite from an account", as
89
89
  });
90
90
 
91
91
  test("wait for storage sync before resolving withNewlyCreatedAccount", async () => {
92
- const { storage, peer } = createMockStoragePeer({
93
- peerId: "account-node",
92
+ const storage = await createAsyncStorage({
93
+ nodeName: "account-node",
94
+ storageName: "storage",
94
95
  });
95
96
 
96
- const { node, accountID } = await LocalNode.withNewlyCreatedAccount({
97
+ const { accountID, node } = await LocalNode.withNewlyCreatedAccount({
97
98
  creationProps: { name: "Hermes Puggington" },
98
99
  crypto: Crypto,
99
- peersToLoadFrom: [peer],
100
+ storage,
100
101
  });
101
102
 
102
- const account = storage.getCoValue(accountID);
103
-
104
- expect(account.isAvailable()).toBe(true);
103
+ expect(storage.getKnownState(accountID).header).toBe(true);
105
104
 
106
- const profile = storage.getCoValue(
107
- expectAccount(account.getCurrentContent()).get("profile")!,
108
- );
105
+ const profileId = expectAccount(
106
+ node.getCoValue(accountID).getCurrentContent(),
107
+ ).get("profile")!;
109
108
 
110
- expect(profile.isAvailable()).toBe(true);
109
+ expect(storage.getKnownState(profileId).header).toBe(true);
111
110
  });
@@ -1,19 +1,17 @@
1
1
  import { beforeEach, describe, expect, test } from "vitest";
2
2
  import { expectStream } from "../coValue.js";
3
- import { MAX_RECOMMENDED_TX_SIZE } from "../coValueCore/coValueCore.js";
4
3
  import {
5
4
  BinaryStreamItem,
6
5
  CoStreamItem,
7
6
  RawBinaryCoStream,
8
7
  RawCoStreamView,
9
8
  } from "../coValues/coStream.js";
9
+ import { MAX_RECOMMENDED_TX_SIZE } from "../config.js";
10
10
  import { WasmCrypto } from "../crypto/WasmCrypto.js";
11
11
  import { SessionID } from "../ids.js";
12
- import { LocalNode } from "../localNode.js";
13
12
  import {
14
13
  loadCoValueOrFail,
15
14
  nodeWithRandomAgentAndSessionID,
16
- randomAgentAndSessionID,
17
15
  setupTestNode,
18
16
  waitFor,
19
17
  } from "./testUtils.js";