cojson 0.16.3 → 0.16.4

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 (113) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +7 -0
  3. package/dist/coValue.d.ts +1 -1
  4. package/dist/coValueContentMessage.d.ts +10 -0
  5. package/dist/coValueContentMessage.d.ts.map +1 -0
  6. package/dist/coValueContentMessage.js +46 -0
  7. package/dist/coValueContentMessage.js.map +1 -0
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +5 -3
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/verifiedState.d.ts +1 -0
  12. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  13. package/dist/coValueCore/verifiedState.js +14 -27
  14. package/dist/coValueCore/verifiedState.js.map +1 -1
  15. package/dist/coValues/group.d.ts.map +1 -1
  16. package/dist/coValues/group.js +16 -8
  17. package/dist/coValues/group.js.map +1 -1
  18. package/dist/localNode.d.ts +6 -1
  19. package/dist/localNode.d.ts.map +1 -1
  20. package/dist/localNode.js +7 -2
  21. package/dist/localNode.js.map +1 -1
  22. package/dist/queue/LocalTransactionsSyncQueue.d.ts +24 -0
  23. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -0
  24. package/dist/queue/LocalTransactionsSyncQueue.js +55 -0
  25. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -0
  26. package/dist/queue/StoreQueue.d.ts +9 -6
  27. package/dist/queue/StoreQueue.d.ts.map +1 -1
  28. package/dist/queue/StoreQueue.js +10 -2
  29. package/dist/queue/StoreQueue.js.map +1 -1
  30. package/dist/storage/storageAsync.d.ts +11 -3
  31. package/dist/storage/storageAsync.d.ts.map +1 -1
  32. package/dist/storage/storageAsync.js +59 -46
  33. package/dist/storage/storageAsync.js.map +1 -1
  34. package/dist/storage/storageSync.d.ts +9 -3
  35. package/dist/storage/storageSync.d.ts.map +1 -1
  36. package/dist/storage/storageSync.js +48 -35
  37. package/dist/storage/storageSync.js.map +1 -1
  38. package/dist/storage/syncUtils.d.ts +2 -1
  39. package/dist/storage/syncUtils.d.ts.map +1 -1
  40. package/dist/storage/syncUtils.js +4 -0
  41. package/dist/storage/syncUtils.js.map +1 -1
  42. package/dist/storage/types.d.ts +3 -2
  43. package/dist/storage/types.d.ts.map +1 -1
  44. package/dist/sync.d.ts +6 -6
  45. package/dist/sync.d.ts.map +1 -1
  46. package/dist/sync.js +33 -56
  47. package/dist/sync.js.map +1 -1
  48. package/dist/tests/StorageApiAsync.test.d.ts +2 -0
  49. package/dist/tests/StorageApiAsync.test.d.ts.map +1 -0
  50. package/dist/tests/StorageApiAsync.test.js +574 -0
  51. package/dist/tests/StorageApiAsync.test.js.map +1 -0
  52. package/dist/tests/StorageApiSync.test.d.ts +2 -0
  53. package/dist/tests/StorageApiSync.test.d.ts.map +1 -0
  54. package/dist/tests/StorageApiSync.test.js +426 -0
  55. package/dist/tests/StorageApiSync.test.js.map +1 -0
  56. package/dist/tests/StoreQueue.test.js +9 -21
  57. package/dist/tests/StoreQueue.test.js.map +1 -1
  58. package/dist/tests/SyncStateManager.test.js +18 -8
  59. package/dist/tests/SyncStateManager.test.js.map +1 -1
  60. package/dist/tests/group.inheritance.test.js +79 -2
  61. package/dist/tests/group.inheritance.test.js.map +1 -1
  62. package/dist/tests/sync.auth.test.js +22 -10
  63. package/dist/tests/sync.auth.test.js.map +1 -1
  64. package/dist/tests/sync.load.test.js +25 -23
  65. package/dist/tests/sync.load.test.js.map +1 -1
  66. package/dist/tests/sync.mesh.test.js +12 -6
  67. package/dist/tests/sync.mesh.test.js.map +1 -1
  68. package/dist/tests/sync.peerReconciliation.test.js +6 -4
  69. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  70. package/dist/tests/sync.storage.test.js +8 -14
  71. package/dist/tests/sync.storage.test.js.map +1 -1
  72. package/dist/tests/sync.storageAsync.test.js +31 -14
  73. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  74. package/dist/tests/sync.test.js +5 -9
  75. package/dist/tests/sync.test.js.map +1 -1
  76. package/dist/tests/sync.upload.test.js +31 -1
  77. package/dist/tests/sync.upload.test.js.map +1 -1
  78. package/dist/tests/testStorage.d.ts +2 -3
  79. package/dist/tests/testStorage.d.ts.map +1 -1
  80. package/dist/tests/testStorage.js +16 -8
  81. package/dist/tests/testStorage.js.map +1 -1
  82. package/dist/tests/testUtils.d.ts +3 -0
  83. package/dist/tests/testUtils.d.ts.map +1 -1
  84. package/dist/tests/testUtils.js +17 -4
  85. package/dist/tests/testUtils.js.map +1 -1
  86. package/package.json +1 -1
  87. package/src/coValueContentMessage.ts +73 -0
  88. package/src/coValueCore/coValueCore.ts +14 -5
  89. package/src/coValueCore/verifiedState.ts +28 -35
  90. package/src/coValues/group.ts +20 -9
  91. package/src/localNode.ts +8 -3
  92. package/src/queue/LocalTransactionsSyncQueue.ts +96 -0
  93. package/src/queue/StoreQueue.ts +22 -12
  94. package/src/storage/storageAsync.ts +78 -56
  95. package/src/storage/storageSync.ts +66 -45
  96. package/src/storage/syncUtils.ts +9 -1
  97. package/src/storage/types.ts +6 -5
  98. package/src/sync.ts +47 -67
  99. package/src/tests/StorageApiAsync.test.ts +829 -0
  100. package/src/tests/StorageApiSync.test.ts +628 -0
  101. package/src/tests/StoreQueue.test.ts +10 -24
  102. package/src/tests/SyncStateManager.test.ts +22 -21
  103. package/src/tests/group.inheritance.test.ts +136 -1
  104. package/src/tests/sync.auth.test.ts +22 -10
  105. package/src/tests/sync.load.test.ts +27 -24
  106. package/src/tests/sync.mesh.test.ts +12 -6
  107. package/src/tests/sync.peerReconciliation.test.ts +6 -4
  108. package/src/tests/sync.storage.test.ts +8 -14
  109. package/src/tests/sync.storageAsync.test.ts +39 -14
  110. package/src/tests/sync.test.ts +6 -14
  111. package/src/tests/sync.upload.test.ts +38 -1
  112. package/src/tests/testStorage.ts +19 -13
  113. package/src/tests/testUtils.ts +24 -5
