cojson 0.19.20 → 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.
Files changed (159) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +13 -0
  3. package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts +42 -0
  4. package/dist/CojsonMessageChannel/CojsonMessageChannel.d.ts.map +1 -0
  5. package/dist/CojsonMessageChannel/CojsonMessageChannel.js +261 -0
  6. package/dist/CojsonMessageChannel/CojsonMessageChannel.js.map +1 -0
  7. package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts +18 -0
  8. package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.d.ts.map +1 -0
  9. package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js +37 -0
  10. package/dist/CojsonMessageChannel/MessagePortOutgoingChannel.js.map +1 -0
  11. package/dist/CojsonMessageChannel/index.d.ts +3 -0
  12. package/dist/CojsonMessageChannel/index.d.ts.map +1 -0
  13. package/dist/CojsonMessageChannel/index.js +2 -0
  14. package/dist/CojsonMessageChannel/index.js.map +1 -0
  15. package/dist/CojsonMessageChannel/types.d.ts +149 -0
  16. package/dist/CojsonMessageChannel/types.d.ts.map +1 -0
  17. package/dist/CojsonMessageChannel/types.js +36 -0
  18. package/dist/CojsonMessageChannel/types.js.map +1 -0
  19. package/dist/GarbageCollector.d.ts +4 -2
  20. package/dist/GarbageCollector.d.ts.map +1 -1
  21. package/dist/GarbageCollector.js +5 -3
  22. package/dist/GarbageCollector.js.map +1 -1
  23. package/dist/SyncStateManager.d.ts +3 -3
  24. package/dist/SyncStateManager.d.ts.map +1 -1
  25. package/dist/SyncStateManager.js +4 -4
  26. package/dist/SyncStateManager.js.map +1 -1
  27. package/dist/coValueCore/coValueCore.d.ts +28 -1
  28. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  29. package/dist/coValueCore/coValueCore.js +50 -5
  30. package/dist/coValueCore/coValueCore.js.map +1 -1
  31. package/dist/coValues/account.d.ts.map +1 -1
  32. package/dist/coValues/account.js +10 -10
  33. package/dist/coValues/account.js.map +1 -1
  34. package/dist/exports.d.ts +1 -0
  35. package/dist/exports.d.ts.map +1 -1
  36. package/dist/exports.js +1 -0
  37. package/dist/exports.js.map +1 -1
  38. package/dist/ids.d.ts +1 -1
  39. package/dist/ids.d.ts.map +1 -1
  40. package/dist/ids.js.map +1 -1
  41. package/dist/knownState.d.ts +5 -0
  42. package/dist/knownState.d.ts.map +1 -1
  43. package/dist/knownState.js +15 -0
  44. package/dist/knownState.js.map +1 -1
  45. package/dist/localNode.d.ts +1 -3
  46. package/dist/localNode.d.ts.map +1 -1
  47. package/dist/localNode.js +11 -4
  48. package/dist/localNode.js.map +1 -1
  49. package/dist/storage/knownState.d.ts +5 -0
  50. package/dist/storage/knownState.d.ts.map +1 -1
  51. package/dist/storage/knownState.js +11 -0
  52. package/dist/storage/knownState.js.map +1 -1
  53. package/dist/storage/sqlite/client.d.ts +2 -0
  54. package/dist/storage/sqlite/client.d.ts.map +1 -1
  55. package/dist/storage/sqlite/client.js +18 -0
  56. package/dist/storage/sqlite/client.js.map +1 -1
  57. package/dist/storage/sqliteAsync/client.d.ts +2 -0
  58. package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
  59. package/dist/storage/sqliteAsync/client.js +20 -0
  60. package/dist/storage/sqliteAsync/client.js.map +1 -1
  61. package/dist/storage/storageAsync.d.ts +10 -3
  62. package/dist/storage/storageAsync.d.ts.map +1 -1
  63. package/dist/storage/storageAsync.js +52 -3
  64. package/dist/storage/storageAsync.js.map +1 -1
  65. package/dist/storage/storageSync.d.ts +9 -3
  66. package/dist/storage/storageSync.d.ts.map +1 -1
  67. package/dist/storage/storageSync.js +27 -3
  68. package/dist/storage/storageSync.js.map +1 -1
  69. package/dist/storage/types.d.ts +23 -0
  70. package/dist/storage/types.d.ts.map +1 -1
  71. package/dist/sync.d.ts +23 -0
  72. package/dist/sync.d.ts.map +1 -1
  73. package/dist/sync.js +136 -45
  74. package/dist/sync.js.map +1 -1
  75. package/dist/tests/CojsonMessageChannel.test.d.ts +2 -0
  76. package/dist/tests/CojsonMessageChannel.test.d.ts.map +1 -0
  77. package/dist/tests/CojsonMessageChannel.test.js +236 -0
  78. package/dist/tests/CojsonMessageChannel.test.js.map +1 -0
  79. package/dist/tests/GarbageCollector.test.js +87 -13
  80. package/dist/tests/GarbageCollector.test.js.map +1 -1
  81. package/dist/tests/StorageApiAsync.test.js +124 -1
  82. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  83. package/dist/tests/StorageApiSync.test.js +123 -0
  84. package/dist/tests/StorageApiSync.test.js.map +1 -1
  85. package/dist/tests/SyncManager.processQueues.test.js +1 -1
  86. package/dist/tests/SyncManager.processQueues.test.js.map +1 -1
  87. package/dist/tests/SyncStateManager.test.js +1 -1
  88. package/dist/tests/SyncStateManager.test.js.map +1 -1
  89. package/dist/tests/coPlainText.test.js +1 -1
  90. package/dist/tests/coPlainText.test.js.map +1 -1
  91. package/dist/tests/coValueCore.loadFromStorage.test.js +2 -0
  92. package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
  93. package/dist/tests/knownState.lazyLoading.test.d.ts +2 -0
  94. package/dist/tests/knownState.lazyLoading.test.d.ts.map +1 -0
  95. package/dist/tests/knownState.lazyLoading.test.js +167 -0
  96. package/dist/tests/knownState.lazyLoading.test.js.map +1 -0
  97. package/dist/tests/messagesTestUtils.d.ts +5 -2
  98. package/dist/tests/messagesTestUtils.d.ts.map +1 -1
  99. package/dist/tests/messagesTestUtils.js +4 -0
  100. package/dist/tests/messagesTestUtils.js.map +1 -1
  101. package/dist/tests/sync.garbageCollection.test.js +56 -32
  102. package/dist/tests/sync.garbageCollection.test.js.map +1 -1
  103. package/dist/tests/sync.load.test.js +387 -1
  104. package/dist/tests/sync.load.test.js.map +1 -1
  105. package/dist/tests/sync.mesh.test.js +5 -5
  106. package/dist/tests/sync.mesh.test.js.map +1 -1
  107. package/dist/tests/sync.peerReconciliation.test.js +3 -3
  108. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  109. package/dist/tests/sync.storage.test.js +9 -9
  110. package/dist/tests/sync.storage.test.js.map +1 -1
  111. package/dist/tests/sync.storageAsync.test.js +7 -7
  112. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  113. package/dist/tests/sync.tracking.test.js +35 -4
  114. package/dist/tests/sync.tracking.test.js.map +1 -1
  115. package/dist/tests/testStorage.js +38 -2
  116. package/dist/tests/testStorage.js.map +1 -1
  117. package/dist/tests/testUtils.d.ts +38 -4
  118. package/dist/tests/testUtils.d.ts.map +1 -1
  119. package/dist/tests/testUtils.js +68 -7
  120. package/dist/tests/testUtils.js.map +1 -1
  121. package/package.json +4 -4
  122. package/src/CojsonMessageChannel/CojsonMessageChannel.ts +332 -0
  123. package/src/CojsonMessageChannel/MessagePortOutgoingChannel.ts +52 -0
  124. package/src/CojsonMessageChannel/index.ts +9 -0
  125. package/src/CojsonMessageChannel/types.ts +200 -0
  126. package/src/GarbageCollector.ts +5 -5
  127. package/src/SyncStateManager.ts +6 -6
  128. package/src/coValueCore/coValueCore.ts +56 -7
  129. package/src/coValues/account.ts +12 -14
  130. package/src/exports.ts +1 -0
  131. package/src/ids.ts +1 -1
  132. package/src/knownState.ts +24 -0
  133. package/src/localNode.ts +12 -7
  134. package/src/storage/knownState.ts +12 -0
  135. package/src/storage/sqlite/client.ts +31 -0
  136. package/src/storage/sqliteAsync/client.ts +35 -0
  137. package/src/storage/storageAsync.ts +66 -4
  138. package/src/storage/storageSync.ts +37 -4
  139. package/src/storage/types.ts +32 -0
  140. package/src/sync.ts +159 -46
  141. package/src/tests/CojsonMessageChannel.test.ts +306 -0
  142. package/src/tests/GarbageCollector.test.ts +114 -13
  143. package/src/tests/StorageApiAsync.test.ts +186 -1
  144. package/src/tests/StorageApiSync.test.ts +181 -0
  145. package/src/tests/SyncManager.processQueues.test.ts +1 -1
  146. package/src/tests/SyncStateManager.test.ts +1 -1
  147. package/src/tests/coPlainText.test.ts +1 -1
  148. package/src/tests/coValueCore.loadFromStorage.test.ts +5 -0
  149. package/src/tests/knownState.lazyLoading.test.ts +219 -0
  150. package/src/tests/messagesTestUtils.ts +10 -3
  151. package/src/tests/sync.garbageCollection.test.ts +69 -36
  152. package/src/tests/sync.load.test.ts +482 -2
  153. package/src/tests/sync.mesh.test.ts +5 -5
  154. package/src/tests/sync.peerReconciliation.test.ts +3 -3
  155. package/src/tests/sync.storage.test.ts +9 -9
  156. package/src/tests/sync.storageAsync.test.ts +7 -7
  157. package/src/tests/sync.tracking.test.ts +54 -4
  158. package/src/tests/testStorage.ts +40 -2
  159. package/src/tests/testUtils.ts +99 -8
