cojson 0.18.29 → 0.18.31

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 (144) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/dist/PeerState.d.ts +23 -14
  4. package/dist/PeerState.d.ts.map +1 -1
  5. package/dist/PeerState.js +74 -23
  6. package/dist/PeerState.js.map +1 -1
  7. package/dist/SyncStateManager.d.ts +3 -3
  8. package/dist/SyncStateManager.d.ts.map +1 -1
  9. package/dist/SyncStateManager.js +18 -44
  10. package/dist/SyncStateManager.js.map +1 -1
  11. package/dist/coValueContentMessage.d.ts.map +1 -1
  12. package/dist/coValueContentMessage.js +2 -1
  13. package/dist/coValueContentMessage.js.map +1 -1
  14. package/dist/coValueCore/PeerKnownState.d.ts +21 -0
  15. package/dist/coValueCore/PeerKnownState.d.ts.map +1 -0
  16. package/dist/coValueCore/PeerKnownState.js +52 -0
  17. package/dist/coValueCore/PeerKnownState.js.map +1 -0
  18. package/dist/coValueCore/coValueCore.d.ts +39 -8
  19. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  20. package/dist/coValueCore/coValueCore.js +139 -40
  21. package/dist/coValueCore/coValueCore.js.map +1 -1
  22. package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts.map +1 -1
  23. package/dist/coValueCore/decryptTransactionChangesAndMeta.js +0 -5
  24. package/dist/coValueCore/decryptTransactionChangesAndMeta.js.map +1 -1
  25. package/dist/coValueCore/verifiedState.d.ts +0 -14
  26. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  27. package/dist/coValueCore/verifiedState.js +2 -32
  28. package/dist/coValueCore/verifiedState.js.map +1 -1
  29. package/dist/coValues/coList.d.ts +3 -4
  30. package/dist/coValues/coList.d.ts.map +1 -1
  31. package/dist/coValues/coList.js +4 -4
  32. package/dist/coValues/coList.js.map +1 -1
  33. package/dist/coValues/coMap.d.ts +3 -4
  34. package/dist/coValues/coMap.d.ts.map +1 -1
  35. package/dist/coValues/coMap.js +5 -4
  36. package/dist/coValues/coMap.js.map +1 -1
  37. package/dist/coValues/coStream.d.ts +3 -3
  38. package/dist/coValues/coStream.d.ts.map +1 -1
  39. package/dist/coValues/coStream.js +3 -4
  40. package/dist/coValues/coStream.js.map +1 -1
  41. package/dist/coValues/group.d.ts +3 -3
  42. package/dist/coValues/group.d.ts.map +1 -1
  43. package/dist/coValues/group.js +74 -52
  44. package/dist/coValues/group.js.map +1 -1
  45. package/dist/exports.d.ts +2 -2
  46. package/dist/exports.d.ts.map +1 -1
  47. package/dist/exports.js +2 -2
  48. package/dist/exports.js.map +1 -1
  49. package/dist/localNode.d.ts.map +1 -1
  50. package/dist/localNode.js +7 -5
  51. package/dist/localNode.js.map +1 -1
  52. package/dist/permissions.d.ts +5 -1
  53. package/dist/permissions.d.ts.map +1 -1
  54. package/dist/permissions.js +173 -109
  55. package/dist/permissions.js.map +1 -1
  56. package/dist/sync.d.ts.map +1 -1
  57. package/dist/sync.js +33 -44
  58. package/dist/sync.js.map +1 -1
  59. package/dist/tests/PeerKnownState.test.d.ts +2 -0
  60. package/dist/tests/PeerKnownState.test.d.ts.map +1 -0
  61. package/dist/tests/PeerKnownState.test.js +342 -0
  62. package/dist/tests/PeerKnownState.test.js.map +1 -0
  63. package/dist/tests/PeerState.test.js +17 -16
  64. package/dist/tests/PeerState.test.js.map +1 -1
  65. package/dist/tests/StorageApiAsync.test.js +12 -12
  66. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  67. package/dist/tests/StorageApiSync.test.js +11 -11
  68. package/dist/tests/StorageApiSync.test.js.map +1 -1
  69. package/dist/tests/SyncStateManager.test.js +16 -21
  70. package/dist/tests/SyncStateManager.test.js.map +1 -1
  71. package/dist/tests/coValueCore.dependencies.test.js +59 -0
  72. package/dist/tests/coValueCore.dependencies.test.js.map +1 -1
  73. package/dist/tests/coValueCore.test.js +41 -21
  74. package/dist/tests/coValueCore.test.js.map +1 -1
  75. package/dist/tests/group.addMember.test.js +266 -219
  76. package/dist/tests/group.addMember.test.js.map +1 -1
  77. package/dist/tests/group.inheritance.test.js +12 -0
  78. package/dist/tests/group.inheritance.test.js.map +1 -1
  79. package/dist/tests/group.invite.test.js +77 -0
  80. package/dist/tests/group.invite.test.js.map +1 -1
  81. package/dist/tests/group.removeMember.test.js +65 -8
  82. package/dist/tests/group.removeMember.test.js.map +1 -1
  83. package/dist/tests/group.roleOf.test.js +14 -4
  84. package/dist/tests/group.roleOf.test.js.map +1 -1
  85. package/dist/tests/permissions.test.js +51 -202
  86. package/dist/tests/permissions.test.js.map +1 -1
  87. package/dist/tests/sync.content.test.js +2 -2
  88. package/dist/tests/sync.content.test.js.map +1 -1
  89. package/dist/tests/sync.invite.test.js +6 -6
  90. package/dist/tests/sync.load.test.js +22 -22
  91. package/dist/tests/sync.mesh.test.js +9 -9
  92. package/dist/tests/sync.storage.test.js +13 -7
  93. package/dist/tests/sync.storage.test.js.map +1 -1
  94. package/dist/tests/sync.storageAsync.test.js +3 -3
  95. package/dist/tests/sync.test.js +13 -33
  96. package/dist/tests/sync.test.js.map +1 -1
  97. package/dist/tests/sync.upload.test.js +2 -2
  98. package/package.json +3 -3
  99. package/src/PeerState.ts +86 -34
  100. package/src/SyncStateManager.ts +25 -60
  101. package/src/coValueContentMessage.ts +3 -1
  102. package/src/coValueCore/PeerKnownState.ts +74 -0
  103. package/src/coValueCore/coValueCore.ts +180 -49
  104. package/src/coValueCore/decryptTransactionChangesAndMeta.ts +0 -6
  105. package/src/coValueCore/verifiedState.ts +2 -37
  106. package/src/coValues/coList.ts +7 -7
  107. package/src/coValues/coMap.ts +9 -7
  108. package/src/coValues/coStream.ts +6 -5
  109. package/src/coValues/group.ts +99 -60
  110. package/src/exports.ts +2 -1
  111. package/src/localNode.ts +7 -5
  112. package/src/permissions.ts +204 -123
  113. package/src/sync.ts +37 -53
  114. package/src/tests/PeerKnownState.test.ts +426 -0
  115. package/src/tests/PeerState.test.ts +24 -24
  116. package/src/tests/StorageApiAsync.test.ts +12 -12
  117. package/src/tests/StorageApiSync.test.ts +11 -11
  118. package/src/tests/SyncStateManager.test.ts +23 -53
  119. package/src/tests/coValueCore.dependencies.test.ts +87 -0
  120. package/src/tests/coValueCore.test.ts +64 -22
  121. package/src/tests/group.addMember.test.ts +384 -345
  122. package/src/tests/group.inheritance.test.ts +33 -0
  123. package/src/tests/group.invite.test.ts +117 -0
  124. package/src/tests/group.removeMember.test.ts +96 -10
  125. package/src/tests/group.roleOf.test.ts +16 -4
  126. package/src/tests/permissions.test.ts +56 -295
  127. package/src/tests/sync.content.test.ts +2 -2
  128. package/src/tests/sync.invite.test.ts +6 -6
  129. package/src/tests/sync.load.test.ts +22 -22
  130. package/src/tests/sync.mesh.test.ts +9 -9
  131. package/src/tests/sync.storage.test.ts +13 -8
  132. package/src/tests/sync.storageAsync.test.ts +3 -3
  133. package/src/tests/sync.test.ts +21 -50
  134. package/src/tests/sync.upload.test.ts +2 -2
  135. package/dist/PeerKnownStates.d.ts +0 -19
  136. package/dist/PeerKnownStates.d.ts.map +0 -1
  137. package/dist/PeerKnownStates.js +0 -64
  138. package/dist/PeerKnownStates.js.map +0 -1
  139. package/dist/tests/PeerKnownStates.test.d.ts +0 -2
  140. package/dist/tests/PeerKnownStates.test.d.ts.map +0 -1
  141. package/dist/tests/PeerKnownStates.test.js +0 -77
  142. package/dist/tests/PeerKnownStates.test.js.map +0 -1
  143. package/src/PeerKnownStates.ts +0 -93
  144. package/src/tests/PeerKnownStates.test.ts +0 -99