@@ -1,20 +1,29 @@
1
1
  import { UpDownCounter, metrics } from "@opentelemetry/api";
2
+ import {
3
+ createContentMessage,
4
+ exceedsRecommendedSize,
5
+ getTransactionSize,
6
+ } from "../coValueContentMessage.js";
2
7
  import {
3
8
  CoValueCore,
4
- MAX_RECOMMENDED_TX_SIZE,
5
9
  RawCoID,
6
10
  type SessionID,
7
11
  type StorageAPI,
12
+ logger,
8
13
  } from "../exports.js";
9
- import { getPriorityFromHeader } from "../priority.js";
10
14
  import {
11
15
  CoValueKnownState,
12
16
  NewContentMessage,
13
17
  emptyKnownState,
14
18
  } from "../sync.js";
15
19
  import { StorageKnownState } from "./knownState.js";
16
- import { collectNewTxs, getDependedOnCoValues } from "./syncUtils.js";
20
+ import {
21
+ collectNewTxs,
22
+ getDependedOnCoValues,
23
+ getNewTransactionsSize,
24
+ } from "./syncUtils.js";
17
25
  import type {
26
+ CorrectionCallback,
18
27
  DBClientInterfaceSync,
19
28
  SignatureAfterRow,
20
29
  StoredCoValueRow,
@@ -84,6 +93,7 @@ export class StorageApiSync implements StorageAPI {
84
93
  }
85
94
 
86
95
  const knownState = this.knwonStates.getKnownState(coValueRow.id);
96
+ knownState.header = true;
87
97
 
88
98
  for (const sessionRow of allCoValueSessions) {
89
99
  knownState.sessions[sessionRow.sessionID] = sessionRow.lastIdx;
@@ -91,13 +101,7 @@ export class StorageApiSync implements StorageAPI {
91
101
 
92
102
  this.loadedCoValues.add(coValueRow.id);
93
103
 
94
- let contentMessage = {
95
- action: "content",
96
- id: coValueRow.id,
97
- header: coValueRow.header,
98
- new: {},
99
- priority: getPriorityFromHeader(coValueRow.header),
100
- } as NewContentMessage;
104
+ let contentMessage = createContentMessage(coValueRow.id, coValueRow.header);
101
105
 
102
106
  if (contentStreaming) {
103
107
  this.streamingCounter.add(1);
@@ -137,13 +141,10 @@ export class StorageApiSync implements StorageAPI {
137
141
  contentMessage,
138
142
  callback,
139
143
  );
140
- contentMessage = {
141
- action: "content",
142
- id: coValueRow.id,
143
- header: coValueRow.header,
144
- new: {},
145
- priority: getPriorityFromHeader(coValueRow.header),
146
- } satisfies NewContentMessage;
144
+ contentMessage = createContentMessage(
145
+ coValueRow.id,
146
+ coValueRow.header,
147
+ );
147
148
 
148
149
  // Introduce a delay to not block the main thread
149
150
  // for the entire content processing
@@ -189,22 +190,49 @@ export class StorageApiSync implements StorageAPI {
189
190
  pushCallback(contentMessage);
190
191
  }
191
192
 
192
- store(
193
- msgs: NewContentMessage[],
194
- correctionCallback: (data: CoValueKnownState) => void,
193
+ store(msg: NewContentMessage, correctionCallback: CorrectionCallback) {
194
+ return this.storeSingle(msg, correctionCallback);
195
+ }
196
+
197
+ /**
198
+ * This function is called when the storage lacks the information required to store the incoming content.
199
+ *
200
+ * It triggers a `correctionCallback` to ask the syncManager to provide the missing information.
201
+ */
202
+ private handleCorrection(
203
+ knownState: CoValueKnownState,
204
+ correctionCallback: CorrectionCallback,
195
205
  ) {
196
- for (const msg of msgs) {
197
- const success = this.storeSingle(msg, correctionCallback);
206
+ const correction = correctionCallback(knownState);
207
+
208
+ if (!correction) {
209
+ logger.error("Correction callback returned undefined", {
210
+ knownState,
211
+ correction: correction ?? null,
212
+ });
213
+ return false;
214
+ }
215
+
216
+ for (const msg of correction) {
217
+ const success = this.storeSingle(msg, (knownState) => {
218
+ logger.error("Double correction requested", {
219
+ msg,
220
+ knownState,
221
+ });
222
+ return undefined;
223
+ });
198
224
 
199
225
  if (!success) {
200
226
  return false;
201
227
  }
202
228
  }
229
+
230
+ return true;
203
231
  }
204
232
 
205
233
  private storeSingle(
206
234
  msg: NewContentMessage,
207
- correctionCallback: (data: CoValueKnownState) => void,
235
+ correctionCallback: CorrectionCallback,
208
236
  ): boolean {
209
237
  const id = msg.id;
210
238
  const coValueRow = this.dbClient.getCoValue(id);
@@ -214,11 +242,9 @@ export class StorageApiSync implements StorageAPI {
214
242
 
215
243
  if (invalidAssumptionOnHeaderPresence) {
216
244
  const knownState = emptyKnownState(id as RawCoID);
217
- correctionCallback(knownState);
218
-
219
245
  this.knwonStates.setKnownState(id, knownState);
220
246
 
221
- return false;
247
+ return this.handleCorrection(knownState, correctionCallback);
222
248
  }
223
249
 
224
250
  const storedCoValueRowID: number = coValueRow
@@ -258,8 +284,7 @@ export class StorageApiSync implements StorageAPI {
258
284
  this.knwonStates.handleUpdate(id, knownState);
259
285
 
260
286
  if (invalidAssumptions) {
261
- correctionCallback(knownState);
262
- return false;
287
+ return this.handleCorrection(knownState, correctionCallback);
263
288
  }
264
289
 
265
290
  return true;
@@ -272,35 +297,29 @@ export class StorageApiSync implements StorageAPI {
272
297
  storedCoValueRowID: number,
273
298
  ) {
274
299
  const newTransactions = msg.new[sessionID]?.newTransactions || [];
300
+ const lastIdx = sessionRow?.lastIdx || 0;
275
301
 
276
- const actuallyNewOffset =
277
- (sessionRow?.lastIdx || 0) - (msg.new[sessionID]?.after || 0);
302
+ const actuallyNewOffset = lastIdx - (msg.new[sessionID]?.after || 0);
278
303
 
279
304
  const actuallyNewTransactions = newTransactions.slice(actuallyNewOffset);
280
305
 
281
306
  if (actuallyNewTransactions.length === 0) {
282
- return sessionRow?.lastIdx || 0;
307
+ return lastIdx;
283
308
  }
284
309
 
285
- let newBytesSinceLastSignature =
286
- (sessionRow?.bytesSinceLastSignature || 0) +
287
- actuallyNewTransactions.reduce(
288
- (sum, tx) =>
289
- sum +
290
- (tx.privacy === "private"
291
- ? tx.encryptedChanges.length
292
- : tx.changes.length),
293
- 0,
294
- );
310
+ let bytesSinceLastSignature = sessionRow?.bytesSinceLastSignature || 0;
311
+ const newTransactionsSize = getNewTransactionsSize(actuallyNewTransactions);
295
312
 
296
313
  const newLastIdx =
297
314
  (sessionRow?.lastIdx || 0) + actuallyNewTransactions.length;
298
315
 
299
316
  let shouldWriteSignature = false;
300
317
 
301
- if (newBytesSinceLastSignature > MAX_RECOMMENDED_TX_SIZE) {
318
+ if (exceedsRecommendedSize(bytesSinceLastSignature, newTransactionsSize)) {
302
319
  shouldWriteSignature = true;
303
- newBytesSinceLastSignature = 0;
320
+ bytesSinceLastSignature = 0;
321
+ } else {
322
+ bytesSinceLastSignature += newTransactionsSize;
304
323
  }
305
324
 
306
325
  const nextIdx = sessionRow?.lastIdx || 0;
@@ -312,7 +331,7 @@ export class StorageApiSync implements StorageAPI {
312
331
  sessionID,
313
332
  lastIdx: newLastIdx,
314
333
  lastSignature: msg.new[sessionID].lastSignature,
315
- bytesSinceLastSignature: newBytesSinceLastSignature,
334
+ bytesSinceLastSignature,
316
335
  };
317
336
 
318
337
  const sessionRowID: number = this.dbClient.addSessionUpdate({
@@ -339,5 +358,7 @@ export class StorageApiSync implements StorageAPI {
339
358
  return this.knwonStates.waitForSync(id, coValue);
340
359
  }
341
360
 
342
- close() {}
361
+ close() {
362
+ return undefined;
363
+ }
343
364
  }
@@ -1,5 +1,9 @@
1
+ import { getTransactionSize } from "../coValueContentMessage.js";
1
2
  import { getDependedOnCoValuesFromRawData } from "../coValueCore/utils.js";
2
- import type { CoValueHeader } from "../coValueCore/verifiedState.js";
3
+ import type {
4
+ CoValueHeader,
5
+ Transaction,
6
+ } from "../coValueCore/verifiedState.js";
3
7
  import type { Signature } from "../crypto/crypto.js";
4
8
  import type { SessionID } from "../exports.js";
5
9
  import type { NewContentMessage } from "../sync.js";
@@ -48,3 +52,7 @@ export function getDependedOnCoValues(
48
52
 
49
53
  return getDependedOnCoValuesFromRawData(id, header, sessionIDs, transactions);
50
54
  }
55
+
56
+ export function getNewTransactionsSize(newTxs: Transaction[]) {
57
+ return newTxs.reduce((sum, tx) => sum + getTransactionSize(tx), 0);
58
+ }
@@ -6,6 +6,10 @@ import { Signature } from "../crypto/crypto.js";
6
6
  import type { CoValueCore, RawCoID, SessionID } from "../exports.js";
7
7
  import { CoValueKnownState, NewContentMessage } from "../sync.js";
8
8
 
9
+ export type CorrectionCallback = (
10
+ correction: CoValueKnownState,
11
+ ) => NewContentMessage[] | undefined;
12
+
9
13
  /**
10
14
  * The StorageAPI is the interface that the StorageSync and StorageAsync classes implement.
11
15
  *
@@ -18,16 +22,13 @@ export interface StorageAPI {
18
22
  callback: (data: NewContentMessage) => void,
19
23
  done?: (found: boolean) => void,
20
24
  ): void;
21
- store(
22
- data: NewContentMessage[] | undefined,
23
- handleCorrection: (correction: CoValueKnownState) => void,
24
- ): void;
25
+ store(data: NewContentMessage, handleCorrection: CorrectionCallback): void;
25
26
 
26
27
  getKnownState(id: string): CoValueKnownState;
27
28
 
28
29
  waitForSync(id: string, coValue: CoValueCore): Promise<void>;
29
30
 
30
- close(): void;
31
+ close(): Promise<unknown> | undefined;
31
32
  }
32
33
 
33
34
  export type CoValueRow = {
package/src/sync.ts CHANGED
@@ -1,15 +1,24 @@
1
1
  import { Histogram, ValueType, metrics } from "@opentelemetry/api";
2
2
  import { PeerState } from "./PeerState.js";
3
3
  import { SyncStateManager } from "./SyncStateManager.js";
4
+ import {
5
+ getTransactionSize,
6
+ knownStateFromContent,
7
+ } from "./coValueContentMessage.js";
4
8
  import { CoValueCore } from "./coValueCore/coValueCore.js";
5
9
  import { getDependedOnCoValuesFromRawData } from "./coValueCore/utils.js";
6
- import { CoValueHeader, Transaction } from "./coValueCore/verifiedState.js";
10
+ import {
11
+ CoValueHeader,
12
+ Transaction,
13
+ VerifiedState,
14
+ } from "./coValueCore/verifiedState.js";
7
15
  import { Signature } from "./crypto/crypto.js";
8
- import { RawCoID, SessionID } from "./ids.js";
16
+ import { RawCoID, SessionID, isRawCoID } from "./ids.js";
9
17
  import { LocalNode } from "./localNode.js";
10
18
  import { logger } from "./logger.js";
11
19
  import { CoValuePriority } from "./priority.js";
12
20
  import { IncomingMessagesQueue } from "./queue/IncomingMessagesQueue.js";
21
+ import { LocalTransactionsSyncQueue } from "./queue/LocalTransactionsSyncQueue.js";
13
22
  import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
14
23
  import { isAccountID } from "./typeUtils/isAccountID.js";
15
24
 
@@ -57,10 +66,12 @@ export type NewContentMessage = {
57
66
  };
58
67
 
59
68
  export type SessionNewContent = {
69
+ // The index where to start appending the new transactions. The index counting starts from 1.
60
70
  after: number;
61
71
  newTransactions: Transaction[];
62
72
  lastSignature: Signature;
63
73
  };
74
+
64
75
  export type DoneMessage = {
65
76
  action: "done";
66
77
  id: RawCoID;
@@ -162,13 +173,9 @@ export class SyncManager {
162
173
  }
163
174
 
164
175
  handleSyncMessage(msg: SyncMessage, peer: PeerState) {
165
- if (msg.id === undefined || msg.id === null) {
166
- logger.warn("Received sync message with undefined id", {
167
- msg,
168
- });
169
- return;
170
- } else if (!msg.id.startsWith("co_z")) {
171
- logger.warn("Received sync message with invalid id", {
176
+ if (!isRawCoID(msg.id)) {
177
+ const errorType = msg.id ? "invalid" : "undefined";
178
+ logger.warn(`Received sync message with ${errorType} id`, {
172
179
  msg,
173
180
  });
174
181
  return;
@@ -431,12 +438,9 @@ export class SyncManager {
431
438
 
432
439
  recordTransactionsSize(newTransactions: Transaction[], source: string) {
433
440
  for (const tx of newTransactions) {
434
- const txLength =
435
- tx.privacy === "private"
436
- ? tx.encryptedChanges.length
437
- : tx.changes.length;
441
+ const size = getTransactionSize(tx);
438
442
 
439
- this.transactionsSizeHistogram.record(txLength, {
443
+ this.transactionsSizeHistogram.record(size, {
440
444
  source,
441
445
  });
442
446
  }
@@ -674,7 +678,7 @@ export class SyncManager {
674
678
  const syncedPeers = [];
675
679
 
676
680
  if (from !== "storage") {
677
- this.storeCoValue(coValue, [msg]);
681
+ this.storeContent(msg);
678
682
  }
679
683
 
680
684
  for (const peer of this.peersInPriorityOrder()) {
@@ -736,60 +740,18 @@ export class SyncManager {
736
740
  };
737
741
  }
738
742
 
739
- requestedSyncs = new Set<RawCoID>();
740
- requestCoValueSync(coValue: CoValueCore) {
741
- if (this.requestedSyncs.has(coValue.id)) {
742
- return;
743
- }
744
-
745
- for (const trackingSet of this.dirtyCoValuesTrackingSets) {
746
- trackingSet.add(coValue.id);
747
- }
748
-
749
- queueMicrotask(() => {
750
- if (this.requestedSyncs.has(coValue.id)) {
751
- this.syncCoValue(coValue);
752
- }
753
- });
754
-
755
- this.requestedSyncs.add(coValue.id);
756
- }
757
-
758
- storeCoValue(coValue: CoValueCore, data: NewContentMessage[] | undefined) {
759
- const storage = this.local.storage;
760
-
761
- if (!storage || !data) return;
762
-
763
- // Try to store the content as-is for performance
764
- // In case that some transactions are missing, a correction will be requested, but it's an edge case
765
- storage.store(data, (correction) => {
766
- if (!coValue.hasVerifiedContent()) return;
767
-
768
- const newContentPieces = coValue.verified.newContentSince(correction);
769
-
770
- if (!newContentPieces) return;
743
+ private syncQueue = new LocalTransactionsSyncQueue((content) =>
744
+ this.syncContent(content),
745
+ );
746
+ syncHeader = this.syncQueue.syncHeader;
747
+ syncLocalTransaction = this.syncQueue.syncTransaction;
771
748
 
772
- storage.store(newContentPieces, (response) => {
773
- logger.error(
774
- "Correction requested by storage after sending a correction content",
775
- {
776
- response,
777
- knownState: coValue.knownState(),
778
- },
779
- );
780
- });
781
- });
782
- }
749
+ syncContent(content: NewContentMessage) {
750
+ const coValue = this.local.getCoValue(content.id);
783
751
 
784
- syncCoValue(coValue: CoValueCore) {
785
- this.requestedSyncs.delete(coValue.id);
752
+ this.storeContent(content);
786
753
 
787
- if (this.local.storage && coValue.hasVerifiedContent()) {
788
- const knownState = this.local.storage.getKnownState(coValue.id);
789
- const newContentPieces = coValue.verified.newContentSince(knownState);
790
-
791
- this.storeCoValue(coValue, newContentPieces);
792
- }
754
+ const contentKnownState = knownStateFromContent(content);
793
755
 
794
756
  for (const peer of this.peersInPriorityOrder()) {
795
757
  if (peer.closed) continue;
@@ -803,7 +765,11 @@ export class SyncManager {
803
765
  continue;
804
766
  }
805
767
 
806
- this.sendNewContentIncludingDependencies(coValue.id, peer);
768
+ // We assume that the peer already knows anything before this content
769
+ // Any eventual reconciliation will be handled through the known state messages exchange
770
+ this.trySendToPeer(peer, content);
771
+ peer.combineOptimisticWith(coValue.id, contentKnownState);
772
+ peer.trackToldKnownState(coValue.id);
807
773
  }
808
774
 
809
775
  for (const peer of this.getPeers()) {
@@ -811,6 +777,20 @@ export class SyncManager {
811
777
  }
812
778
  }
813
779
 
780
+ private storeContent(content: NewContentMessage) {
781
+ const storage = this.local.storage;
782
+
783
+ if (!storage) return;
784
+
785
+ // Try to store the content as-is for performance
786
+ // In case that some transactions are missing, a correction will be requested, but it's an edge case
787
+ storage.store(content, (correction) => {
788
+ return this.local
789
+ .getCoValue(content.id)
790
+ .verified?.newContentSince(correction);
791
+ });
792
+ }
793
+
814
794
  waitForSyncWithPeer(peerId: PeerID, id: RawCoID, timeout: number) {
815
795
  const { syncState } = this;
816
796
  const currentSyncState = syncState.getCurrentSyncState(peerId, id);