cojson 0.19.18 → 0.19.20

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 (124) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +9 -0
  3. package/dist/PeerState.d.ts.map +1 -1
  4. package/dist/SyncStateManager.d.ts +5 -2
  5. package/dist/SyncStateManager.d.ts.map +1 -1
  6. package/dist/SyncStateManager.js +49 -12
  7. package/dist/SyncStateManager.js.map +1 -1
  8. package/dist/UnsyncedCoValuesTracker.d.ts +81 -0
  9. package/dist/UnsyncedCoValuesTracker.d.ts.map +1 -0
  10. package/dist/UnsyncedCoValuesTracker.js +209 -0
  11. package/dist/UnsyncedCoValuesTracker.js.map +1 -0
  12. package/dist/config.d.ts +6 -0
  13. package/dist/config.d.ts.map +1 -1
  14. package/dist/config.js +10 -0
  15. package/dist/config.js.map +1 -1
  16. package/dist/exports.d.ts +11 -3
  17. package/dist/exports.d.ts.map +1 -1
  18. package/dist/exports.js +6 -1
  19. package/dist/exports.js.map +1 -1
  20. package/dist/localNode.d.ts +9 -5
  21. package/dist/localNode.d.ts.map +1 -1
  22. package/dist/localNode.js +12 -8
  23. package/dist/localNode.js.map +1 -1
  24. package/dist/queue/IncomingMessagesQueue.d.ts +6 -7
  25. package/dist/queue/IncomingMessagesQueue.d.ts.map +1 -1
  26. package/dist/queue/IncomingMessagesQueue.js +7 -30
  27. package/dist/queue/IncomingMessagesQueue.js.map +1 -1
  28. package/dist/queue/LinkedList.d.ts +1 -1
  29. package/dist/queue/LinkedList.d.ts.map +1 -1
  30. package/dist/queue/LinkedList.js.map +1 -1
  31. package/dist/queue/StorageStreamingQueue.d.ts +43 -0
  32. package/dist/queue/StorageStreamingQueue.d.ts.map +1 -0
  33. package/dist/queue/StorageStreamingQueue.js +70 -0
  34. package/dist/queue/StorageStreamingQueue.js.map +1 -0
  35. package/dist/storage/knownState.d.ts +1 -1
  36. package/dist/storage/knownState.js +4 -4
  37. package/dist/storage/sqlite/client.d.ts +8 -0
  38. package/dist/storage/sqlite/client.d.ts.map +1 -1
  39. package/dist/storage/sqlite/client.js +17 -0
  40. package/dist/storage/sqlite/client.js.map +1 -1
  41. package/dist/storage/sqlite/sqliteMigrations.d.ts.map +1 -1
  42. package/dist/storage/sqlite/sqliteMigrations.js +9 -0
  43. package/dist/storage/sqlite/sqliteMigrations.js.map +1 -1
  44. package/dist/storage/sqliteAsync/client.d.ts +8 -0
  45. package/dist/storage/sqliteAsync/client.d.ts.map +1 -1
  46. package/dist/storage/sqliteAsync/client.js +19 -0
  47. package/dist/storage/sqliteAsync/client.js.map +1 -1
  48. package/dist/storage/storageAsync.d.ts +9 -2
  49. package/dist/storage/storageAsync.d.ts.map +1 -1
  50. package/dist/storage/storageAsync.js +9 -0
  51. package/dist/storage/storageAsync.js.map +1 -1
  52. package/dist/storage/storageSync.d.ts +17 -4
  53. package/dist/storage/storageSync.d.ts.map +1 -1
  54. package/dist/storage/storageSync.js +67 -44
  55. package/dist/storage/storageSync.js.map +1 -1
  56. package/dist/storage/types.d.ts +35 -0
  57. package/dist/storage/types.d.ts.map +1 -1
  58. package/dist/sync.d.ts +38 -1
  59. package/dist/sync.d.ts.map +1 -1
  60. package/dist/sync.js +181 -7
  61. package/dist/sync.js.map +1 -1
  62. package/dist/tests/IncomingMessagesQueue.test.js +4 -150
  63. package/dist/tests/IncomingMessagesQueue.test.js.map +1 -1
  64. package/dist/tests/StorageStreamingQueue.test.d.ts +2 -0
  65. package/dist/tests/StorageStreamingQueue.test.d.ts.map +1 -0
  66. package/dist/tests/StorageStreamingQueue.test.js +213 -0
  67. package/dist/tests/StorageStreamingQueue.test.js.map +1 -0
  68. package/dist/tests/SyncManager.processQueues.test.d.ts +2 -0
  69. package/dist/tests/SyncManager.processQueues.test.d.ts.map +1 -0
  70. package/dist/tests/SyncManager.processQueues.test.js +208 -0
  71. package/dist/tests/SyncManager.processQueues.test.js.map +1 -0
  72. package/dist/tests/SyncStateManager.test.js +3 -3
  73. package/dist/tests/SyncStateManager.test.js.map +1 -1
  74. package/dist/tests/coValueCore.loadFromStorage.test.js +3 -0
  75. package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -1
  76. package/dist/tests/setup.d.ts +2 -0
  77. package/dist/tests/setup.d.ts.map +1 -0
  78. package/dist/tests/setup.js +4 -0
  79. package/dist/tests/setup.js.map +1 -0
  80. package/dist/tests/sync.garbageCollection.test.js.map +1 -1
  81. package/dist/tests/sync.mesh.test.js +19 -19
  82. package/dist/tests/sync.storage.test.js +176 -20
  83. package/dist/tests/sync.storage.test.js.map +1 -1
  84. package/dist/tests/sync.test.js +1 -1
  85. package/dist/tests/sync.test.js.map +1 -1
  86. package/dist/tests/sync.tracking.test.d.ts +2 -0
  87. package/dist/tests/sync.tracking.test.d.ts.map +1 -0
  88. package/dist/tests/sync.tracking.test.js +261 -0
  89. package/dist/tests/sync.tracking.test.js.map +1 -0
  90. package/dist/tests/testUtils.d.ts +4 -3
  91. package/dist/tests/testUtils.d.ts.map +1 -1
  92. package/dist/tests/testUtils.js +4 -4
  93. package/dist/tests/testUtils.js.map +1 -1
  94. package/package.json +4 -4
  95. package/src/PeerState.ts +2 -2
  96. package/src/SyncStateManager.ts +63 -12
  97. package/src/UnsyncedCoValuesTracker.ts +272 -0
  98. package/src/config.ts +13 -0
  99. package/src/exports.ts +10 -1
  100. package/src/localNode.ts +15 -3
  101. package/src/queue/IncomingMessagesQueue.ts +7 -39
  102. package/src/queue/LinkedList.ts +1 -1
  103. package/src/queue/StorageStreamingQueue.ts +96 -0
  104. package/src/storage/knownState.ts +4 -4
  105. package/src/storage/sqlite/client.ts +31 -0
  106. package/src/storage/sqlite/sqliteMigrations.ts +9 -0
  107. package/src/storage/sqliteAsync/client.ts +35 -0
  108. package/src/storage/storageAsync.ts +18 -1
  109. package/src/storage/storageSync.ts +119 -56
  110. package/src/storage/types.ts +42 -0
  111. package/src/sync.ts +235 -8
  112. package/src/tests/IncomingMessagesQueue.test.ts +4 -206
  113. package/src/tests/StorageStreamingQueue.test.ts +276 -0
  114. package/src/tests/SyncManager.processQueues.test.ts +287 -0
  115. package/src/tests/SyncStateManager.test.ts +3 -0
  116. package/src/tests/coValueCore.loadFromStorage.test.ts +11 -0
  117. package/src/tests/setup.ts +4 -0
  118. package/src/tests/sync.garbageCollection.test.ts +1 -3
  119. package/src/tests/sync.mesh.test.ts +19 -19
  120. package/src/tests/sync.storage.test.ts +224 -32
  121. package/src/tests/sync.test.ts +1 -9
  122. package/src/tests/sync.tracking.test.ts +396 -0
  123. package/src/tests/testUtils.ts +11 -5
  124. package/vitest.config.ts +1 -0