@@ -0,0 +1,219 @@
1
+ import { beforeEach, describe, expect, test, vi } from "vitest";
2
+ import { RawCoID, SessionID } from "../ids";
3
+ import { PeerID } from "../sync";
4
+ import { StorageAPI } from "../storage/types";
5
+ import { CoValueKnownState, peerHasAllContent } from "../knownState";
6
+ import { createTestNode, createUnloadedCoValue } from "./testUtils";
7
+
8
+ function createMockStorage(
9
+ opts: {
10
+ load?: (
11
+ id: RawCoID,
12
+ callback: (data: any) => void,
13
+ done: (found: boolean) => void,
14
+ ) => void;
15
+ store?: (data: any, correctionCallback: any) => void;
16
+ getKnownState?: (id: RawCoID) => any;
17
+ loadKnownState?: (id: string, callback: (knownState: any) => void) => void;
18
+ waitForSync?: (id: string, coValue: any) => Promise<void>;
19
+ trackCoValuesSyncState?: (
20
+ operations: Array<{ id: RawCoID; peerId: PeerID; synced: boolean }>,
21
+ ) => void;
22
+ getUnsyncedCoValueIDs?: (
23
+ callback: (unsyncedCoValueIDs: RawCoID[]) => void,
24
+ ) => void;
25
+ stopTrackingSyncState?: (id: RawCoID) => void;
26
+ onCoValueUnmounted?: (id: RawCoID) => void;
27
+ close?: () => Promise<unknown> | undefined;
28
+ } = {},
29
+ ): StorageAPI {
30
+ return {
31
+ load: opts.load || vi.fn(),
32
+ store: opts.store || vi.fn(),
33
+ getKnownState: opts.getKnownState || vi.fn(),
34
+ loadKnownState:
35
+ opts.loadKnownState || vi.fn((id, callback) => callback(undefined)),
36
+ waitForSync: opts.waitForSync || vi.fn().mockResolvedValue(undefined),
37
+ trackCoValuesSyncState: opts.trackCoValuesSyncState || vi.fn(),
38
+ getUnsyncedCoValueIDs: opts.getUnsyncedCoValueIDs || vi.fn(),
39
+ stopTrackingSyncState: opts.stopTrackingSyncState || vi.fn(),
40
+ onCoValueUnmounted: opts.onCoValueUnmounted || vi.fn(),
41
+ close: opts.close || vi.fn().mockResolvedValue(undefined),
42
+ };
43
+ }
44
+
45
+ describe("peerHasAllContent", () => {
46
+ const storageKnownState: CoValueKnownState = {
47
+ id: "co_test123" as RawCoID,
48
+ header: true,
49
+ sessions: {
50
+ ["session1" as SessionID]: 5,
51
+ ["session2" as SessionID]: 3,
52
+ },
53
+ };
54
+
55
+ test("returns false when peerKnownState is undefined", () => {
56
+ expect(peerHasAllContent(storageKnownState, undefined)).toBe(false);
57
+ });
58
+
59
+ test("returns false when peer does not have header but storage does", () => {
60
+ const peerKnownState: CoValueKnownState = {
61
+ id: "co_test123" as RawCoID,
62
+ header: false,
63
+ sessions: {
64
+ ["session1" as SessionID]: 5,
65
+ ["session2" as SessionID]: 3,
66
+ },
67
+ };
68
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(false);
69
+ });
70
+
71
+ test("returns false when peer has fewer transactions in a session", () => {
72
+ const peerKnownState: CoValueKnownState = {
73
+ id: "co_test123" as RawCoID,
74
+ header: true,
75
+ sessions: {
76
+ ["session1" as SessionID]: 3, // Less than storage's 5
77
+ ["session2" as SessionID]: 3,
78
+ },
79
+ };
80
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(false);
81
+ });
82
+
83
+ test("returns false when peer is missing a session", () => {
84
+ const peerKnownState: CoValueKnownState = {
85
+ id: "co_test123" as RawCoID,
86
+ header: true,
87
+ sessions: {
88
+ ["session1" as SessionID]: 5,
89
+ // session2 is missing
90
+ },
91
+ };
92
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(false);
93
+ });
94
+
95
+ test("returns true when peer has exactly the same content", () => {
96
+ const peerKnownState: CoValueKnownState = {
97
+ id: "co_test123" as RawCoID,
98
+ header: true,
99
+ sessions: {
100
+ ["session1" as SessionID]: 5,
101
+ ["session2" as SessionID]: 3,
102
+ },
103
+ };
104
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(true);
105
+ });
106
+
107
+ test("returns true when peer has more transactions than storage", () => {
108
+ const peerKnownState: CoValueKnownState = {
109
+ id: "co_test123" as RawCoID,
110
+ header: true,
111
+ sessions: {
112
+ ["session1" as SessionID]: 10, // More than storage's 5
113
+ ["session2" as SessionID]: 5, // More than storage's 3
114
+ },
115
+ };
116
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(true);
117
+ });
118
+
119
+ test("returns true when peer has additional sessions", () => {
120
+ const peerKnownState: CoValueKnownState = {
121
+ id: "co_test123" as RawCoID,
122
+ header: true,
123
+ sessions: {
124
+ ["session1" as SessionID]: 5,
125
+ ["session2" as SessionID]: 3,
126
+ ["session3" as SessionID]: 2, // Extra session not in storage
127
+ },
128
+ };
129
+ expect(peerHasAllContent(storageKnownState, peerKnownState)).toBe(true);
130
+ });
131
+
132
+ test("returns true when storage has empty sessions", () => {
133
+ const emptyStorageKnownState: CoValueKnownState = {
134
+ id: "co_test123" as RawCoID,
135
+ header: true,
136
+ sessions: {},
137
+ };
138
+ const peerKnownState: CoValueKnownState = {
139
+ id: "co_test123" as RawCoID,
140
+ header: true,
141
+ sessions: {},
142
+ };
143
+ expect(peerHasAllContent(emptyStorageKnownState, peerKnownState)).toBe(
144
+ true,
145
+ );
146
+ });
147
+ });
148
+
149
+ describe("CoValueCore.getKnownStateFromStorage", () => {
150
+ function setup() {
151
+ const node = createTestNode();
152
+ const { coValue, id, header } = createUnloadedCoValue(node);
153
+ return { node, coValue, id, header };
154
+ }
155
+
156
+ test("returns undefined when storage is not configured", () => {
157
+ const { coValue } = setup();
158
+ const doneSpy = vi.fn();
159
+
160
+ coValue.getKnownStateFromStorage(doneSpy);
161
+
162
+ expect(doneSpy).toHaveBeenCalledWith(undefined);
163
+ });
164
+
165
+ test("returns current knownState when CoValue is already available", () => {
166
+ const { node, coValue, header } = setup();
167
+ const storage = createMockStorage();
168
+ node.setStorage(storage);
169
+
170
+ // Make the CoValue available by providing header
171
+ coValue.provideHeader(header, undefined, false);
172
+
173
+ const doneSpy = vi.fn();
174
+ coValue.getKnownStateFromStorage(doneSpy);
175
+
176
+ expect(doneSpy).toHaveBeenCalledWith(
177
+ expect.objectContaining({
178
+ header: true,
179
+ }),
180
+ );
181
+ });
182
+
183
+ test("calls storage.loadKnownState when CoValue not in memory", () => {
184
+ const { node, coValue, id } = setup();
185
+ const loadKnownStateSpy = vi.fn((id, callback) => {
186
+ callback({
187
+ id,
188
+ header: true,
189
+ sessions: { session1: 5 },
190
+ });
191
+ });
192
+ const storage = createMockStorage({ loadKnownState: loadKnownStateSpy });
193
+ node.setStorage(storage);
194
+
195
+ const doneSpy = vi.fn();
196
+ coValue.getKnownStateFromStorage(doneSpy);
197
+
198
+ expect(loadKnownStateSpy).toHaveBeenCalledWith(id, expect.any(Function));
199
+ expect(doneSpy).toHaveBeenCalledWith({
200
+ id,
201
+ header: true,
202
+ sessions: { session1: 5 },
203
+ });
204
+ });
205
+
206
+ test("returns undefined when storage does not have the CoValue", () => {
207
+ const { node, coValue } = setup();
208
+ const loadKnownStateSpy = vi.fn((id, callback) => {
209
+ callback(undefined);
210
+ });
211
+ const storage = createMockStorage({ loadKnownState: loadKnownStateSpy });
212
+ node.setStorage(storage);
213
+
214
+ const doneSpy = vi.fn();
215
+ coValue.getKnownStateFromStorage(doneSpy);
216
+
217
+ expect(doneSpy).toHaveBeenCalledWith(undefined);
218
+ });
219
+ });
@@ -1,6 +1,7 @@
1
1
  import { CoValueCore, LocalNode } from "../exports";
