cojson 0.19.21 → 0.19.22
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +13 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts +42 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.js +261 -0
- package/dist/CojsonMessageChannel/CojsonMessageChannel.js.map +1 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts +18 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js +37 -0
- package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js.map +1 -0
- package/dist/CojsonMessageChannel/index.d.ts +3 -0
- package/dist/CojsonMessageChannel/index.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/index.js +2 -0
- package/dist/CojsonMessageChannel/index.js.map +1 -0
- package/dist/CojsonMessageChannel/types.d.ts +149 -0
- package/dist/CojsonMessageChannel/types.d.ts.map +1 -0
- package/dist/CojsonMessageChannel/types.js +36 -0
- package/dist/CojsonMessageChannel/types.js.map +1 -0
- package/dist/GarbageCollector.d.ts +4 -2
- package/dist/GarbageCollector.d.ts.map +1 -1
- package/dist/GarbageCollector.js +5 -3
- package/dist/GarbageCollector.js.map +1 -1
- package/dist/SyncStateManager.d.ts +3 -3
- package/dist/SyncStateManager.d.ts.map +1 -1
- package/dist/SyncStateManager.js +4 -4
- package/dist/SyncStateManager.js.map +1 -1
- package/dist/coValueCore/coValueCore.d.ts +19 -1
- package/dist/coValueCore/coValueCore.d.ts.map +1 -1
- package/dist/coValueCore/coValueCore.js +29 -5
- package/dist/coValueCore/coValueCore.js.map +1 -1
- package/dist/exports.d.ts +1 -0
- package/dist/exports.d.ts.map +1 -1
- package/dist/exports.js +1 -0
- package/dist/exports.js.map +1 -1
- package/dist/localNode.d.ts +1 -3
- package/dist/localNode.d.ts.map +1 -1
- package/dist/localNode.js +3 -2
- package/dist/localNode.js.map +1 -1
- package/dist/storage/storageAsync.d.ts +8 -3
- package/dist/storage/storageAsync.d.ts.map +1 -1
- package/dist/storage/storageAsync.js +12 -3
- package/dist/storage/storageAsync.js.map +1 -1
- package/dist/storage/storageSync.d.ts +8 -3
- package/dist/storage/storageSync.d.ts.map +1 -1
- package/dist/storage/storageSync.js +12 -3
- package/dist/storage/storageSync.js.map +1 -1
- package/dist/storage/types.d.ts +5 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/sync.d.ts +6 -0
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +25 -4
- package/dist/sync.js.map +1 -1
- package/dist/tests/CojsonMessageChannel.test.d.ts +2 -0
- package/dist/tests/CojsonMessageChannel.test.d.ts.map +1 -0
- package/dist/tests/CojsonMessageChannel.test.js +236 -0
- package/dist/tests/CojsonMessageChannel.test.js.map +1 -0
- package/dist/tests/GarbageCollector.test.js +87 -13
- package/dist/tests/GarbageCollector.test.js.map +1 -1
- package/dist/tests/StorageApiAsync.test.js +33 -1
- package/dist/tests/StorageApiAsync.test.js.map +1 -1
- package/dist/tests/StorageApiSync.test.js +32 -0
- package/dist/tests/StorageApiSync.test.js.map +1 -1
- package/dist/tests/SyncManager.processQueues.test.js +1 -1
- package/dist/tests/SyncManager.processQueues.test.js.map +1 -1
- package/dist/tests/SyncStateManager.test.js +1 -1
- package/dist/tests/SyncStateManager.test.js.map +1 -1
- package/dist/tests/coPlainText.test.js +1 -1
- package/dist/tests/coPlainText.test.js.map +1 -1
- package/dist/tests/coValueCore.loadFromStorage.test.js +1 -0
- package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
- package/dist/tests/knownState.lazyLoading.test.js +1 -0
- package/dist/tests/knownState.lazyLoading.test.js.map +1 -1
- package/dist/tests/sync.garbageCollection.test.js +56 -32
- package/dist/tests/sync.garbageCollection.test.js.map +1 -1
- package/dist/tests/sync.load.test.js +3 -5
- package/dist/tests/sync.load.test.js.map +1 -1
- package/dist/tests/sync.mesh.test.js +1 -1
- package/dist/tests/sync.mesh.test.js.map +1 -1
- package/dist/tests/sync.peerReconciliation.test.js +3 -3
- package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
- package/dist/tests/sync.storage.test.js +9 -9
- package/dist/tests/sync.storage.test.js.map +1 -1
- package/dist/tests/sync.storageAsync.test.js +7 -7
- package/dist/tests/sync.storageAsync.test.js.map +1 -1
- package/dist/tests/sync.tracking.test.js +35 -4
- package/dist/tests/sync.tracking.test.js.map +1 -1
- package/dist/tests/testStorage.js +2 -2
- package/dist/tests/testStorage.js.map +1 -1
- package/dist/tests/testUtils.d.ts +24 -2
- package/dist/tests/testUtils.d.ts.map +1 -1
- package/dist/tests/testUtils.js +68 -7
- package/dist/tests/testUtils.js.map +1 -1
- package/package.json +4 -4
- package/src/CojsonMessageChannel/CojsonMessageChannel.ts +332 -0
- package/src/CojsonMessageChannel/MessagePortOutgoingChannel.ts +52 -0
- package/src/CojsonMessageChannel/index.ts +9 -0
- package/src/CojsonMessageChannel/types.ts +200 -0
- package/src/GarbageCollector.ts +5 -5
- package/src/SyncStateManager.ts +6 -6
- package/src/coValueCore/coValueCore.ts +30 -7
- package/src/exports.ts +1 -0
- package/src/localNode.ts +3 -5
- package/src/storage/storageAsync.ts +15 -4
- package/src/storage/storageSync.ts +15 -4
- package/src/storage/types.ts +6 -0
- package/src/sync.ts +33 -4
- package/src/tests/CojsonMessageChannel.test.ts +306 -0
- package/src/tests/GarbageCollector.test.ts +114 -13
- package/src/tests/StorageApiAsync.test.ts +50 -1
- package/src/tests/StorageApiSync.test.ts +49 -0
- package/src/tests/SyncManager.processQueues.test.ts +1 -1
- package/src/tests/SyncStateManager.test.ts +1 -1
- package/src/tests/coPlainText.test.ts +1 -1
- package/src/tests/coValueCore.loadFromStorage.test.ts +2 -0
- package/src/tests/knownState.lazyLoading.test.ts +2 -0
- package/src/tests/sync.garbageCollection.test.ts +69 -36
- package/src/tests/sync.load.test.ts +3 -5
- package/src/tests/sync.mesh.test.ts +1 -1
- package/src/tests/sync.peerReconciliation.test.ts +3 -3
- package/src/tests/sync.storage.test.ts +9 -9
- package/src/tests/sync.storageAsync.test.ts +7 -7
- package/src/tests/sync.tracking.test.ts +54 -4
- package/src/tests/testStorage.ts +2 -2
- package/src/tests/testUtils.ts +85 -6
|
@@ -50,6 +50,47 @@ describe("sync after the garbage collector has run", () => {
|
|
|
50
50
|
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
51
51
|
expect(mapOnClient.get("hello")).toEqual("world");
|
|
52
52
|
|
|
53
|
+
expect(
|
|
54
|
+
SyncMessagesLog.getMessages({
|
|
55
|
+
Group: group.core,
|
|
56
|
+
Map: map.core,
|
|
57
|
+
}),
|
|
58
|
+
).toMatchInlineSnapshot(`
|
|
59
|
+
[
|
|
60
|
+
"client -> server | LOAD Map sessions: empty",
|
|
61
|
+
"server -> storage | LOAD Map sessions: empty",
|
|
62
|
+
"storage -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
63
|
+
"server -> client | CONTENT Group header: true new: After: 0 New: 3",
|
|
64
|
+
"server -> client | CONTENT Map header: true new: After: 0 New: 1",
|
|
65
|
+
"client -> server | KNOWN Group sessions: header/3",
|
|
66
|
+
"client -> server | KNOWN Map sessions: header/1",
|
|
67
|
+
]
|
|
68
|
+
`);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("loading a coValue from the sync server that was removed by the garbage collector along with its owner", async () => {
|
|
72
|
+
const client = setupTestNode();
|
|
73
|
+
|
|
74
|
+
client.connectToSyncServer();
|
|
75
|
+
|
|
76
|
+
const group = jazzCloud.node.createGroup();
|
|
77
|
+
const map = group.createMap();
|
|
78
|
+
map.set("hello", "world", "trusting");
|
|
79
|
+
|
|
80
|
+
await map.core.waitForSync();
|
|
81
|
+
|
|
82
|
+
// force the garbage collector to run twice to remove the map and its group
|
|
83
|
+
jazzCloud.node.garbageCollector?.collect();
|
|
84
|
+
jazzCloud.node.garbageCollector?.collect();
|
|
85
|
+
|
|
86
|
+
expect(jazzCloud.node.getCoValue(group.id).isAvailable()).toBe(false);
|
|
87
|
+
expect(jazzCloud.node.getCoValue(map.id).isAvailable()).toBe(false);
|
|
88
|
+
|
|
89
|
+
SyncMessagesLog.clear();
|
|
90
|
+
|
|
91
|
+
const mapOnClient = await loadCoValueOrFail(client.node, map.id);
|
|
92
|
+
expect(mapOnClient.get("hello")).toEqual("world");
|
|
93
|
+
|
|
53
94
|
expect(
|
|
54
95
|
SyncMessagesLog.getMessages({
|
|
55
96
|
Group: group.core,
|
|
@@ -103,7 +144,6 @@ describe("sync after the garbage collector has run", () => {
|
|
|
103
144
|
[
|
|
104
145
|
"client -> server | CONTENT Map header: false new: After: 0 New: 1",
|
|
105
146
|
"server -> storage | LOAD Map sessions: empty",
|
|
106
|
-
"storage -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
107
147
|
"storage -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
108
148
|
"server -> client | KNOWN Map sessions: header/2",
|
|
109
149
|
"server -> storage | CONTENT Map header: false new: After: 0 New: 1",
|
|
@@ -112,41 +152,30 @@ describe("sync after the garbage collector has run", () => {
|
|
|
112
152
|
});
|
|
113
153
|
|
|
114
154
|
test("syncing a coValue that was removed by the garbage collector", async () => {
|
|
115
|
-
const edge = setupTestNode();
|
|
116
|
-
edge.addStorage({
|
|
117
|
-
ourName: "edge",
|
|
118
|
-
});
|
|
119
|
-
edge.connectToSyncServer({
|
|
120
|
-
syncServer: jazzCloud.node,
|
|
121
|
-
syncServerName: "server",
|
|
122
|
-
ourName: "edge",
|
|
123
|
-
});
|
|
124
|
-
edge.node.enableGarbageCollector();
|
|
125
155
|
const client = setupTestNode();
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
syncServer: edge.node,
|
|
129
|
-
syncServerName: "edge",
|
|
156
|
+
client.addStorage({
|
|
157
|
+
ourName: "client",
|
|
130
158
|
});
|
|
159
|
+
client.node.enableGarbageCollector();
|
|
131
160
|
|
|
132
|
-
const group =
|
|
133
|
-
group.addMember("everyone", "writer");
|
|
134
|
-
|
|
135
|
-
await group.core.waitForSync();
|
|
136
|
-
|
|
161
|
+
const group = client.node.createGroup();
|
|
137
162
|
const map = group.createMap();
|
|
138
|
-
|
|
139
163
|
map.set("hello", "updated", "trusting");
|
|
140
164
|
|
|
141
165
|
// force the garbage collector to run before the transaction is synced
|
|
142
|
-
|
|
143
|
-
expect(
|
|
166
|
+
client.node.garbageCollector?.collect();
|
|
167
|
+
expect(client.node.getCoValue(map.id).isAvailable()).toBe(false);
|
|
144
168
|
|
|
145
169
|
SyncMessagesLog.clear();
|
|
146
170
|
|
|
171
|
+
client.connectToSyncServer();
|
|
172
|
+
|
|
173
|
+
// Wait for unsynced coValues to be resumed and synced after connecting to server
|
|
174
|
+
await client.node.syncManager.waitForAllCoValuesSync();
|
|
175
|
+
|
|
147
176
|
// The storage should work even after the coValue is unmounted, so the load should be successful
|
|
148
|
-
const
|
|
149
|
-
expect(
|
|
177
|
+
const mapOnServer = await loadCoValueOrFail(jazzCloud.node, map.id);
|
|
178
|
+
expect(mapOnServer.get("hello")).toEqual("updated");
|
|
150
179
|
|
|
151
180
|
expect(
|
|
152
181
|
SyncMessagesLog.getMessages({
|
|
@@ -155,18 +184,22 @@ describe("sync after the garbage collector has run", () => {
|
|
|
155
184
|
}),
|
|
156
185
|
).toMatchInlineSnapshot(`
|
|
157
186
|
[
|
|
158
|
-
"client ->
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
165
|
-
"
|
|
166
|
-
"server ->
|
|
187
|
+
"client -> server | LOAD Map sessions: empty",
|
|
188
|
+
"client -> server | LOAD Group sessions: header/3",
|
|
189
|
+
"client -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
190
|
+
"client -> server | CONTENT Group header: true new: After: 0 New: 3",
|
|
191
|
+
"client -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
192
|
+
"client -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
193
|
+
"server -> storage | LOAD Map sessions: empty",
|
|
194
|
+
"storage -> server | KNOWN Map sessions: empty",
|
|
195
|
+
"server -> client | KNOWN Map sessions: empty",
|
|
196
|
+
"server -> storage | GET_KNOWN_STATE Group",
|
|
197
|
+
"storage -> server | GET_KNOWN_STATE_RESULT Group sessions: empty",
|
|
198
|
+
"server -> client | KNOWN Group sessions: empty",
|
|
199
|
+
"server -> client | KNOWN Group sessions: header/3",
|
|
200
|
+
"server -> storage | CONTENT Group header: true new: After: 0 New: 3",
|
|
201
|
+
"server -> client | KNOWN Map sessions: header/1",
|
|
167
202
|
"server -> storage | CONTENT Map header: true new: After: 0 New: 1",
|
|
168
|
-
"client -> edge | KNOWN Group sessions: header/5",
|
|
169
|
-
"client -> edge | KNOWN Map sessions: header/1",
|
|
170
203
|
]
|
|
171
204
|
`);
|
|
172
205
|
});
|
|
@@ -514,7 +514,7 @@ describe("loading coValues from server", () => {
|
|
|
514
514
|
});
|
|
515
515
|
|
|
516
516
|
// Makes the CoValues unavailable on the server
|
|
517
|
-
jazzCloud.restart();
|
|
517
|
+
await jazzCloud.restart();
|
|
518
518
|
|
|
519
519
|
const client = setupTestNode({
|
|
520
520
|
connected: true,
|
|
@@ -1476,7 +1476,7 @@ describe("lazy storage load optimization", () => {
|
|
|
1476
1476
|
|
|
1477
1477
|
// Restart the server to clear memory (keeping storage)
|
|
1478
1478
|
// Now the server has no CoValues in memory, only in storage
|
|
1479
|
-
jazzCloud.restart();
|
|
1479
|
+
await jazzCloud.restart();
|
|
1480
1480
|
jazzCloud.node.setStorage(storage);
|
|
1481
1481
|
|
|
1482
1482
|
SyncMessagesLog.clear();
|
|
@@ -1519,7 +1519,7 @@ describe("lazy storage load optimization", () => {
|
|
|
1519
1519
|
await map.core.waitForSync();
|
|
1520
1520
|
|
|
1521
1521
|
// Restart the server to clear memory (keeping storage)
|
|
1522
|
-
jazzCloud.restart();
|
|
1522
|
+
await jazzCloud.restart();
|
|
1523
1523
|
jazzCloud.node.setStorage(storage);
|
|
1524
1524
|
|
|
1525
1525
|
SyncMessagesLog.clear();
|
|
@@ -1643,7 +1643,6 @@ describe("lazy storage load optimization", () => {
|
|
|
1643
1643
|
[
|
|
1644
1644
|
"client -> server | CONTENT Map header: false new: After: 0 New: 1",
|
|
1645
1645
|
"server -> storage | LOAD Map sessions: empty",
|
|
1646
|
-
"storage -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
1647
1646
|
"storage -> server | CONTENT Map header: true new: After: 0 New: 1",
|
|
1648
1647
|
"server -> client | KNOWN Map sessions: header/2",
|
|
1649
1648
|
"server -> storage | CONTENT Map header: false new: After: 0 New: 1",
|
|
@@ -1702,7 +1701,6 @@ describe("lazy storage load optimization", () => {
|
|
|
1702
1701
|
[
|
|
1703
1702
|
"client -> server | CONTENT Map header: false new: After: 0 New: 1",
|
|
1704
1703
|
"server -> storage | LOAD Map sessions: empty",
|
|
1705
|
-
"storage -> server | CONTENT Group header: true new: After: 0 New: 5",
|
|
1706
1704
|
"storage -> server | CONTENT Map header: true new: After: 0 New: 73 expectContentUntil: header/201",
|
|
1707
1705
|
"server -> client | KNOWN Map sessions: header/74",
|
|
1708
1706
|
"server -> storage | CONTENT Map header: false new: After: 0 New: 1",
|
|
@@ -167,7 +167,7 @@ describe("peer reconciliation", () => {
|
|
|
167
167
|
|
|
168
168
|
await map.core.waitForSync();
|
|
169
169
|
|
|
170
|
-
jazzCloud.restart();
|
|
170
|
+
await jazzCloud.restart();
|
|
171
171
|
SyncMessagesLog.clear();
|
|
172
172
|
client.connectToSyncServer();
|
|
173
173
|
|
|
@@ -222,7 +222,7 @@ describe("peer reconciliation", () => {
|
|
|
222
222
|
|
|
223
223
|
await map.core.waitForSync();
|
|
224
224
|
|
|
225
|
-
jazzCloud.restart();
|
|
225
|
+
await jazzCloud.restart();
|
|
226
226
|
SyncMessagesLog.clear();
|
|
227
227
|
client.connectToSyncServer();
|
|
228
228
|
|
|
@@ -305,7 +305,7 @@ describe("peer reconciliation", () => {
|
|
|
305
305
|
|
|
306
306
|
await map.core.waitForSync();
|
|
307
307
|
|
|
308
|
-
jazzCloud.restart();
|
|
308
|
+
await jazzCloud.restart();
|
|
309
309
|
|
|
310
310
|
SyncMessagesLog.clear();
|
|
311
311
|
client.connectToSyncServer();
|
|
@@ -83,7 +83,7 @@ describe("client with storage syncs with server", () => {
|
|
|
83
83
|
|
|
84
84
|
await loadCoValueOrFail(client.node, map.id);
|
|
85
85
|
|
|
86
|
-
client.restart();
|
|
86
|
+
await client.restart();
|
|
87
87
|
|
|
88
88
|
client.connectToSyncServer();
|
|
89
89
|
client.addStorage({
|
|
@@ -167,7 +167,7 @@ describe("client with storage syncs with server", () => {
|
|
|
167
167
|
|
|
168
168
|
await map.core.waitForSync();
|
|
169
169
|
|
|
170
|
-
client.restart();
|
|
170
|
+
await client.restart();
|
|
171
171
|
|
|
172
172
|
client.addStorage({
|
|
173
173
|
storage,
|
|
@@ -217,7 +217,7 @@ describe("client with storage syncs with server", () => {
|
|
|
217
217
|
branch.set("branchKey", "branchValue");
|
|
218
218
|
await branch.core.waitForSync();
|
|
219
219
|
|
|
220
|
-
client.restart();
|
|
220
|
+
await client.restart();
|
|
221
221
|
client.addStorage({
|
|
222
222
|
storage,
|
|
223
223
|
});
|
|
@@ -388,7 +388,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
388
388
|
|
|
389
389
|
SyncMessagesLog.clear();
|
|
390
390
|
|
|
391
|
-
client.restart();
|
|
391
|
+
await client.restart();
|
|
392
392
|
|
|
393
393
|
client.connectToSyncServer({
|
|
394
394
|
ourName: "client",
|
|
@@ -457,7 +457,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
457
457
|
|
|
458
458
|
expect(correctionSpy).not.toHaveBeenCalled();
|
|
459
459
|
|
|
460
|
-
client.restart();
|
|
460
|
+
await client.restart();
|
|
461
461
|
|
|
462
462
|
client.connectToSyncServer({
|
|
463
463
|
ourName: "client",
|
|
@@ -771,7 +771,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
771
771
|
|
|
772
772
|
SyncMessagesLog.clear();
|
|
773
773
|
|
|
774
|
-
syncServer.restart();
|
|
774
|
+
await syncServer.restart();
|
|
775
775
|
syncServer.addStorage({
|
|
776
776
|
ourName: "syncServer",
|
|
777
777
|
storage,
|
|
@@ -848,7 +848,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
848
848
|
]);
|
|
849
849
|
|
|
850
850
|
// Restart to load from storage
|
|
851
|
-
client.restart();
|
|
851
|
+
await client.restart();
|
|
852
852
|
client.addStorage({ storage });
|
|
853
853
|
|
|
854
854
|
// Load all maps concurrently from storage
|
|
@@ -892,7 +892,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
892
892
|
SyncMessagesLog.clear();
|
|
893
893
|
|
|
894
894
|
// Restart client with storage
|
|
895
|
-
client.restart();
|
|
895
|
+
await client.restart();
|
|
896
896
|
client.connectToSyncServer();
|
|
897
897
|
client.addStorage({ storage });
|
|
898
898
|
|
|
@@ -985,7 +985,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
985
985
|
|
|
986
986
|
SyncMessagesLog.clear();
|
|
987
987
|
|
|
988
|
-
syncServer.restart();
|
|
988
|
+
await syncServer.restart();
|
|
989
989
|
syncServer.addStorage({
|
|
990
990
|
ourName: "syncServer",
|
|
991
991
|
storage,
|
|
@@ -72,7 +72,7 @@ describe("client with storage syncs with server", () => {
|
|
|
72
72
|
const firstLoad = await loadCoValueOrFail(client.node, map.id);
|
|
73
73
|
await firstLoad.core.waitForSync(); // Need to wait for sync with storage
|
|
74
74
|
|
|
75
|
-
client.restart();
|
|
75
|
+
await client.restart();
|
|
76
76
|
|
|
77
77
|
client.connectToSyncServer();
|
|
78
78
|
client.addStorage({
|
|
@@ -311,7 +311,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
311
311
|
|
|
312
312
|
SyncMessagesLog.clear();
|
|
313
313
|
|
|
314
|
-
client.restart();
|
|
314
|
+
await client.restart();
|
|
315
315
|
|
|
316
316
|
client.connectToSyncServer({
|
|
317
317
|
ourName: "client",
|
|
@@ -406,7 +406,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
406
406
|
const largeMapContent =
|
|
407
407
|
largeMap.core.newContentSince(undefined)?.slice(0, 4) ?? [];
|
|
408
408
|
|
|
409
|
-
client.restart();
|
|
409
|
+
await client.restart();
|
|
410
410
|
|
|
411
411
|
const newSyncServer = setupTestNode({
|
|
412
412
|
isSyncServer: true,
|
|
@@ -518,7 +518,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
518
518
|
|
|
519
519
|
expect(correctionSpy).not.toHaveBeenCalled();
|
|
520
520
|
|
|
521
|
-
client.restart();
|
|
521
|
+
await client.restart();
|
|
522
522
|
|
|
523
523
|
client.connectToSyncServer({
|
|
524
524
|
ourName: "client",
|
|
@@ -566,14 +566,14 @@ describe("client syncs with a server with storage", () => {
|
|
|
566
566
|
|
|
567
567
|
await largeMap.core.waitForSync();
|
|
568
568
|
|
|
569
|
-
server.restart();
|
|
569
|
+
await server.restart();
|
|
570
570
|
|
|
571
571
|
server.addStorage({
|
|
572
572
|
ourName: "server",
|
|
573
573
|
storage: serverStorage,
|
|
574
574
|
});
|
|
575
575
|
|
|
576
|
-
client.restart();
|
|
576
|
+
await client.restart();
|
|
577
577
|
|
|
578
578
|
client.connectToSyncServer({
|
|
579
579
|
ourName: "client",
|
|
@@ -703,7 +703,7 @@ describe("client syncs with a server with storage", () => {
|
|
|
703
703
|
|
|
704
704
|
SyncMessagesLog.clear();
|
|
705
705
|
|
|
706
|
-
syncServer.restart();
|
|
706
|
+
await syncServer.restart();
|
|
707
707
|
syncServer.addStorage({
|
|
708
708
|
ourName: "syncServer",
|
|
709
709
|
storage,
|
|
@@ -73,6 +73,56 @@ describe("coValue sync state tracking", () => {
|
|
|
73
73
|
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test("coValue is marked as synced after connecting to a server peer", async () => {
|
|
77
|
+
const client = setupTestNode({ connected: false });
|
|
78
|
+
|
|
79
|
+
const group = client.node.createGroup();
|
|
80
|
+
const map = group.createMap();
|
|
81
|
+
map.set("key", "value");
|
|
82
|
+
|
|
83
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
84
|
+
|
|
85
|
+
const unsyncedTracker = client.node.syncManager.unsyncedTracker;
|
|
86
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
87
|
+
|
|
88
|
+
client.connectToSyncServer();
|
|
89
|
+
|
|
90
|
+
const serverPeer =
|
|
91
|
+
client.node.syncManager.peers[jazzCloud.node.currentSessionID]!;
|
|
92
|
+
await waitFor(() =>
|
|
93
|
+
client.node.syncManager.syncState.isSynced(serverPeer, map.id),
|
|
94
|
+
);
|
|
95
|
+
expect(unsyncedTracker.has(map.id)).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("coValue is NOT marked as synced after uploading it to a client peer", async () => {
|
|
99
|
+
const client = setupTestNode({ connected: false });
|
|
100
|
+
|
|
101
|
+
const group = client.node.createGroup();
|
|
102
|
+
const map = group.createMap();
|
|
103
|
+
map.set("key", "value");
|
|
104
|
+
|
|
105
|
+
await new Promise<void>((resolve) => queueMicrotask(resolve));
|
|
106
|
+
|
|
107
|
+
const unsyncedTracker = client.node.syncManager.unsyncedTracker;
|
|
108
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
109
|
+
|
|
110
|
+
const anotherClient = setupTestNode({ connected: false });
|
|
111
|
+
anotherClient.connectToSyncServer({
|
|
112
|
+
syncServer: client.node,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Load the coValue from the client to trigger sync between the server and the client
|
|
116
|
+
await anotherClient.node.loadCoValueCore(map.id);
|
|
117
|
+
|
|
118
|
+
const clientPeer =
|
|
119
|
+
client.node.syncManager.peers[anotherClient.node.currentSessionID]!;
|
|
120
|
+
await waitFor(() =>
|
|
121
|
+
client.node.syncManager.syncState.isSynced(clientPeer, map.id),
|
|
122
|
+
);
|
|
123
|
+
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
|
|
76
126
|
test("only tracks sync state for persistent servers peers", async () => {
|
|
77
127
|
const { node: client, connectToSyncServer } = setupTestNode({
|
|
78
128
|
connected: true,
|
|
@@ -262,7 +312,7 @@ describe("sync resumption", () => {
|
|
|
262
312
|
expect(unsyncedTracker.has(map.id)).toBe(true);
|
|
263
313
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(2);
|
|
264
314
|
|
|
265
|
-
client.restart();
|
|
315
|
+
await client.restart();
|
|
266
316
|
client.addStorage({ storage });
|
|
267
317
|
const { peerState: serverPeerState } = client.connectToSyncServer();
|
|
268
318
|
|
|
@@ -300,7 +350,7 @@ describe("sync resumption", () => {
|
|
|
300
350
|
}
|
|
301
351
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(101);
|
|
302
352
|
|
|
303
|
-
client.restart();
|
|
353
|
+
await client.restart();
|
|
304
354
|
client.addStorage({ storage });
|
|
305
355
|
const { peerState: serverPeerState } = client.connectToSyncServer();
|
|
306
356
|
|
|
@@ -339,7 +389,7 @@ describe("sync resumption", () => {
|
|
|
339
389
|
|
|
340
390
|
expect(await getUnsyncedCoValueIDsFromStorage()).toHaveLength(2);
|
|
341
391
|
|
|
342
|
-
client.restart();
|
|
392
|
+
await client.restart();
|
|
343
393
|
client.addStorage({ storage });
|
|
344
394
|
const newSyncServer = setupTestNode({ isSyncServer: true });
|
|
345
395
|
const { peerState: newServerPeerState } = client.connectToSyncServer({
|
|
@@ -377,7 +427,7 @@ describe("sync resumption", () => {
|
|
|
377
427
|
expect(unsyncedCoValueIDs).toContain(map.id);
|
|
378
428
|
expect(unsyncedCoValueIDs).toContain(group.id);
|
|
379
429
|
|
|
380
|
-
client.restart();
|
|
430
|
+
await client.restart();
|
|
381
431
|
client.addStorage({ storage });
|
|
382
432
|
const newPeer = setupTestNode({ isSyncServer: true });
|
|
383
433
|
client.connectToSyncServer({
|
package/src/tests/testStorage.ts
CHANGED
|
@@ -104,8 +104,8 @@ export async function createAsyncStorage({
|
|
|
104
104
|
new LibSQLSqliteAsyncDriver(getDbPath(filename)),
|
|
105
105
|
);
|
|
106
106
|
|
|
107
|
-
onTestFinished(() => {
|
|
108
|
-
storage.close();
|
|
107
|
+
onTestFinished(async () => {
|
|
108
|
+
await storage.close();
|
|
109
109
|
});
|
|
110
110
|
|
|
111
111
|
trackStorageMessages(storage, nodeName, storageName);
|
package/src/tests/testUtils.ts
CHANGED
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
AnyRawCoValue,
|
|
14
14
|
type CoID,
|
|
15
15
|
type CoValueCore,
|
|
16
|
+
MessageChannelLike,
|
|
17
|
+
MessagePortLike,
|
|
16
18
|
type RawAccount,
|
|
17
19
|
RawAccountID,
|
|
18
20
|
RawCoMap,
|
|
@@ -187,8 +189,8 @@ export function newGroupHighLevel() {
|
|
|
187
189
|
|
|
188
190
|
const group = node.createGroup();
|
|
189
191
|
|
|
190
|
-
onTestFinished(() => {
|
|
191
|
-
node.gracefulShutdown();
|
|
192
|
+
onTestFinished(async () => {
|
|
193
|
+
await node.gracefulShutdown();
|
|
192
194
|
});
|
|
193
195
|
return { admin, node, group };
|
|
194
196
|
}
|
|
@@ -517,8 +519,8 @@ export function setupTestNode(
|
|
|
517
519
|
connectToSyncServer();
|
|
518
520
|
}
|
|
519
521
|
|
|
520
|
-
onTestFinished(() => {
|
|
521
|
-
node.gracefulShutdown();
|
|
522
|
+
onTestFinished(async () => {
|
|
523
|
+
await node.gracefulShutdown();
|
|
522
524
|
});
|
|
523
525
|
|
|
524
526
|
const ctx = {
|
|
@@ -526,8 +528,8 @@ export function setupTestNode(
|
|
|
526
528
|
connectToSyncServer,
|
|
527
529
|
addStorage,
|
|
528
530
|
addAsyncStorage,
|
|
529
|
-
restart: () => {
|
|
530
|
-
node.gracefulShutdown();
|
|
531
|
+
restart: async () => {
|
|
532
|
+
await node.gracefulShutdown();
|
|
531
533
|
ctx.node = node = new LocalNode(
|
|
532
534
|
admin.agentSecret,
|
|
533
535
|
session,
|
|
@@ -811,3 +813,80 @@ export function fillCoMapWithLargeData(map: RawCoMap) {
|
|
|
811
813
|
|
|
812
814
|
return map;
|
|
813
815
|
}
|
|
816
|
+
|
|
817
|
+
// ============================================================================
|
|
818
|
+
// MessageChannel Test Helpers
|
|
819
|
+
// ============================================================================
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Type guard to check if a message is a SyncMessage.
|
|
823
|
+
*/
|
|
824
|
+
export function isSyncMessage(msg: unknown): msg is SyncMessage {
|
|
825
|
+
return (
|
|
826
|
+
typeof msg === "object" &&
|
|
827
|
+
msg !== null &&
|
|
828
|
+
"action" in msg &&
|
|
829
|
+
typeof (msg as { action: unknown }).action === "string"
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* Creates a MessageChannel that logs all sync messages exchanged between ports.
|
|
835
|
+
* Similar to connectedPeersWithMessagesTracking but for MessageChannel.
|
|
836
|
+
*/
|
|
837
|
+
export function createTrackedMessageChannel(opts: {
|
|
838
|
+
port1Name?: string;
|
|
839
|
+
port2Name?: string;
|
|
840
|
+
}) {
|
|
841
|
+
const { port1, port2 } = new MessageChannel();
|
|
842
|
+
const port1Name = opts.port1Name ?? "port1";
|
|
843
|
+
const port2Name = opts.port2Name ?? "port2";
|
|
844
|
+
|
|
845
|
+
// Wrap port1.postMessage to log messages
|
|
846
|
+
const originalPort1PostMessage = port1.postMessage.bind(port1);
|
|
847
|
+
port1.postMessage = (message, transfer) => {
|
|
848
|
+
if (isSyncMessage(message)) {
|
|
849
|
+
SyncMessagesLog.add({
|
|
850
|
+
from: port1Name,
|
|
851
|
+
to: port2Name,
|
|
852
|
+
msg: message,
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
originalPort1PostMessage(message, transfer);
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
// Wrap port2.postMessage to log messages
|
|
860
|
+
const originalPort2PostMessage = port2.postMessage.bind(port2);
|
|
861
|
+
port2.postMessage = (message, transfer) => {
|
|
862
|
+
if (isSyncMessage(message)) {
|
|
863
|
+
SyncMessagesLog.add({
|
|
864
|
+
from: port2Name,
|
|
865
|
+
to: port1Name,
|
|
866
|
+
msg: message,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
originalPort2PostMessage(message, transfer);
|
|
871
|
+
};
|
|
872
|
+
|
|
873
|
+
return { port1, port2 };
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Creates a mock worker target that simulates receiving a port
|
|
878
|
+
* and calling a callback with the received port (simulating a connection handshake).
|
|
879
|
+
*/
|
|
880
|
+
export function createMockWorkerWithAccept(
|
|
881
|
+
onPortReceived: (port: MessagePortLike) => Promise<void>,
|
|
882
|
+
) {
|
|
883
|
+
return {
|
|
884
|
+
postMessage: vi.fn().mockImplementation((data, transfer) => {
|
|
885
|
+
if (data?.type === "jazz:port" && transfer?.[0]) {
|
|
886
|
+
const port = transfer[0] as MessagePortLike;
|
|
887
|
+
// Simulate the worker receiving the port and calling accept
|
|
888
|
+
onPortReceived(port);
|
|
889
|
+
}
|
|
890
|
+
}),
|
|
891
|
+
};
|
|
892
|
+
}
|