@@ -31,6 +31,15 @@ export const migrations: Record<number, string[]> = {
31
31
  ) WITHOUT ROWID;`,
32
32
  "ALTER TABLE sessions ADD COLUMN bytesSinceLastSignature INTEGER;",
33
33
  ],
34
+ 4: [
35
+ `CREATE TABLE IF NOT EXISTS unsynced_covalues (
36
+ rowID INTEGER PRIMARY KEY,
37
+ co_value_id TEXT NOT NULL,
38
+ peer_id TEXT NOT NULL,
39
+ UNIQUE (co_value_id, peer_id)
40
+ );`,
41
+ "CREATE INDEX IF NOT EXISTS idx_unsynced_covalues_co_value_id ON unsynced_covalues(co_value_id);",
42
+ ],
34
43
  };
35
44
 
36
45
  type Migration = {
@@ -15,6 +15,7 @@ import type {
15
15
  TransactionRow,
16
16
  } from "../types.js";
17
17
  import type { SQLiteDatabaseDriverAsync } from "./types.js";
18
+ import type { PeerID } from "../../sync.js";
18
19
 
19
20
  export type RawCoValueRow = {
20
21
  id: RawCoID;
@@ -201,4 +202,38 @@ export class SQLiteClientAsync
201
202
  ) {
202
203
  return this.db.transaction(() => operationsCallback(this));
203
204
  }
205
+
206
+ async getUnsyncedCoValueIDs(): Promise<RawCoID[]> {
207
+ const rows = await this.db.query<{ co_value_id: RawCoID }>(
208
+ "SELECT DISTINCT co_value_id FROM unsynced_covalues",
209
+ [],
210
+ );
211
+ return rows.map((row) => row.co_value_id);
212
+ }
213
+
214
+ async trackCoValuesSyncState(
215
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
216
+ ): Promise<void> {
217
+ await Promise.all(
218
+ updates.map(async (update) => {
219
+ if (update.synced) {
220
+ await this.db.run(
221
+ "DELETE FROM unsynced_covalues WHERE co_value_id = ? AND peer_id = ?",
222
+ [update.id, update.peerId],
223
+ );
224
+ } else {
225
+ await this.db.run(
226
+ "INSERT OR REPLACE INTO unsynced_covalues (co_value_id, peer_id) VALUES (?, ?)",
227
+ [update.id, update.peerId],
228
+ );
229
+ }
230
+ }),
231
+ );
232
+ }
233
+
234
+ async stopTrackingSyncState(id: RawCoID): Promise<void> {
235
+ await this.db.run("DELETE FROM unsynced_covalues WHERE co_value_id = ?", [
236
+ id,
237
+ ]);
238
+ }
204
239
  }
@@ -10,7 +10,7 @@ import {
10
10
  logger,
11
11
  } from "../exports.js";
12
12
  import { StoreQueue } from "../queue/StoreQueue.js";
13
- import { NewContentMessage } from "../sync.js";
13
+ import { NewContentMessage, type PeerID } from "../sync.js";
14
14
  import {
15
15
  CoValueKnownState,
16
16
  emptyKnownState,
@@ -392,6 +392,23 @@ export class StorageApiAsync implements StorageAPI {
392
392
  return this.knownStates.waitForSync(id, coValue);
393
393
  }
394
394
 
395
+ trackCoValuesSyncState(
396
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
397
+ done?: () => void,
398
+ ): void {
399
+ this.dbClient.trackCoValuesSyncState(updates).then(() => done?.());
400
+ }
401
+
402
+ getUnsyncedCoValueIDs(
403
+ callback: (unsyncedCoValueIDs: RawCoID[]) => void,
404
+ ): void {
405
+ this.dbClient.getUnsyncedCoValueIDs().then(callback);
406
+ }
407
+
408
+ stopTrackingSyncState(id: RawCoID): void {
409
+ this.dbClient.stopTrackingSyncState(id);
410
+ }
411
+
395
412
  close() {
396
413
  return this.storeQueue.close();
397
414
  }
@@ -1,4 +1,3 @@
1
- import { UpDownCounter, metrics } from "@opentelemetry/api";
2
1
  import {
3
2
  createContentMessage,
4
3
  exceedsRecommendedSize,
@@ -10,7 +9,7 @@ import {
10
9
  type StorageAPI,
11
10
  logger,
12
11
  } from "../exports.js";
13
- import { NewContentMessage } from "../sync.js";
12
+ import { NewContentMessage, type PeerID } from "../sync.js";
14
13
  import { StorageKnownState } from "./knownState.js";
15
14
  import {
16
15
  CoValueKnownState,
@@ -30,22 +29,25 @@ import type {
30
29
  StoredCoValueRow,
31
30
  StoredSessionRow,
32
31
  } from "./types.js";
32
+ import {
33
+ ContentCallback,
34
+ StorageStreamingQueue,
35
+ } from "../queue/StorageStreamingQueue.js";
36
+ import { getPriorityFromHeader } from "../priority.js";
33
37
 
34
38
  export class StorageApiSync implements StorageAPI {
35
- private streamingCounter: UpDownCounter;
36
-
37
39
  private readonly dbClient: DBClientInterfaceSync;
38
40
  private loadedCoValues = new Set<RawCoID>();
39
41
 
42
+ /**
43
+ * Queue for streaming content that will be pulled by SyncManager.
44
+ * Only used when content requires streaming (multiple chunks).
45
+ */
46
+ readonly streamingQueue: StorageStreamingQueue;
47
+
40
48
  constructor(dbClient: DBClientInterfaceSync) {
41
49
  this.dbClient = dbClient;
42
- this.streamingCounter = metrics
43
- .getMeter("cojson")
44
- .createUpDownCounter(`jazz.storage.streaming`, {
45
- description: "Number of streaming coValues",
46
- unit: "1",
47
- });
48
- this.streamingCounter.add(0);
50
+ this.streamingQueue = new StorageStreamingQueue();
49
51
  }
50
52
 
51
53
  knownStates = new StorageKnownState();
@@ -62,7 +64,7 @@ export class StorageApiSync implements StorageAPI {
62
64
  await this.loadCoValue(id, callback, done);
63
65
  }
64
66
 
65
- async loadCoValue(
67
+ loadCoValue(
66
68
  id: string,
67
69
  callback: (data: NewContentMessage) => void,
68
70
  done?: (found: boolean) => void,
@@ -89,8 +91,18 @@ export class StorageApiSync implements StorageAPI {
89
91
 
90
92
  if (signatures.length > 0) {
91
93
  contentStreaming = true;
92
- signaturesBySession.set(sessionRow.sessionID, signatures);
93
94
  }
95
+
96
+ const lastSignature = signatures[signatures.length - 1];
97
+
98
+ if (lastSignature?.signature !== sessionRow.lastSignature) {
99
+ signatures.push({
100
+ idx: sessionRow.lastIdx,
101
+ signature: sessionRow.lastSignature,
102
+ });
103
+ }
104
+
105
+ signaturesBySession.set(sessionRow.sessionID, signatures);
94
106
  }
95
107
 
96
108
  const knownState = this.knownStates.getKnownState(coValueRow.id);
@@ -106,78 +118,110 @@ export class StorageApiSync implements StorageAPI {
106
118
 
107
119
  this.loadedCoValues.add(coValueRow.id);
108
120
 
109
- let contentMessage = createContentMessage(coValueRow.id, coValueRow.header);
121
+ const priority = getPriorityFromHeader(coValueRow.header);
122
+ const contentMessage = createContentMessage(
123
+ coValueRow.id,
124
+ coValueRow.header,
125
+ );
110
126
 
111
127
  if (contentStreaming) {
112
- this.streamingCounter.add(1);
113
128
  contentMessage.expectContentUntil = knownState.sessions;
114
129
  }
115
130
 
131
+ const streamingQueue: ContentCallback[] = [];
132
+
116
133
  for (const sessionRow of allCoValueSessions) {
117
- const signatures = signaturesBySession.get(sessionRow.sessionID) || [];
134
+ const signatures = signaturesBySession.get(sessionRow.sessionID);
118
135
 
119
- let idx = 0;
136
+ if (!signatures) {
137
+ throw new Error("Signatures not found for session");
138
+ }
120
139
 
121
- const lastSignature = signatures[signatures.length - 1];
140
+ const firstSignature = signatures[0];
122
141
 
123
- if (lastSignature?.signature !== sessionRow.lastSignature) {
124
- signatures.push({
125
- idx: sessionRow.lastIdx,
126
- signature: sessionRow.lastSignature,
127
- });
142
+ if (!firstSignature) {
143
+ continue;
128
144
  }
129
145
 
130
- for (const signature of signatures) {
131
- const newTxsInSession = this.dbClient.getNewTransactionInSession(
132
- sessionRow.rowID,
133
- idx,
134
- signature.idx,
135
- );
146
+ this.loadSessionTransactions(
147
+ contentMessage,
148
+ sessionRow,
149
+ 0,
150
+ firstSignature,
151
+ );
136
152
 
137
- collectNewTxs({
138
- newTxsInSession,
139
- contentMessage,
140
- sessionRow,
141
- firstNewTxIdx: idx,
142
- signature: signature.signature,
143
- });
153
+ for (let i = 1; i < signatures.length; i++) {
154
+ const prevSignature = signatures[i - 1];
144
155
 
145
- idx = signature.idx + 1;
156
+ if (!prevSignature) {
157
+ throw new Error("Previous signature is nullish");
158
+ }
146
159
 
147
- if (signatures.length > 1) {
148
- this.pushContentWithDependencies(
149
- coValueRow,
150
- contentMessage,
151
- callback,
152
- );
153
- contentMessage = createContentMessage(
160
+ streamingQueue.push(() => {
161
+ const contentMessage = createContentMessage(
154
162
  coValueRow.id,
155
163
  coValueRow.header,
156
164
  );
157
165
 
158
- // Introduce a delay to not block the main thread
159
- // for the entire content processing
160
- await new Promise((resolve) => setTimeout(resolve));
161
- }
166
+ const signature = signatures[i];
167
+ if (!signature) throw new Error("Signature item is nullish");
168
+
169
+ this.loadSessionTransactions(
170
+ contentMessage,
171
+ sessionRow,
172
+ prevSignature.idx + 1,
173
+ signature,
174
+ );
175
+
176
+ if (Object.keys(contentMessage.new).length > 0) {
177
+ this.pushContentWithDependencies(
178
+ coValueRow,
179
+ contentMessage,
180
+ callback,
181
+ );
182
+ }
183
+ });
162
184
  }
163
185
  }
164
186
 
165
- const hasNewContent = Object.keys(contentMessage.new).length > 0;
187
+ // Send the first chunk
188
+ this.pushContentWithDependencies(coValueRow, contentMessage, callback);
189
+ this.knownStates.handleUpdate(coValueRow.id, knownState);
166
190
 
167
- // If there is no new content but steaming is not active, it's the case for a coValue with the header but no transactions
168
- // For streaming the push has already been done in the loop above
169
- if (hasNewContent || !contentStreaming) {
170
- this.pushContentWithDependencies(coValueRow, contentMessage, callback);
191
+ // All priorities go through the queue (HIGH > MEDIUM > LOW)
192
+ for (const pushStreamingContent of streamingQueue) {
193
+ this.streamingQueue.push(pushStreamingContent, priority);
171
194
  }
172
195
 
173
- if (contentStreaming) {
174
- this.streamingCounter.add(-1);
196
+ // Trigger the queue to process the entries
197
+ if (streamingQueue.length > 0) {
198
+ this.streamingQueue.emit();
175
199
  }
176
200
 
177
- this.knownStates.handleUpdate(coValueRow.id, knownState);
178
201
  done?.(true);
179
202
  }
180
203
 
204
+ private loadSessionTransactions(
205
+ contentMessage: NewContentMessage,
206
+ sessionRow: StoredSessionRow,
207
+ idx: number,
208
+ signature: Pick<SignatureAfterRow, "idx" | "signature">,
209
+ ) {
210
+ const newTxsInSession = this.dbClient.getNewTransactionInSession(
211
+ sessionRow.rowID,
212
+ idx,
213
+ signature.idx,
214
+ );
215
+
216
+ collectNewTxs({
217
+ newTxsInSession,
218
+ contentMessage,
219
+ sessionRow,
220
+ firstNewTxIdx: idx,
221
+ signature: signature.signature,
222
+ });
223
+ }
224
+
181
225
  async pushContentWithDependencies(
182
226
  coValueRow: StoredCoValueRow,
183
227
  contentMessage: NewContentMessage,
@@ -365,6 +409,25 @@ export class StorageApiSync implements StorageAPI {
365
409
  return this.knownStates.waitForSync(id, coValue);
366
410
  }
367
411
 
412
+ trackCoValuesSyncState(
413
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
414
+ done?: () => void,
415
+ ): void {
416
+ this.dbClient.trackCoValuesSyncState(updates);
417
+ done?.();
418
+ }
419
+
420
+ getUnsyncedCoValueIDs(
421
+ callback: (unsyncedCoValueIDs: RawCoID[]) => void,
422
+ ): void {
423
+ const ids = this.dbClient.getUnsyncedCoValueIDs();
424
+ callback(ids);
425
+ }
426
+
427
+ stopTrackingSyncState(id: RawCoID): void {
428
+ this.dbClient.stopTrackingSyncState(id);
429
+ }
430
+
368
431
  close() {
369
432
  return undefined;
370
433
  }
@@ -5,7 +5,9 @@ import type {
5
5
  import { Signature } from "../crypto/crypto.js";
6
6
  import type { CoValueCore, RawCoID, SessionID } from "../exports.js";
7
7
  import { NewContentMessage } from "../sync.js";
8
+ import type { PeerID } from "../sync.js";
8
9
  import { CoValueKnownState } from "../knownState.js";
10
+ import { StorageStreamingQueue } from "../queue/StorageStreamingQueue.js";
9
11
 
10
12
  export type CorrectionCallback = (
11
13
  correction: CoValueKnownState,
@@ -25,10 +27,34 @@ export interface StorageAPI {
25
27
  ): void;
26
28
  store(data: NewContentMessage, handleCorrection: CorrectionCallback): void;
27
29
 
30
+ streamingQueue?: StorageStreamingQueue;
31
+
28
32
  getKnownState(id: string): CoValueKnownState;
29
33
 
30
34
  waitForSync(id: string, coValue: CoValueCore): Promise<void>;
31
35
 
36
+ /**
37
+ * Track multiple sync status updates.
38
+ * Does not guarantee the updates will be applied in order, so only one
39
+ * update per CoValue ID + Peer ID combination should be tracked at a time.
40
+ */
41
+ trackCoValuesSyncState(
42
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
43
+ done?: () => void,
44
+ ): void;
45
+
46
+ /**
47
+ * Get all CoValue IDs that have at least one unsynced peer.
48
+ */
49
+ getUnsyncedCoValueIDs(
50
+ callback: (unsyncedCoValueIDs: RawCoID[]) => void,
51
+ ): void;
52
+
53
+ /**
54
+ * Stop tracking sync status for a CoValue (remove all peer entries).
55
+ */
56
+ stopTrackingSyncState(id: RawCoID): void;
57
+
32
58
  close(): Promise<unknown> | undefined;
33
59
  }
34
60
 
@@ -118,6 +144,14 @@ export interface DBClientInterfaceAsync {
118
144
  transaction(
119
145
  callback: (tx: DBTransactionInterfaceAsync) => Promise<unknown>,
120
146
  ): Promise<unknown>;
147
+
148
+ trackCoValuesSyncState(
149
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
150
+ ): Promise<void>;
151
+
152
+ getUnsyncedCoValueIDs(): Promise<RawCoID[]>;
153
+
154
+ stopTrackingSyncState(id: RawCoID): Promise<void>;
121
155
  }
122
156
 
123
157
  export interface DBTransactionInterfaceSync {
@@ -170,4 +204,12 @@ export interface DBClientInterfaceSync {
170
204
  ): Pick<SignatureAfterRow, "idx" | "signature">[];
171
205
 
172
206
  transaction(callback: (tx: DBTransactionInterfaceSync) => unknown): unknown;
207
+
208
+ trackCoValuesSyncState(
209
+ updates: { id: RawCoID; peerId: PeerID; synced: boolean }[],
210
+ ): void;
211
+
212
+ getUnsyncedCoValueIDs(): RawCoID[];
213
+
214
+ stopTrackingSyncState(id: RawCoID): void;
173
215
  }