2
2
  import { NewContentMessage, SyncMessage } from "../sync";
3
3
  import { CoValueKnownState } from "../knownState.js";
4
+ import { LazyLoadMessage, LazyLoadResultMessage } from "./testUtils.js";
4
5
 
5
6
  function simplifySessions(msg: Pick<CoValueKnownState, "sessions" | "header">) {
6
7
  const count = Object.values(msg.sessions).reduce(
@@ -25,12 +26,14 @@ function simplifyNewContent(content: NewContentMessage["new"]) {
25
26
  .join(" | ");
26
27
  }
27
28
 
29
+ type TestMessage = SyncMessage | LazyLoadMessage | LazyLoadResultMessage;
30
+
28
31
  export function toSimplifiedMessages(
29
32
  coValues: Record<string, CoValueCore>,
30
33
  messages: {
31
34
  from: string;
32
35
  to: string;
33
- msg: SyncMessage;
36
+ msg: TestMessage;
34
37
  }[],
35
38
  ) {
36
39
  function getCoValue(id: string) {
@@ -43,7 +46,7 @@ export function toSimplifiedMessages(
43
46
  return `unknown/${id}`;
44
47
  }
45
48
 
46
- function toDebugString(from: string, to: string, msg: SyncMessage) {
49
+ function toDebugString(from: string, to: string, msg: TestMessage) {
47
50
  switch (msg.action) {
48
51
  case "known":
49
52
  return `${from} -> ${to} | KNOWN ${msg.isCorrection ? "CORRECTION " : ""}${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
@@ -53,6 +56,10 @@ export function toSimplifiedMessages(
53
56
  return `${from} -> ${to} | DONE ${getCoValue(msg.id)}`;
54
57
  case "content":
55
58
  return `${from} -> ${to} | CONTENT ${getCoValue(msg.id)} header: ${Boolean(msg.header)} new: ${simplifyNewContent(msg.new)}${msg.expectContentUntil ? ` expectContentUntil: ${simplifySessions({ sessions: msg.expectContentUntil, header: true })}` : ""}`;
59
+ case "lazyLoad":
60
+ return `${from} -> ${to} | GET_KNOWN_STATE ${getCoValue(msg.id)}`;
61
+ case "lazyLoadResult":
62
+ return `${from} -> ${to} | GET_KNOWN_STATE_RESULT ${getCoValue(msg.id)} sessions: ${simplifySessions(msg)}`;
56
63
  }
57
64
  }
58
65
 
@@ -75,7 +82,7 @@ export function debugMessages(
75
82
  messages: {
76
83
  from: string;
77
84
  to: string;
78
- msg: SyncMessage;
85
+ msg: TestMessage;
79
86
  }[],
80
87
  ) {
81
88
  console.log(toSimplifiedMessages(coValues, messages));
@@ -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
- client.connectToSyncServer({
128
- syncServer: edge.node,
129
- syncServerName: "edge",
156
+ client.addStorage({
157
+ ourName: "client",
130
158
  });
159
+ client.node.enableGarbageCollector();
131
160
 
132
- const group = edge.node.createGroup();
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
- edge.node.garbageCollector?.collect();
143
- expect(edge.node.getCoValue(map.id).isAvailable()).toBe(false);
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 mapOnClient = await loadCoValueOrFail(client.node, map.id);
149
- expect(mapOnClient.get("hello")).toEqual("updated");
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 -> edge | LOAD Map sessions: empty",
159
- "edge -> storage | CONTENT Map header: true new: After: 0 New: 1",
160
- "edge -> server | CONTENT Map header: true new: After: 0 New: 1",
161
- "edge -> storage | LOAD Map sessions: empty",
162
- "storage -> edge | CONTENT Group header: true new: After: 0 New: 5",
163
- "storage -> edge | CONTENT Map header: true new: After: 0 New: 1",
164
- "edge -> client | CONTENT Group header: true new: After: 0 New: 5",
165
- "edge -> client | CONTENT Map header: true new: After: 0 New: 1",
166
- "server -> edge | KNOWN Map sessions: header/1",
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
  });