cojson 0.18.36 → 0.18.38

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 (76) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +18 -0
  3. package/dist/coValueCore/SessionMap.d.ts +5 -3
  4. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  5. package/dist/coValueCore/SessionMap.js +19 -9
  6. package/dist/coValueCore/SessionMap.js.map +1 -1
  7. package/dist/coValueCore/coValueCore.d.ts +5 -2
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +24 -4
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/verifiedState.d.ts +1 -3
  12. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  13. package/dist/coValueCore/verifiedState.js +10 -14
  14. package/dist/coValueCore/verifiedState.js.map +1 -1
  15. package/dist/coValues/group.d.ts +2 -1
  16. package/dist/coValues/group.d.ts.map +1 -1
  17. package/dist/coValues/group.js +21 -18
  18. package/dist/coValues/group.js.map +1 -1
  19. package/dist/exports.d.ts +5 -4
  20. package/dist/exports.d.ts.map +1 -1
  21. package/dist/exports.js +3 -3
  22. package/dist/exports.js.map +1 -1
  23. package/dist/permissions.d.ts +0 -1
  24. package/dist/permissions.d.ts.map +1 -1
  25. package/dist/permissions.js +83 -89
  26. package/dist/permissions.js.map +1 -1
  27. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
  28. package/dist/queue/LocalTransactionsSyncQueue.js +1 -18
  29. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
  30. package/dist/sync.d.ts.map +1 -1
  31. package/dist/sync.js +8 -0
  32. package/dist/sync.js.map +1 -1
  33. package/dist/tests/StorageApiAsync.test.js +8 -8
  34. package/dist/tests/coValueCore.isStreaming.test.js +30 -40
  35. package/dist/tests/coValueCore.isStreaming.test.js.map +1 -1
  36. package/dist/tests/coValueCore.newContentSince.test.js +242 -132
  37. package/dist/tests/coValueCore.newContentSince.test.js.map +1 -1
  38. package/dist/tests/group.inheritance.test.js +47 -1
  39. package/dist/tests/group.inheritance.test.js.map +1 -1
  40. package/dist/tests/group.invite.test.js +4 -9
  41. package/dist/tests/group.invite.test.js.map +1 -1
  42. package/dist/tests/sync.auth.test.js +6 -6
  43. package/dist/tests/sync.load.test.js +11 -75
  44. package/dist/tests/sync.load.test.js.map +1 -1
  45. package/dist/tests/sync.mesh.test.js +2 -2
  46. package/dist/tests/sync.storage.test.js +22 -48
  47. package/dist/tests/sync.storage.test.js.map +1 -1
  48. package/dist/tests/sync.storageAsync.test.js +121 -71
  49. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  50. package/dist/tests/sync.upload.test.js +11 -75
  51. package/dist/tests/sync.upload.test.js.map +1 -1
  52. package/dist/tests/testUtils.d.ts +4 -1
  53. package/dist/tests/testUtils.d.ts.map +1 -1
  54. package/dist/tests/testUtils.js +11 -0
  55. package/dist/tests/testUtils.js.map +1 -1
  56. package/package.json +3 -3
  57. package/src/coValueCore/SessionMap.ts +25 -15
  58. package/src/coValueCore/coValueCore.ts +32 -2
  59. package/src/coValueCore/verifiedState.ts +11 -20
  60. package/src/coValues/group.ts +28 -24
  61. package/src/exports.ts +5 -2
  62. package/src/permissions.ts +98 -119
  63. package/src/queue/LocalTransactionsSyncQueue.ts +1 -20
  64. package/src/sync.ts +9 -0
  65. package/src/tests/StorageApiAsync.test.ts +8 -8
  66. package/src/tests/coValueCore.isStreaming.test.ts +84 -91
  67. package/src/tests/coValueCore.newContentSince.test.ts +246 -141
  68. package/src/tests/group.inheritance.test.ts +61 -0
  69. package/src/tests/group.invite.test.ts +4 -21
  70. package/src/tests/sync.auth.test.ts +6 -6
  71. package/src/tests/sync.load.test.ts +11 -79
  72. package/src/tests/sync.mesh.test.ts +2 -2
  73. package/src/tests/sync.storage.test.ts +22 -51
  74. package/src/tests/sync.storageAsync.test.ts +159 -76
  75. package/src/tests/sync.upload.test.ts +11 -78
  76. package/src/tests/testUtils.ts +16 -0