@@ -44,6 +44,7 @@ import {
44
44
  import { type RawAccountID } from "../coValues/account.js";
45
45
  import { decryptTransactionChangesAndMeta } from "./decryptTransactionChangesAndMeta.js";
46
46
  import {
47
+ cloneKnownState,
47
48
  combineKnownStateSessions,
48
49
  CoValueKnownState,
49
50
  emptyKnownState,
@@ -60,6 +61,7 @@ export function idforHeader(
60
61
  }
61
62
 
62
63
  export class VerifiedTransaction {
64
+ dispatchTransaction: (transaction: VerifiedTransaction) => void;
63
65
  // The account or agent that made the transaction
64
66
  author: RawAccountID | AgentID;
65
67
  // An object containing the session ID and the transaction index
@@ -75,14 +77,9 @@ export class VerifiedTransaction {
75
77
  changes: JsonValue[] | undefined;
76
78
  // The decoded meta information of the transaction
77
79
  meta: JsonObject | undefined;
80
+ isValidated: boolean = false;
78
81
  // Whether the transaction is valid, as per membership rules
79
82
  isValid: boolean = false;
80
- // Whether the transaction has been validated, used to track if determinedValidTransactions needs to check this
81
- isValidated: boolean = false;
82
- // True if the transaction has been decrypted
83
- isDecrypted: boolean = false;
84
- // True if the meta information has been parsed and loaded in the CoValueCore
85
- hasMetaBeenParsed: boolean = false;
86
83
  // The previous verified transaction for the same session
87
84
  previous: VerifiedTransaction | undefined;
88
85
 
@@ -95,7 +92,9 @@ export class VerifiedTransaction {
95
92
  | { changes: JsonValue[]; meta: JsonObject | undefined }
96
93
  | undefined,
97
94
  previous: VerifiedTransaction | undefined,
95
+ dispatchTransaction: (transaction: VerifiedTransaction) => void,
98
96
  ) {
97
+ this.dispatchTransaction = dispatchTransaction;
99
98
  this.author = accountOrAgentIDfromSessionID(sessionID);
100
99
 
101
100
  const txID = branchId
@@ -114,7 +113,6 @@ export class VerifiedTransaction {
114
113
  this.tx = tx;
115
114
  this.currentMadeAt = tx.madeAt;
116
115
  this.sourceTxMadeAt = undefined;
117
- this.isValidated = false;
118
116
 
119
117
  this.previous = previous;
120
118
 
@@ -151,6 +149,20 @@ export class VerifiedTransaction {
151
149
  } {
152
150
  return Boolean(this.isValid && this.changes);
153
151
  }
152
+
153
+ markValid() {
154
+ this.isValid = true;
155
+
156
+ if (!this.isValidated) {
157
+ this.isValidated = true;
158
+ this.dispatchTransaction(this);
159
+ }
160
+ }
161
+
162
+ markInvalid() {
163
+ this.isValidated = true;
164
+ this.isValid = false;
165
+ }
154
166
  }
155
167
 
156
168
  export type DecryptedTransaction = Omit<VerifiedTransaction, "changes"> & {
@@ -242,6 +254,31 @@ export class CoValueCore {
242
254
  return this.hasVerifiedContent();
243
255
  }
244
256
 
257
+ /**
258
+ * True if the coValue is completely downloaded:
259
+ * - the current coValue is available and not streaming
260
+ * - the group is available and not streaming
261
+ * - TODO: all the parent groups are available and not streaming
262
+ */
263
+ isCompletelyDownloaded(): this is AvailableCoValueCore {
264
+ if (!this.hasVerifiedContent()) {
265
+ return false;
266
+ }
267
+
268
+ if (this.verified.isStreaming()) {
269
+ return false;
270
+ }
271
+
272
+ const group = this.safeGetGroup();
273
+
274
+ // TODO: Group coValues should be completely downloaded when all their parent groups are completely downloaded
275
+ if (!group) {
276
+ return true;
277
+ }
278
+
279
+ return group.core.isCompletelyDownloaded();
280
+ }
281
+
245
282
  hasVerifiedContent(): this is AvailableCoValueCore {
246
283
  return !!this.verified;
247
284
  }
@@ -432,6 +469,8 @@ export class CoValueCore {
432
469
  new SessionMap(this.id, this.node.crypto, streamingKnownState),
433
470
  );
434
471
 
472
+ this.resetKnownStateCache();
473
+
435
474
  return true;
436
475
  }
437
476
 
@@ -487,20 +526,46 @@ export class CoValueCore {
487
526
  .then((core) => core.getCurrentContent());
488
527
  }
489
528
 
529
+ private _cachedKnownStateWithStreaming?: CoValueKnownState;
530
+ /**
531
+ * Returns the known state considering the known state of the streaming source
532
+ *
533
+ * Used to correctly manage the content & subscriptions during the content streaming process
534
+ */
490
535
  knownStateWithStreaming(): CoValueKnownState {
491
- if (this.verified) {
492
- return this.verified.knownStateWithStreaming();
493
- } else {
494
- return emptyKnownState(this.id);
536
+ if (this._cachedKnownStateWithStreaming) {
537
+ return this._cachedKnownStateWithStreaming;
495
538
  }
539
+
540
+ const knownState = this.verified
541
+ ? cloneKnownState(this.verified.knownStateWithStreaming())
542
+ : emptyKnownState(this.id);
543
+
544
+ this._cachedKnownStateWithStreaming = knownState;
545
+
546
+ return knownState;
496
547
  }
497
548
 
549
+ private _cachedKnownState?: CoValueKnownState;
550
+ /**
551
+ * Returns the known state of the CoValue
552
+ *
553
+ * The return value identity is going to be stable as long as the CoValue is not modified.
554
+ *
555
+ * On change the knownState is invalidated and a new object is returned.
556
+ */
498
557
  knownState(): CoValueKnownState {
499
- if (this.verified) {
500
- return this.verified.knownState();
501
- } else {
502
- return emptyKnownState(this.id);
558
+ if (this._cachedKnownState) {
559
+ return this._cachedKnownState;
503
560
  }
561
+
562
+ const knownState = this.verified
563
+ ? cloneKnownState(this.verified.knownState())
564
+ : emptyKnownState(this.id);
565
+
566
+ this._cachedKnownState = knownState;
567
+
568
+ return knownState;
504
569
  }
505
570
 
506
571
  get meta(): JsonValue {
@@ -575,6 +640,7 @@ export class CoValueCore {
575
640
  );
576
641
 
577
642
  if (result.isOk()) {
643
+ this.resetKnownStateCache();
578
644
  this.processNewTransactions();
579
645
  this.scheduleNotifyUpdate();
580
646
  }
@@ -583,6 +649,11 @@ export class CoValueCore {
583
649
  });
584
650
  }
585
651
 
652
+ private resetKnownStateCache() {
653
+ this._cachedKnownState = undefined;
654
+ this._cachedKnownStateWithStreaming = undefined;
655
+ }
656
+
586
657
  private processNewTransactions() {
587
658
  if (this._cachedContent) {
588
659
  // Does the cached content support incremental processing?
@@ -730,6 +801,7 @@ export class CoValueCore {
730
801
  const session = this.verified.sessions.get(sessionID);
731
802
  const txIdx = session ? session.transactions.length - 1 : 0;
732
803
 
804
+ this.resetKnownStateCache();
733
805
  this.processNewTransactions();
734
806
  this.addDependenciesFromNewTransaction(transaction);
735
807
 
@@ -768,10 +840,10 @@ export class CoValueCore {
768
840
  return this._cachedContent;
769
841
  }
770
842
 
771
- this.subscribeToGroupInvalidation();
772
-
773
843
  const newContent = coreToCoValue(this as AvailableCoValueCore, options);
774
844
 
845
+ this.subscribeToGroupInvalidation();
846
+
775
847
  if (!options?.ignorePrivateTransactions) {
776
848
  this._cachedContent = newContent;
777
849
  }
@@ -797,11 +869,20 @@ export class CoValueCore {
797
869
 
798
870
  for (const transaction of this.verifiedTransactions) {
799
871
  transaction.isValidated = false;
800
- transaction.hasMetaBeenParsed = false;
801
872
  }
873
+
874
+ this.toValidateTransactions = this.verifiedTransactions.slice();
875
+ this.toProcessTransactions = [];
876
+ this.toDecryptTransactions = [];
877
+ this.toParseMetaTransactions = [];
802
878
  }
803
879
 
804
880
  verifiedTransactions: VerifiedTransaction[] = [];
881
+ toValidateTransactions: VerifiedTransaction[] = [];
882
+ toDecryptTransactions: VerifiedTransaction[] = [];
883
+ toParseMetaTransactions: VerifiedTransaction[] = [];
884
+ toProcessTransactions: VerifiedTransaction[] = [];
885
+
805
886
  private verifiedTransactionsKnownSessions: CoValueKnownState["sessions"] = {};
806
887
 
807
888
  private lastVerifiedTransactionBySessionID: Record<
@@ -855,6 +936,7 @@ export class CoValueCore {
855
936
  isBranched ? this.id : undefined,
856
937
  cache,
857
938
  this.lastVerifiedTransactionBySessionID[sessionID],
939
+ this.dispatchTransaction,
858
940
  );
859
941
 
860
942
  if (verifiedTransaction.madeAt > this.latestTxMadeAt) {
@@ -866,6 +948,7 @@ export class CoValueCore {
866
948
  }
867
949
 
868
950
  this.verifiedTransactions.push(verifiedTransaction);
951
+ this.dispatchTransaction(verifiedTransaction);
869
952
  this.lastVerifiedTransactionBySessionID[sessionID] =
870
953
  verifiedTransaction;
871
954
  }
@@ -875,27 +958,39 @@ export class CoValueCore {
875
958
  }
876
959
  }
877
960
 
961
+ dispatchTransaction = (transaction: VerifiedTransaction) => {
962
+ if (!transaction.isValidated) {
963
+ this.toValidateTransactions.push(transaction);
964
+ return;
965
+ }
966
+
967
+ if (transaction.changes) {
968
+ this.toProcessTransactions.push(transaction);
969
+ } else {
970
+ this.toDecryptTransactions.push(transaction);
971
+ }
972
+
973
+ if (transaction.meta) {
974
+ this.toParseMetaTransactions.push(transaction);
975
+ }
976
+ };
977
+
878
978
  /**
879
979
  * Iterates over the verifiedTransactions and marks them as valid or invalid, based on the group membership of the authors of the transactions .
880
980
  */
881
981
  private determineValidTransactions() {
882
982
  determineValidTransactions(this);
983
+ this.toValidateTransactions = [];
883
984
  }
884
985
 
885
986
  /**
886
987
  * Parses the meta information of a transaction, and set the branchStart and mergeCommits.
887
988
  */
888
989
  private parseMetaInformation(transaction: VerifiedTransaction) {
889
- if (
890
- !transaction.meta ||
891
- !transaction.isValid ||
892
- transaction.hasMetaBeenParsed
893
- ) {
990
+ if (!transaction.meta) {
894
991
  return;
895
992
  }
896
993
 
897
- transaction.hasMetaBeenParsed = true;
898
-
899
994
  // Branch related meta information
900
995
  if (this.isBranched()) {
901
996
  // Check if the transaction is a branch start
@@ -945,7 +1040,7 @@ export class CoValueCore {
945
1040
  transaction.sourceTxMadeAt &&
946
1041
  transaction.sourceTxMadeAt > transaction.currentMadeAt
947
1042
  ) {
948
- transaction.isValid = false;
1043
+ transaction.markInvalid();
949
1044
  }
950
1045
 
951
1046
  if (sessionID) {
@@ -973,15 +1068,21 @@ export class CoValueCore {
973
1068
  if (!this.isAvailable()) {
974
1069
  return;
975
1070
  }
976
-
977
1071
  this.loadVerifiedTransactionsFromLogs();
978
1072
  this.determineValidTransactions();
979
1073
 
980
- for (const transaction of this.verifiedTransactions) {
981
- if (!ignorePrivateTransactions) {
1074
+ if (!ignorePrivateTransactions) {
1075
+ const toDecryptTransactions = this.toDecryptTransactions;
1076
+ this.toDecryptTransactions = [];
1077
+ for (const transaction of toDecryptTransactions) {
982
1078
  decryptTransactionChangesAndMeta(this, transaction);
1079
+ this.dispatchTransaction(transaction);
983
1080
  }
1081
+ }
984
1082
 
1083
+ const toParseMetaTransactions = this.toParseMetaTransactions;
1084
+ this.toParseMetaTransactions = [];
1085
+ for (const transaction of toParseMetaTransactions) {
985
1086
  this.parseMetaInformation(transaction);
986
1087
  }
987
1088
  }
@@ -994,9 +1095,7 @@ export class CoValueCore {
994
1095
  // The range, described as knownState sessions, to filter the transactions returned
995
1096
  from?: CoValueKnownState["sessions"];
996
1097
  to?: CoValueKnownState["sessions"];
997
-
998
- // The transactions that have already been processed, used for the incremental builds of the content views
999
- knownTransactions?: Set<Transaction>;
1098
+ knownTransactions?: Record<RawCoID, number>;
1000
1099
 
1001
1100
  // If true, the branch source transactions will be skipped. Used to gather the transactions for the merge operation.
1002
1101
  skipBranchSource?: boolean;
@@ -1011,39 +1110,48 @@ export class CoValueCore {
1011
1110
 
1012
1111
  const source = getBranchSource(this);
1013
1112
 
1014
- for (const transaction of this.verifiedTransactions) {
1015
- if (!transaction.isValidTransactionWithChanges()) {
1016
- continue;
1017
- }
1113
+ const from = options?.from;
1114
+ const to = options?.to;
1018
1115
 
1019
- if (options?.knownTransactions?.has(transaction.tx)) {
1116
+ const knownTransactions = options?.knownTransactions?.[this.id] ?? 0;
1117
+
1118
+ for (
1119
+ let i = knownTransactions;
1120
+ i < this.toProcessTransactions.length;
1121
+ i++
1122
+ ) {
1123
+ const transaction = this.toProcessTransactions[i]!;
1124
+
1125
+ if (!transaction.isValidTransactionWithChanges()) {
1020
1126
  continue;
1021
1127
  }
1022
1128
 
1023
- options?.knownTransactions?.add(transaction.tx);
1024
-
1025
1129
  // Using the currentTxID to filter the transactions, because the TxID is modified by the merge meta
1026
1130
  const txID = transaction.currentTxID;
1027
1131
 
1028
- const from = options?.from?.[txID.sessionID] ?? -1;
1132
+ const fromIdx = from?.[txID.sessionID] ?? -1;
1029
1133
 
1030
1134
  // Load the to filter index. Sessions that are not in the to filter will be skipped
1031
- const to = options?.to ? (options.to[txID.sessionID] ?? -1) : Infinity;
1135
+ const toIdx = to?.[txID.sessionID] ?? Infinity;
1032
1136
 
1033
1137
  // The txIndex starts at 0 and from/to are referring to the count of transactions
1034
- if (from > txID.txIndex || to < txID.txIndex) {
1138
+ if (fromIdx > txID.txIndex || toIdx < txID.txIndex) {
1035
1139
  continue;
1036
1140
  }
1037
1141
 
1038
1142
  matchingTransactions.push(transaction);
1039
1143
  }
1040
1144
 
1145
+ if (options?.knownTransactions !== undefined) {
1146
+ options.knownTransactions[this.id] = this.toProcessTransactions.length;
1147
+ }
1148
+
1041
1149
  // If this is a branch, we load the valid transactions from the source
1042
1150
  if (source && this.branchStart && !options?.skipBranchSource) {
1043
1151
  const sourceTransactions = source.getValidTransactions({
1152
+ knownTransactions: options?.knownTransactions,
1044
1153
  to: this.branchStart,
1045
1154
  ignorePrivateTransactions: options?.ignorePrivateTransactions ?? false,
1046
- knownTransactions: options?.knownTransactions,
1047
1155
  });
1048
1156
 
1049
1157
  for (const transaction of sourceTransactions) {
@@ -1064,12 +1172,14 @@ export class CoValueCore {
1064
1172
 
1065
1173
  const dependencyCoValue = this.node.getCoValue(dependency);
1066
1174
 
1067
- if (
1068
- !dependencyCoValue.isAvailable() &&
1069
- !this.isCircularMissingDependency(dependencyCoValue)
1070
- ) {
1071
- this.missingDependencies.add(dependency);
1175
+ if (this.isCircularMissingDependency(dependencyCoValue)) {
1176
+ return true;
1177
+ }
1178
+
1179
+ dependencyCoValue.addDependant(this.id);
1072
1180
 
1181
+ if (!dependencyCoValue.isAvailable()) {
1182
+ this.missingDependencies.add(dependency);
1073
1183
  dependencyCoValue.subscribe((dependencyCoValue, unsubscribe) => {
1074
1184
  if (dependencyCoValue.isAvailable()) {
1075
1185
  unsubscribe();
@@ -1080,6 +1190,27 @@ export class CoValueCore {
1080
1190
  }
1081
1191
  }
1082
1192
 
1193
+ dependant: Set<RawCoID> = new Set();
1194
+ private addDependant(dependant: RawCoID) {
1195
+ this.dependant.add(dependant);
1196
+ }
1197
+
1198
+ isGroup() {
1199
+ if (!this.verified) {
1200
+ return false;
1201
+ }
1202
+
1203
+ if (this.verified.header.ruleset.type !== "group") {
1204
+ return false;
1205
+ }
1206
+
1207
+ if (this.verified.header.meta?.type === "account") {
1208
+ return false;
1209
+ }
1210
+
1211
+ return true;
1212
+ }
1213
+
1083
1214
  createBranch(name: string, ownerId?: RawCoID) {
1084
1215
  return createBranch(this, name, ownerId);
1085
1216
  }
@@ -1137,7 +1268,7 @@ export class CoValueCore {
1137
1268
  ignorePrivateTransactions: boolean;
1138
1269
 
1139
1270
  // The transactions that have already been processed, used for the incremental builds of the content views
1140
- knownTransactions?: Set<Transaction>;
1271
+ knownTransactions?: Record<RawCoID, number>;
1141
1272
  }): DecryptedTransaction[] {
1142
1273
  const allTransactions = this.getValidTransactions(options);
1143
1274
 
@@ -6,7 +6,6 @@ export function decryptTransactionChangesAndMeta(
6
6
  ) {
7
7
  if (
8
8
  !transaction.isValid ||
9
- transaction.isDecrypted ||
10
9
  transaction.tx.privacy === "trusting" // Trusting transactions are already decrypted
11
10
  ) {
12
11
  return;
@@ -48,9 +47,4 @@ export function decryptTransactionChangesAndMeta(
48
47
  transaction.meta = meta;
49
48
  }
50
49
  }
51
-
52
- // We mark the transaction as decrypted even if the changes or meta have failed to be decrypted
53
- // This is because, if we successfully extracted the readKey and the decrypt failed once it will always fail
54
- // so better to log the error (we already do that) and mark the transaction as decrypted
55
- transaction.isDecrypted = true;
56
50
  }
@@ -55,8 +55,6 @@ export class VerifiedState {
55
55
  readonly crypto: CryptoProvider;
56
56
  readonly header: CoValueHeader;
57
57
  readonly sessions: SessionMap;
58
- private _cachedKnownState?: CoValueKnownState;
59
- private _cachedKnownStateWithStreaming?: CoValueKnownState;
60
58
  private _cachedNewContentSinceEmpty: NewContentMessage[] | undefined;
61
59
  public lastAccessed: number | undefined;
62
60
  public branchSourceId?: RawCoID;
@@ -102,8 +100,6 @@ export class VerifiedState {
102
100
 
103
101
  if (result.isOk()) {
104
102
  this._cachedNewContentSinceEmpty = undefined;
105
- this._cachedKnownState = undefined;
106
- this._cachedKnownStateWithStreaming = undefined;
107
103
  }
108
104
 
109
105
  return result;
@@ -125,8 +121,6 @@ export class VerifiedState {
125
121
  );
126
122
 
127
123
  this._cachedNewContentSinceEmpty = undefined;
128
- this._cachedKnownState = undefined;
129
- this._cachedKnownStateWithStreaming = undefined;
130
124
 
131
125
  return result;
132
126
  }
@@ -151,8 +145,6 @@ export class VerifiedState {
151
145
  );
152
146
 
153
147
  this._cachedNewContentSinceEmpty = undefined;
154
- this._cachedKnownState = undefined;
155
- this._cachedKnownStateWithStreaming = undefined;
156
148
 
157
149
  return result;
158
150
  }
@@ -286,39 +278,12 @@ export class VerifiedState {
286
278
  return piecesWithContent;
287
279
  }
288
280
 
289
- /**
290
- * Returns the known state of the CoValue
291
- *
292
- * The return value identity is going to be stable as long as the CoValue is not modified.
293
- *
294
- * On change the knownState is invalidated and a new object is returned.
295
- */
296
281
  knownState() {
297
- if (this._cachedKnownState) {
298
- return this._cachedKnownState;
299
- }
300
- this._cachedKnownState = cloneKnownState(this.sessions.knownState);
301
- return this._cachedKnownState;
282
+ return this.sessions.knownState;
302
283
  }
303
284
 
304
- /**
305
- * Returns the known state considering the known state of the streaming source
306
- *
307
- * Used to correctly manage the content & subscriptions during the content streaming process
308
- */
309
285
  knownStateWithStreaming() {
310
- if (!this.sessions.knownStateWithStreaming) {
311
- return this.knownState();
312
- }
313
-
314
- if (this._cachedKnownStateWithStreaming) {
315
- return this._cachedKnownStateWithStreaming;
316
- }
317
- this._cachedKnownStateWithStreaming = cloneKnownState(
318
- this.sessions.knownStateWithStreaming,
319
- );
320
-
321
- return this._cachedKnownStateWithStreaming;
286
+ return this.sessions.knownStateWithStreaming ?? this.knownState();
322
287
  }
323
288
 
324
289
  isStreaming(): boolean {
@@ -1,6 +1,6 @@
1
1
  import { CoID, RawCoValue } from "../coValue.js";
2
2
  import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
3
- import { AgentID, SessionID, TransactionID } from "../ids.js";
3
+ import { AgentID, SessionID, TransactionID, RawCoID } from "../ids.js";
4
4
  import { JsonObject, JsonValue } from "../jsonValue.js";
5
5
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
6
6
  import { isCoValue } from "../typeUtils/isCoValue.js";
@@ -85,11 +85,8 @@ export class RawCoList<
85
85
  opID: OpID;
86
86
  }[];
87
87
  /** @internal */
88
- knownTransactions: Set<Transaction>;
89
-
90
- get totalValidTransactions() {
91
- return this.knownTransactions.size;
92
- }
88
+ knownTransactions: Record<RawCoID, number>;
89
+ totalValidTransactions: number = 0;
93
90
 
94
91
  lastValidTransaction: number | undefined;
95
92
 
@@ -102,7 +99,7 @@ export class RawCoList<
102
99
  this.deletionsByInsertion = {};
103
100
  this.afterStart = [];
104
101
  this.beforeEnd = [];
105
- this.knownTransactions = new Set<Transaction>();
102
+ this.knownTransactions = { [core.id]: 0 };
106
103
 
107
104
  this.processNewTransactions();
108
105
  }
@@ -282,6 +279,8 @@ export class RawCoList<
282
279
  } else {
283
280
  this.lastValidTransaction = lastValidTransaction;
284
281
  }
282
+
283
+ this.totalValidTransactions += transactions.length;
285
284
  }
286
285
 
287
286
  /** @category 6. Meta */
@@ -669,6 +668,7 @@ export class RawCoList<
669
668
  this.insertions = listAfter.insertions;
670
669
  this.lastValidTransaction = listAfter.lastValidTransaction;
671
670
  this.knownTransactions = listAfter.knownTransactions;
671
+ this.totalValidTransactions = listAfter.totalValidTransactions;
672
672
  this.deletionsByInsertion = listAfter.deletionsByInsertion;
673
673
  this._cachedEntries = undefined;
674
674
  }
@@ -1,12 +1,11 @@
1
1
  import { CoID, RawCoValue } from "../coValue.js";
2
2
  import { AvailableCoValueCore } from "../coValueCore/coValueCore.js";
3
- import { AgentID, TransactionID } from "../ids.js";
3
+ import { AgentID, RawCoID, TransactionID } from "../ids.js";
4
4
  import { JsonObject, JsonValue } from "../jsonValue.js";
5
5
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
6
6
  import { isCoValue } from "../typeUtils/isCoValue.js";
7
7
  import { RawAccountID } from "./account.js";
8
8
  import type { RawGroup } from "./group.js";
9
- import { Transaction } from "../coValueCore/verifiedState.js";
10
9
 
11
10
  type MapOp<K extends string, V extends JsonValue | undefined> = {
12
11
  txID: TransactionID;
@@ -61,7 +60,7 @@ export class RawCoMapView<
61
60
  [Key in keyof Shape & string]?: MapOp<Key, Shape[Key]>[];
62
61
  };
63
62
  /** @internal */
64
- knownTransactions: Set<Transaction>;
63
+ knownTransactions: Record<RawCoID, number>;
65
64
 
66
65
  /** @internal */
67
66
  ignorePrivateTransactions: boolean;
@@ -70,9 +69,7 @@ export class RawCoMapView<
70
69
  /** @category 6. Meta */
71
70
  readonly _shape!: Shape;
72
71
 
73
- get totalValidTransactions() {
74
- return this.knownTransactions.size;
75
- }
72
+ totalValidTransactions: number = 0;
76
73
 
77
74
  /** @internal */
78
75
  constructor(
@@ -88,7 +85,10 @@ export class RawCoMapView<
88
85
  options?.ignorePrivateTransactions ?? false;
89
86
  this.ops = {};
90
87
  this.latest = {};
91
- this.knownTransactions = new Set<Transaction>();
88
+
89
+ // We track the knownTransacions in multiple CoValues because branches
90
+ // need to retrieve the transactions from both the source and the branch
91
+ this.knownTransactions = { [core.id]: 0 };
92
92
 
93
93
  this.processNewTransactions();
94
94
  }
@@ -147,6 +147,8 @@ export class RawCoMapView<
147
147
  for (const [key, entries] of changedEntries.entries()) {
148
148
  this.latest[key] = entries[entries.length - 1];
149
149
  }
150
+
151
+ this.totalValidTransactions += newValidTransactions.length;
150
152
  }
151
153
 
152
154
  isTimeTravelEntity() {
@@ -10,6 +10,7 @@ import { isCoValue } from "../typeUtils/isCoValue.js";
10
10
  import { RawAccountID } from "./account.js";
11
11
  import { RawGroup } from "./group.js";
12
12
  import { Transaction } from "../coValueCore/verifiedState.js";
13
+ import { RawCoID } from "../ids.js";
13
14
 
14
15
  export type BinaryStreamInfo = {
15
16
  mimeType: string;
@@ -55,18 +56,16 @@ export class RawCoStreamView<
55
56
  [key: SessionID]: CoStreamItem<Item>[];
56
57
  };
57
58
  /** @internal */
58
- knownTransactions: Set<Transaction>;
59
+ knownTransactions: Record<RawCoID, number>;
59
60
  readonly _item!: Item;
60
61
 
61
- get totalValidTransactions() {
62
- return this.knownTransactions.size;
63
- }
62
+ totalValidTransactions: number = 0;
64
63
 
65
64
  constructor(core: AvailableCoValueCore) {
66
65
  this.id = core.id as CoID<this>;
67
66
  this.core = core;
68
67
  this.items = {};
69
- this.knownTransactions = new Set<Transaction>();
68
+ this.knownTransactions = { [core.id]: 0 };
70
69
  this.processNewTransactions();
71
70
  }
72
71
 
@@ -128,6 +127,8 @@ export class RawCoStreamView<
128
127
  for (const entries of changeEntries) {
129
128
  entries.sort(this.compareStreamItems);
130
129
  }
130
+
131
+ this.totalValidTransactions += newValidTransactions.length;
131
132
  }
132
133
 
133
134
  getSingleStream(): Item[] | undefined {