@@ -8,6 +8,7 @@ import {
8
8
  ParentGroupReferenceRole,
9
9
  RawGroup,
10
10
  isInheritableRole,
11
+ isSelfExtension,
11
12
  } from "./coValues/group.js";
12
13
  import { KeyID } from "./crypto/crypto.js";
13
14
  import {
@@ -17,7 +18,6 @@ import {
17
18
  getParentGroupId,
18
19
  } from "./ids.js";
19
20
  import { JsonValue } from "./jsonValue.js";
20
- import { logger } from "./logger.js";
21
21
  import { expectGroup } from "./typeUtils/expectGroup.js";
22
22
 
23
23
  export type PermissionsDef =
@@ -70,25 +70,6 @@ function canAdmin(role: Role | undefined): boolean {
70
70
  return role === "admin" || role === "manager";
71
71
  }
72
72
 
73
- type MemberState = { [agent: RawAccountID | AgentID]: Role; [EVERYONE]?: Role };
74
-
75
- let logPermissionErrors = true;
76
-
77
- export function disablePermissionErrors() {
78
- logPermissionErrors = false;
79
- }
80
-
81
- function logPermissionError(
82
- message: string,
83
- attributes?: Record<string, JsonValue>,
84
- ) {
85
- if (logPermissionErrors === false) {
86
- return;
87
- }
88
-
89
- logger.debug("Permission error: " + message, attributes);
90
- }
91
-
92
73
  export function determineValidTransactions(coValue: CoValueCore): void {
93
74
  if (!coValue.isAvailable()) {
94
75
  throw new Error("determineValidTransactions CoValue is not available");
@@ -130,7 +111,10 @@ export function determineValidTransactions(coValue: CoValueCore): void {
130
111
  );
131
112
 
132
113
  if (!effectiveTransactor) {
133
- tx.markInvalid();
114
+ tx.markInvalid("Transactor not found in group", {
115
+ transactor: tx.author,
116
+ group: groupAtTime.toJSON(),
117
+ });
134
118
  continue;
135
119
  }
136
120
 
@@ -158,7 +142,10 @@ export function determineValidTransactions(coValue: CoValueCore): void {
158
142
  transactorRoleAtTxTime !== "writer" &&
159
143
  transactorRoleAtTxTime !== "writeOnly"
160
144
  ) {
161
- tx.markInvalid();
145
+ tx.markInvalid("Transactor has no write permissions", {
146
+ transactor: tx.author,
147
+ transactorRole: transactorRoleAtTxTime ?? "undefined",
148
+ });
162
149
  continue;
163
150
  }
164
151
 
@@ -193,77 +180,78 @@ function isHigherRole(a: Role, b: Role | undefined) {
193
180
  return a === "writer" && b === "reader";
194
181
  }
195
182
 
196
- function resolveMemberStateFromParentReference(
197
- coValue: CoValueCore,
198
- memberState: MemberState,
199
- parentReference: ParentGroupReference,
200
- roleMapping: ParentGroupReferenceRole,
201
- extendChain: Set<CoValueCore["id"]>,
202
- ) {
203
- const parentGroup = coValue.node.expectCoValueLoaded(
204
- getParentGroupId(parentReference),
205
- "Expected parent group to be loaded",
206
- );
183
+ class MemberRoleResolver {
184
+ private parentGroups = new Map<RawGroup, ParentGroupReferenceRole>();
185
+ private memberRoles = new Map<RawAccountID | AgentID | Everyone, Role>();
207
186
 
208
- if (parentGroup.verified.header.ruleset.type !== "group") {
209
- return;
187
+ setDirectRole(member: RawAccountID | AgentID | Everyone, role: Role) {
188
+ this.memberRoles.set(member, role);
210
189
  }
211
190
 
212
- // Skip circular references
213
- if (extendChain.has(parentGroup.id)) {
214
- return;
191
+ removeMember(member: RawAccountID | AgentID | Everyone) {
192
+ this.memberRoles.delete(member);
215
193
  }
216
194
 
217
- const initialAdmin = parentGroup.verified.header.ruleset.initialAdmin;
195
+ addParentGroup(parentGroup: RawGroup, roleMapping: ParentGroupReferenceRole) {
196
+ this.parentGroups.set(parentGroup, roleMapping);
197
+ }
218
198
 
219
- if (!initialAdmin) {
220
- throw new Error("Group must have initialAdmin");
199
+ removeParentGroup(parentGroup: RawGroup) {
200
+ this.parentGroups.delete(parentGroup);
221
201
  }
222
202
 
223
- extendChain.add(parentGroup.id);
203
+ getDirectRole(member: RawAccountID | AgentID | Everyone) {
204
+ return this.memberRoles.get(member);
205
+ }
224
206
 
225
- const { memberState: parentGroupMemberState } =
226
- determineValidTransactionsForGroup(parentGroup, initialAdmin, extendChain);
207
+ getRoleAtTime(member: RawAccountID | AgentID | Everyone, time: number) {
208
+ let role = this.memberRoles.get(member);
227
209
 
228
- for (const agent of Object.keys(parentGroupMemberState) as Array<
229
- keyof MemberState
230
- >) {
231
- const parentRole = parentGroupMemberState[agent];
232
- const currentRole = memberState[agent];
210
+ for (const [parentGroup, roleMapping] of this.parentGroups.entries()) {
211
+ const parentRole = parentGroup.atTime(time).roleOfInternal(member);
233
212
 
234
- if (isInheritableRole(parentRole)) {
235
- if (roleMapping !== "extend" && isHigherRole(roleMapping, currentRole)) {
236
- memberState[agent] = roleMapping;
237
- } else if (isHigherRole(parentRole, currentRole)) {
238
- memberState[agent] = parentRole;
213
+ if (!parentRole || !isInheritableRole(parentRole)) {
214
+ continue;
215
+ }
216
+
217
+ const resolvedParentRole =
218
+ roleMapping === "extend" ? parentRole : roleMapping;
219
+
220
+ if (isHigherRole(resolvedParentRole, role)) {
221
+ role = resolvedParentRole;
239
222
  }
240
223
  }
224
+
225
+ return role;
241
226
  }
242
227
  }
243
228
 
244
229
  function determineValidTransactionsForGroup(
245
230
  coValue: CoValueCore,
246
231
  initialAdmin: RawAccountID | AgentID,
247
- extendChain?: Set<CoValueCore["id"]>,
248
- ): { memberState: MemberState } {
232
+ ): void {
249
233
  coValue.verifiedTransactions.sort(coValue.compareTransactions);
250
234
 
251
- const memberState: MemberState = {};
252
235
  const writeOnlyKeys: Record<RawAccountID | AgentID, KeyID> = {};
253
236
  const writeKeys = new Set<string>();
237
+ const memberRoleResolver = new MemberRoleResolver();
254
238
 
255
239
  for (const transaction of coValue.verifiedTransactions) {
256
240
  const transactor = transaction.author;
257
- const transactorRole = memberState[transactor];
241
+
242
+ const transactorRole = memberRoleResolver.getRoleAtTime(
243
+ transactor,
244
+ transaction.currentMadeAt,
245
+ );
258
246
 
259
247
  const tx = transaction.tx;
260
248
 
261
249
  if (tx.privacy === "private") {
262
- if (memberState[transactor] === "admin") {
250
+ if (transactorRole === "admin") {
263
251
  transaction.markValid();
264
252
  continue;
265
253
  } else {
266
- logPermissionError(
254
+ transaction.markInvalid(
267
255
  "Only admins can make private transactions in groups",
268
256
  );
269
257
  continue;
@@ -285,21 +273,18 @@ function determineValidTransactionsForGroup(
285
273
  | MapOpPayload<`child_${CoID<RawGroup>}`, CoID<RawGroup>>;
286
274
 
287
275
  if (changes.length !== 1) {
288
- logPermissionError("Group transaction must have exactly one change");
289
- transaction.markInvalid();
276
+ transaction.markInvalid("Group transaction must have exactly one change");
290
277
  continue;
291
278
  }
292
279
 
293
280
  if (change.op !== "set") {
294
- logPermissionError("Group transaction must set a role or readKey");
295
- transaction.markInvalid();
281
+ transaction.markInvalid("Group transaction must set a role or readKey");
296
282
  continue;
297
283
  }
298
284
 
299
285
  if (change.key === "readKey") {
300
286
  if (!canAdmin(transactorRole)) {
301
- logPermissionError("Only admins can set readKeys");
302
- transaction.markInvalid();
287
+ transaction.markInvalid("Only admins can set readKeys");
303
288
  continue;
304
289
  }
305
290
 
@@ -307,8 +292,7 @@ function determineValidTransactionsForGroup(
307
292
  continue;
308
293
  } else if (change.key === "profile") {
309
294
  if (!canAdmin(transactorRole)) {
310
- logPermissionError("Only admins can set profile");
311
- transaction.markInvalid();
295
+ transaction.markInvalid("Only admins can set profile");
312
296
  continue;
313
297
  }
314
298
 
@@ -316,7 +300,7 @@ function determineValidTransactionsForGroup(
316
300
  continue;
317
301
  } else if (change.key === "root") {
318
302
  if (!canAdmin(transactorRole)) {
319
- logPermissionError("Only admins can set root");
303
+ transaction.markInvalid("Only admins can set root");
320
304
  continue;
321
305
  }
322
306
 
@@ -336,47 +320,51 @@ function determineValidTransactionsForGroup(
336
320
  transactorRole !== "writeOnlyInvite" &&
337
321
  !isOwnWriteKeyRevelation(change.key, transactor, writeOnlyKeys)
338
322
  ) {
339
- logPermissionError("Only admins and managers can reveal keys");
340
- transaction.markInvalid();
323
+ transaction.markInvalid("Only admins and managers can reveal keys");
341
324
  continue;
342
325
  }
343
326
 
344
- // TODO: check validity of agents who the key is revealed to?
345
327
  transaction.markValid();
346
328
  continue;
347
329
  } else if (isParentExtension(change.key)) {
348
330
  if (!canAdmin(transactorRole)) {
349
- logPermissionError(
331
+ transaction.markInvalid(
350
332
  "Only admins and managers can set parent extensions",
351
333
  );
352
- transaction.markInvalid();
353
334
  continue;
354
335
  }
355
336
 
356
- extendChain = extendChain ?? new Set([]);
337
+ const parentGroupId = getParentGroupId(change.key);
357
338
 
358
- resolveMemberStateFromParentReference(
359
- coValue,
360
- memberState,
361
- change.key,
362
- change.value as ParentGroupReferenceRole,
363
- extendChain,
339
+ const parentGroupCore = coValue.node.expectCoValueLoaded(
340
+ parentGroupId,
341
+ "Expected parent group to be loaded",
364
342
  );
365
343
 
366
- // Circular reference detected, drop all the transactions involved
367
- if (extendChain.has(coValue.id)) {
368
- logPermissionError(
369
- "Circular extend detected, dropping the transaction",
370
- );
371
- transaction.markInvalid();
344
+ if (!parentGroupCore.isGroup()) {
345
+ transaction.markInvalid("Parent group is not a group");
346
+ continue;
347
+ }
348
+
349
+ const parentGroup = expectGroup(parentGroupCore.getCurrentContent());
350
+
351
+ if (isSelfExtension(coValue, parentGroup)) {
352
+ transaction.markInvalid("Parent group is a circular dependency");
372
353
  continue;
373
354
  }
374
355
 
356
+ const value = change.value as ParentGroupReferenceRole;
357
+
358
+ if (value === "revoked") {
359
+ memberRoleResolver.removeParentGroup(parentGroup);
360
+ } else {
361
+ memberRoleResolver.addParentGroup(parentGroup, value);
362
+ }
363
+
375
364
  transaction.markValid();
376
365
  continue;
377
366
  } else if (isChildExtension(change.key)) {
378
- logPermissionError("Child extensions are not allowed anymore");
379
- transaction.markInvalid();
367
+ transaction.markInvalid("Child extensions are not allowed anymore");
380
368
  continue;
381
369
  } else if (isWriteKeyForMember(change.key)) {
382
370
  const memberKey = getAccountOrAgentFromWriteKeyForMember(change.key);
@@ -387,8 +375,7 @@ function determineValidTransactionsForGroup(
387
375
  transactorRole !== "writeOnlyInvite" &&
388
376
  memberKey !== transactor
389
377
  ) {
390
- logPermissionError("Only admins and managers can set writeKeys");
391
- transaction.markInvalid();
378
+ transaction.markInvalid("Only admins and managers can set writeKeys");
392
379
  continue;
393
380
  }
394
381
 
@@ -403,10 +390,9 @@ function determineValidTransactionsForGroup(
403
390
  * blocking them from accessing the group.ß
404
391
  */
405
392
  if (writeKeys.has(change.key) && !canAdmin(transactorRole)) {
406
- logPermissionError(
393
+ transaction.markInvalid(
407
394
  "Write key already exists and can't be overridden by invite",
408
395
  );
409
- transaction.markInvalid();
410
396
  continue;
411
397
  }
412
398
 
@@ -432,8 +418,7 @@ function determineValidTransactionsForGroup(
432
418
  assignedRole !== "readerInvite" &&
433
419
  assignedRole !== "writeOnlyInvite"
434
420
  ) {
435
- logPermissionError("Group transaction must set a valid role");
436
- transaction.markInvalid();
421
+ transaction.markInvalid("Group transaction must set a valid role");
437
422
  continue;
438
423
  }
439
424
 
@@ -446,10 +431,9 @@ function determineValidTransactionsForGroup(
446
431
  assignedRole === "revoked"
447
432
  )
448
433
  ) {
449
- logPermissionError(
434
+ transaction.markInvalid(
450
435
  "Everyone can only be set to reader, writer, writeOnly or revoked",
451
436
  );
452
- transaction.markInvalid();
453
437
  continue;
454
438
  }
455
439
 
@@ -460,15 +444,10 @@ function determineValidTransactionsForGroup(
460
444
  throw new Error("Expected set operation");
461
445
  }
462
446
 
463
- memberState[change.key] = change.value;
447
+ memberRoleResolver.setDirectRole(change.key, change.value);
464
448
  transaction.markValid();
465
449
  }
466
450
 
467
- function markTransactionAsInvalid(message: string) {
468
- logPermissionError(message);
469
- transaction.markInvalid();
470
- }
471
-
472
451
  // is first self promotion to admin
473
452
  if (
474
453
  transactorRole === undefined &&
@@ -486,7 +465,10 @@ function determineValidTransactionsForGroup(
486
465
  continue;
487
466
  }
488
467
 
489
- const affectedMemberRole = memberState[affectedMember];
468
+ const affectedMemberRole = memberRoleResolver.getRoleAtTime(
469
+ affectedMember,
470
+ transaction.currentMadeAt,
471
+ );
490
472
 
491
473
  /**
492
474
  * Admins can't:
@@ -498,7 +480,7 @@ function determineValidTransactionsForGroup(
498
480
  assignedRole !== "admin" &&
499
481
  affectedMember !== transactor
500
482
  ) {
501
- markTransactionAsInvalid("Admins can't demote admins.");
483
+ transaction.markInvalid("Admins can't demote admins.");
502
484
  continue;
503
485
  }
504
486
 
@@ -514,20 +496,20 @@ function determineValidTransactionsForGroup(
514
496
  */
515
497
  if (transactorRole === "manager") {
516
498
  if (affectedMemberRole === "admin") {
517
- markTransactionAsInvalid("Managers can't demote admins.");
499
+ transaction.markInvalid("Managers can't demote admins.");
518
500
  continue;
519
501
  }
520
502
  if (change.value === "admin") {
521
- markTransactionAsInvalid("Managers can't promote to admin.");
503
+ transaction.markInvalid("Managers can't promote to admin.");
522
504
  continue;
523
505
  }
524
506
 
525
507
  if (change.value === "adminInvite") {
526
- markTransactionAsInvalid("Managers can't invite admins.");
508
+ transaction.markInvalid("Managers can't invite admins.");
527
509
  continue;
528
510
  }
529
511
  if (change.value === "managerInvite") {
530
- markTransactionAsInvalid("Managers can't invite managers.");
512
+ transaction.markInvalid("Managers can't invite managers.");
531
513
  continue;
532
514
  }
533
515
 
@@ -537,42 +519,39 @@ function determineValidTransactionsForGroup(
537
519
 
538
520
  if (transactorRole === "adminInvite") {
539
521
  if (change.value !== "admin") {
540
- logPermissionError("AdminInvites can only create admins.");
541
- transaction.markInvalid();
522
+ transaction.markInvalid("AdminInvites can only create admins.");
542
523
  continue;
543
524
  }
544
525
  } else if (transactorRole === "managerInvite") {
545
526
  if (change.value !== "manager") {
546
- markTransactionAsInvalid("managerInvite can only create managers.");
527
+ transaction.markInvalid("managerInvite can only create managers.");
547
528
  continue;
548
529
  }
549
530
  } else if (transactorRole === "writerInvite") {
550
531
  if (change.value !== "writer") {
551
- markTransactionAsInvalid("WriterInvites can only create writers.");
532
+ transaction.markInvalid("WriterInvites can only create writers.");
552
533
  continue;
553
534
  }
554
535
  } else if (transactorRole === "readerInvite") {
555
536
  if (change.value !== "reader") {
556
- markTransactionAsInvalid("ReaderInvites can only create reader.");
537
+ transaction.markInvalid("ReaderInvites can only create reader.");
557
538
  continue;
558
539
  }
559
540
  } else if (transactorRole === "writeOnlyInvite") {
560
541
  if (change.value !== "writeOnly") {
561
- markTransactionAsInvalid("WriteOnlyInvites can only create writeOnly.");
542
+ transaction.markInvalid("WriteOnlyInvites can only create writeOnly.");
562
543
  continue;
563
544
  }
564
545
  } else {
565
- markTransactionAsInvalid(
546
+ transaction.markInvalid(
566
547
  "Group transaction must be made by current admin, manager, or invite",
567
548
  );
568
549
  continue;
569
550
  }
570
551
 
571
- memberState[affectedMember] = change.value;
552
+ memberRoleResolver.setDirectRole(affectedMember, change.value);
572
553
  transaction.markValid();
573
554
  }
574
-
575
- return { memberState };
576
555
  }
577
556
 
578
557
  function agentInAccountOrMemberInGroup(
@@ -50,33 +50,14 @@ export class LocalTransactionsSyncQueue {
50
50
  coValue: VerifiedState,
51
51
  knownStateBefore: CoValueKnownState,
52
52
  ) {
53
- const content = coValue.newContentSince(knownStateBefore, {
54
- skipExpectContentUntil: true, // we need to calculate the streaming header considering the current batch
55
- });
53
+ const content = coValue.newContentSince(knownStateBefore);
56
54
 
57
55
  if (!content) {
58
56
  return;
59
57
  }
60
58
 
61
- let firstChunk = this.firstChunks.get(coValue.id);
62
-
63
59
  for (const piece of content) {
64
60
  this.batch.push(piece);
65
-
66
- // Check if the local content updates are in streaming, if so we need to add the info to the first chunk
67
- if (firstChunk) {
68
- if (!firstChunk.expectContentUntil) {
69
- firstChunk.expectContentUntil =
70
- knownStateFromContent(firstChunk).sessions;
71
- }
72
- combineKnownStateSessions(
73
- firstChunk.expectContentUntil,
74
- knownStateFromContent(piece).sessions,
75
- );
76
- } else {
77
- firstChunk = piece;
78
- this.firstChunks.set(coValue.id, firstChunk);
79
- }
80
61
  }
81
62
  }
82
63
 
package/src/sync.ts CHANGED
@@ -484,6 +484,15 @@ export class SyncManager {
484
484
  ? "import"
485
485
  : peer?.role;
486
486
 
487
+ // TODO: We can't handle client-to-client streaming until we
488
+ // handle the streaming state reset on disconnection
489
+ if (peer?.role === "client" && msg.expectContentUntil) {
490
+ msg = {
491
+ ...msg,
492
+ expectContentUntil: undefined,
493
+ };
494
+ }
495
+
487
496
  coValue.addDependenciesFromContentMessage(msg);
488
497
 
489
498
  // If some of the dependencies are missing, we wait for them to be available
@@ -539,16 +539,16 @@ describe("StorageApiAsync", () => {
539
539
  }),
540
540
  ).toMatchInlineSnapshot(`
541
541
  [
542
- "test -> test-storage | CONTENT Core header: false new: After: 1 New: 1 expectContentUntil: header/3",
543
- "test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1 expectContentUntil: header/3",
542
+ "test -> test-storage | CONTENT Core header: false new: After: 1 New: 1",
543
+ "test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1",
544
544
  "test -> test-storage | CONTENT Core header: false new: After: 2 New: 1",
545
545
  "test -> test-storage | CONTENT Core2 header: false new: After: 2 New: 1",
546
546
  "test-storage -> test | KNOWN CORRECTION Core sessions: empty",
547
547
  "test -> test-storage | CONTENT Core header: true new: After: 0 New: 3",
548
548
  "test-storage -> test | KNOWN CORRECTION Core2 sessions: empty",
549
549
  "test -> test-storage | CONTENT Core2 header: true new: After: 0 New: 3",
550
- "test -> test-storage | CONTENT Core header: false new: After: 3 New: 1 expectContentUntil: header/5",
551
- "test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1 expectContentUntil: header/5",
550
+ "test -> test-storage | CONTENT Core header: false new: After: 3 New: 1",
551
+ "test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1",
552
552
  "test -> test-storage | CONTENT Core header: false new: After: 4 New: 1",
553
553
  "test -> test-storage | CONTENT Core2 header: false new: After: 4 New: 1",
554
554
  ]
@@ -606,14 +606,14 @@ describe("StorageApiAsync", () => {
606
606
  }),
607
607
  ).toMatchInlineSnapshot(`
608
608
  [
609
- "test -> test-storage | CONTENT Core header: false new: After: 1 New: 1 expectContentUntil: header/3",
610
- "test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1 expectContentUntil: header/3",
609
+ "test -> test-storage | CONTENT Core header: false new: After: 1 New: 1",
610
+ "test -> test-storage | CONTENT Core2 header: false new: After: 1 New: 1",
611
611
  "test -> test-storage | CONTENT Core header: false new: After: 2 New: 1",
612
612
  "test -> test-storage | CONTENT Core2 header: false new: After: 2 New: 1",
613
613
  "test-storage -> test | KNOWN CORRECTION Core sessions: empty",
614
614
  "test -> test-storage | CONTENT Core header: true new: After: 0 New: 3",
615
- "test -> test-storage | CONTENT Core header: false new: After: 3 New: 1 expectContentUntil: header/5",
616
- "test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1 expectContentUntil: header/5",
615
+ "test -> test-storage | CONTENT Core header: false new: After: 3 New: 1",
616
+ "test -> test-storage | CONTENT Core2 header: false new: After: 3 New: 1",
617
617
  "test -> test-storage | CONTENT Core header: false new: After: 4 New: 1",
618
618
  "test -> test-storage | CONTENT Core2 header: false new: After: 4 New: 1",
619
619
  ]