cojson 0.16.3 → 0.16.5

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 (138) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +20 -0
  3. package/dist/coValue.d.ts +1 -1
  4. package/dist/coValue.d.ts.map +1 -1
  5. package/dist/coValue.js.map +1 -1
  6. package/dist/coValueContentMessage.d.ts +10 -0
  7. package/dist/coValueContentMessage.d.ts.map +1 -0
  8. package/dist/coValueContentMessage.js +46 -0
  9. package/dist/coValueContentMessage.js.map +1 -0
  10. package/dist/coValueCore/coValueCore.d.ts +6 -10
  11. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  12. package/dist/coValueCore/coValueCore.js +20 -125
  13. package/dist/coValueCore/coValueCore.js.map +1 -1
  14. package/dist/coValueCore/verifiedState.d.ts +1 -0
  15. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  16. package/dist/coValueCore/verifiedState.js +14 -27
  17. package/dist/coValueCore/verifiedState.js.map +1 -1
  18. package/dist/coValues/group.d.ts +18 -10
  19. package/dist/coValues/group.d.ts.map +1 -1
  20. package/dist/coValues/group.js +237 -67
  21. package/dist/coValues/group.js.map +1 -1
  22. package/dist/ids.d.ts +3 -3
  23. package/dist/ids.d.ts.map +1 -1
  24. package/dist/ids.js.map +1 -1
  25. package/dist/localNode.d.ts +11 -6
  26. package/dist/localNode.d.ts.map +1 -1
  27. package/dist/localNode.js +7 -2
  28. package/dist/localNode.js.map +1 -1
  29. package/dist/queue/LocalTransactionsSyncQueue.d.ts +24 -0
  30. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -0
  31. package/dist/queue/LocalTransactionsSyncQueue.js +55 -0
  32. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -0
  33. package/dist/queue/StoreQueue.d.ts +9 -6
  34. package/dist/queue/StoreQueue.d.ts.map +1 -1
  35. package/dist/queue/StoreQueue.js +10 -2
  36. package/dist/queue/StoreQueue.js.map +1 -1
  37. package/dist/storage/storageAsync.d.ts +11 -3
  38. package/dist/storage/storageAsync.d.ts.map +1 -1
  39. package/dist/storage/storageAsync.js +59 -46
  40. package/dist/storage/storageAsync.js.map +1 -1
  41. package/dist/storage/storageSync.d.ts +9 -3
  42. package/dist/storage/storageSync.d.ts.map +1 -1
  43. package/dist/storage/storageSync.js +48 -35
  44. package/dist/storage/storageSync.js.map +1 -1
  45. package/dist/storage/syncUtils.d.ts +2 -1
  46. package/dist/storage/syncUtils.d.ts.map +1 -1
  47. package/dist/storage/syncUtils.js +4 -0
  48. package/dist/storage/syncUtils.js.map +1 -1
  49. package/dist/storage/types.d.ts +3 -2
  50. package/dist/storage/types.d.ts.map +1 -1
  51. package/dist/sync.d.ts +6 -6
  52. package/dist/sync.d.ts.map +1 -1
  53. package/dist/sync.js +33 -56
  54. package/dist/sync.js.map +1 -1
  55. package/dist/tests/StorageApiAsync.test.d.ts +2 -0
  56. package/dist/tests/StorageApiAsync.test.d.ts.map +1 -0
  57. package/dist/tests/StorageApiAsync.test.js +574 -0
  58. package/dist/tests/StorageApiAsync.test.js.map +1 -0
  59. package/dist/tests/StorageApiSync.test.d.ts +2 -0
  60. package/dist/tests/StorageApiSync.test.d.ts.map +1 -0
  61. package/dist/tests/StorageApiSync.test.js +426 -0
  62. package/dist/tests/StorageApiSync.test.js.map +1 -0
  63. package/dist/tests/StoreQueue.test.js +9 -21
  64. package/dist/tests/StoreQueue.test.js.map +1 -1
  65. package/dist/tests/SyncStateManager.test.js +18 -8
  66. package/dist/tests/SyncStateManager.test.js.map +1 -1
  67. package/dist/tests/group.inheritance.test.js +274 -2
  68. package/dist/tests/group.inheritance.test.js.map +1 -1
  69. package/dist/tests/group.removeMember.test.js +152 -1
  70. package/dist/tests/group.removeMember.test.js.map +1 -1
  71. package/dist/tests/group.roleOf.test.js +2 -2
  72. package/dist/tests/group.roleOf.test.js.map +1 -1
  73. package/dist/tests/group.test.js +81 -3
  74. package/dist/tests/group.test.js.map +1 -1
  75. package/dist/tests/sync.auth.test.js +22 -10
  76. package/dist/tests/sync.auth.test.js.map +1 -1
  77. package/dist/tests/sync.load.test.js +30 -25
  78. package/dist/tests/sync.load.test.js.map +1 -1
  79. package/dist/tests/sync.mesh.test.js +12 -6
  80. package/dist/tests/sync.mesh.test.js.map +1 -1
  81. package/dist/tests/sync.peerReconciliation.test.js +6 -4
  82. package/dist/tests/sync.peerReconciliation.test.js.map +1 -1
  83. package/dist/tests/sync.storage.test.js +8 -14
  84. package/dist/tests/sync.storage.test.js.map +1 -1
  85. package/dist/tests/sync.storageAsync.test.js +31 -14
  86. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  87. package/dist/tests/sync.test.js +5 -9
  88. package/dist/tests/sync.test.js.map +1 -1
  89. package/dist/tests/sync.upload.test.js +31 -1
  90. package/dist/tests/sync.upload.test.js.map +1 -1
  91. package/dist/tests/testStorage.d.ts +2 -3
  92. package/dist/tests/testStorage.d.ts.map +1 -1
  93. package/dist/tests/testStorage.js +16 -8
  94. package/dist/tests/testStorage.js.map +1 -1
  95. package/dist/tests/testUtils.d.ts +4 -0
  96. package/dist/tests/testUtils.d.ts.map +1 -1
  97. package/dist/tests/testUtils.js +22 -4
  98. package/dist/tests/testUtils.js.map +1 -1
  99. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts +2 -2
  100. package/dist/typeUtils/accountOrAgentIDfromSessionID.d.ts.map +1 -1
  101. package/dist/typeUtils/expectGroup.d.ts.map +1 -1
  102. package/dist/typeUtils/expectGroup.js +6 -5
  103. package/dist/typeUtils/expectGroup.js.map +1 -1
  104. package/package.json +1 -1
  105. package/src/coValue.ts +1 -4
  106. package/src/coValueContentMessage.ts +73 -0
  107. package/src/coValueCore/coValueCore.ts +36 -192
  108. package/src/coValueCore/verifiedState.ts +28 -35
  109. package/src/coValues/group.ts +329 -99
  110. package/src/ids.ts +3 -3
  111. package/src/localNode.ts +15 -10
  112. package/src/queue/LocalTransactionsSyncQueue.ts +96 -0
  113. package/src/queue/StoreQueue.ts +22 -12
  114. package/src/storage/storageAsync.ts +78 -56
  115. package/src/storage/storageSync.ts +66 -45
  116. package/src/storage/syncUtils.ts +9 -1
  117. package/src/storage/types.ts +6 -5
  118. package/src/sync.ts +47 -67
  119. package/src/tests/StorageApiAsync.test.ts +829 -0
  120. package/src/tests/StorageApiSync.test.ts +628 -0
  121. package/src/tests/StoreQueue.test.ts +10 -24
  122. package/src/tests/SyncStateManager.test.ts +22 -21
  123. package/src/tests/group.inheritance.test.ts +415 -1
  124. package/src/tests/group.removeMember.test.ts +244 -1
  125. package/src/tests/group.roleOf.test.ts +2 -2
  126. package/src/tests/group.test.ts +105 -5
  127. package/src/tests/sync.auth.test.ts +22 -10
  128. package/src/tests/sync.load.test.ts +32 -26
  129. package/src/tests/sync.mesh.test.ts +12 -6
  130. package/src/tests/sync.peerReconciliation.test.ts +6 -4
  131. package/src/tests/sync.storage.test.ts +8 -14
  132. package/src/tests/sync.storageAsync.test.ts +39 -14
  133. package/src/tests/sync.test.ts +6 -14
  134. package/src/tests/sync.upload.test.ts +38 -1
  135. package/src/tests/testStorage.ts +19 -13
  136. package/src/tests/testUtils.ts +29 -5
  137. package/src/typeUtils/accountOrAgentIDfromSessionID.ts +2 -2
  138. package/src/typeUtils/expectGroup.ts +8 -5
@@ -0,0 +1,73 @@
1
+ import {
2
+ CoValueHeader,
3
+ Transaction,
4
+ VerifiedState,
5
+ } from "./coValueCore/verifiedState.js";
6
+ import { MAX_RECOMMENDED_TX_SIZE } from "./config.js";
7
+ import { Signature } from "./crypto/crypto.js";
8
+ import { RawCoID, SessionID } from "./ids.js";
9
+ import { getPriorityFromHeader } from "./priority.js";
10
+ import { NewContentMessage, emptyKnownState } from "./sync.js";
11
+
12
+ export function createContentMessage(
13
+ id: RawCoID,
14
+ header: CoValueHeader,
15
+ includeHeader = true,
16
+ ): NewContentMessage {
17
+ return {
18
+ action: "content",
19
+ id,
20
+ header: includeHeader ? header : undefined,
21
+ priority: getPriorityFromHeader(header),
22
+ new: {},
23
+ };
24
+ }
25
+
26
+ export function addTransactionToContentMessage(
27
+ content: NewContentMessage,
28
+ transaction: Transaction,
29
+ sessionID: SessionID,
30
+ signature: Signature,
31
+ txIdx: number,
32
+ ) {
33
+ const sessionContent = content.new[sessionID];
34
+
35
+ if (sessionContent) {
36
+ sessionContent.newTransactions.push(transaction);
37
+ sessionContent.lastSignature = signature;
38
+ } else {
39
+ content.new[sessionID] = {
40
+ after: txIdx,
41
+ newTransactions: [transaction],
42
+ lastSignature: signature,
43
+ };
44
+ }
45
+ }
46
+
47
+ export function getTransactionSize(transaction: Transaction) {
48
+ return transaction.privacy === "private"
49
+ ? transaction.encryptedChanges.length
50
+ : transaction.changes.length;
51
+ }
52
+
53
+ export function exceedsRecommendedSize(
54
+ baseSize: number,
55
+ transactionSize?: number,
56
+ ) {
57
+ if (transactionSize === undefined) {
58
+ return baseSize > MAX_RECOMMENDED_TX_SIZE;
59
+ }
60
+
61
+ return baseSize + transactionSize > MAX_RECOMMENDED_TX_SIZE;
62
+ }
63
+
64
+ export function knownStateFromContent(content: NewContentMessage) {
65
+ const knownState = emptyKnownState(content.id);
66
+
67
+ for (const [sessionID, session] of Object.entries(content.new)) {
68
+ knownState.sessions[sessionID as SessionID] =
69
+ session.after + session.newTransactions.length;
70
+ }
71
+
72
+ return knownState;
73
+ }
@@ -1,10 +1,10 @@
1
1
  import { UpDownCounter, ValueType, metrics } from "@opentelemetry/api";
2
2
  import { Result, err } from "neverthrow";
3
- import { PeerState } from "../PeerState.js";
4
- import { RawCoValue } from "../coValue.js";
5
- import { ControlledAccountOrAgent, RawAccountID } from "../coValues/account.js";
6
- import { RawGroup } from "../coValues/group.js";
7
- import { CO_VALUE_LOADING_CONFIG, MAX_RECOMMENDED_TX_SIZE } from "../config.js";
3
+ import type { PeerState } from "../PeerState.js";
4
+ import type { RawCoValue } from "../coValue.js";
5
+ import type { ControlledAccountOrAgent } from "../coValues/account.js";
6
+ import type { RawGroup } from "../coValues/group.js";
7
+ import { CO_VALUE_LOADING_CONFIG } from "../config.js";
8
8
  import { coreToCoValue } from "../coreToCoValue.js";
9
9
  import {
10
10
  CryptoProvider,
@@ -16,25 +16,15 @@ import {
16
16
  SignerID,
17
17
  StreamingHash,
18
18
  } from "../crypto/crypto.js";
19
- import {
20
- RawCoID,
21
- SessionID,
22
- TransactionID,
23
- getParentGroupId,
24
- isParentGroupReference,
25
- } from "../ids.js";
19
+ import { RawCoID, SessionID, TransactionID } from "../ids.js";
26
20
  import { parseJSON, stableStringify } from "../jsonStringify.js";
27
21
  import { JsonValue } from "../jsonValue.js";
28
22
  import { LocalNode, ResolveAccountAgentError } from "../localNode.js";
29
23
  import { logger } from "../logger.js";
30
- import {
31
- determineValidTransactions,
32
- isKeyForKeyField,
33
- } from "../permissions.js";
24
+ import { determineValidTransactions } from "../permissions.js";
34
25
  import { CoValueKnownState, PeerID, emptyKnownState } from "../sync.js";
35
26
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
36
27
  import { expectGroup } from "../typeUtils/expectGroup.js";
37
- import { isAccountID } from "../typeUtils/isAccountID.js";
38
28
  import { getDependedOnCoValuesFromRawData } from "./utils.js";
39
29
  import { CoValueHeader, Transaction, VerifiedState } from "./verifiedState.js";
40
30
 
@@ -53,8 +43,6 @@ export type DecryptedTransaction = {
53
43
  trusting?: boolean;
54
44
  };
55
45
 
56
- const readKeyCache = new WeakMap<CoValueCore, { [id: KeyID]: KeySecret }>();
57
-
58
46
  export type AvailableCoValueCore = CoValueCore & { verified: VerifiedState };
59
47
 
60
48
  export class CoValueCore {
@@ -380,7 +368,7 @@ export class CoValueCore {
380
368
  }
381
369
 
382
370
  knownStateWithStreaming(): CoValueKnownState {
383
- if (this.isAvailable()) {
371
+ if (this.verified) {
384
372
  return this.verified.knownStateWithStreaming();
385
373
  } else {
386
374
  return emptyKnownState(this.id);
@@ -388,7 +376,7 @@ export class CoValueCore {
388
376
  }
389
377
 
390
378
  knownState(): CoValueKnownState {
391
- if (this.isAvailable()) {
379
+ if (this.verified) {
392
380
  return this.verified.knownState();
393
381
  } else {
394
382
  return emptyKnownState(this.id);
@@ -605,8 +593,17 @@ export class CoValueCore {
605
593
  )._unsafeUnwrap({ withStackTrace: true });
606
594
 
607
595
  if (success) {
596
+ const session = this.verified.sessions.get(sessionID);
597
+ const txIdx = session ? session.transactions.length - 1 : 0;
598
+
608
599
  this.node.syncManager.recordTransactionsSize([transaction], "local");
609
- void this.node.syncManager.requestCoValueSync(this);
600
+ this.node.syncManager.syncLocalTransaction(
601
+ this.verified,
602
+ transaction,
603
+ sessionID,
604
+ signature,
605
+ txIdx,
606
+ );
610
607
  }
611
608
 
612
609
  return success;
@@ -759,20 +756,7 @@ export class CoValueCore {
759
756
  }
760
757
 
761
758
  if (this.verified.header.ruleset.type === "group") {
762
- const content = expectGroup(this.getCurrentContent());
763
-
764
- const currentKeyId = content.getCurrentReadKeyId();
765
-
766
- if (!currentKeyId) {
767
- throw new Error("No readKey set");
768
- }
769
-
770
- const secret = this.getReadKey(currentKeyId);
771
-
772
- return {
773
- secret: secret,
774
- id: currentKeyId,
775
- };
759
+ return expectGroup(this.getCurrentContent()).getCurrentReadKey();
776
760
  } else if (this.verified.header.ruleset.type === "ownedByGroup") {
777
761
  return this.node
778
762
  .expectCoValueLoaded(this.verified.header.ruleset.group)
@@ -784,154 +768,36 @@ export class CoValueCore {
784
768
  }
785
769
  }
786
770
 
771
+ readKeyCache = new Map<KeyID, KeySecret>();
787
772
  getReadKey(keyID: KeyID): KeySecret | undefined {
788
- let key = readKeyCache.get(this)?.[keyID];
789
- if (!key) {
790
- key = this.getUncachedReadKey(keyID);
791
- if (key) {
792
- let cache = readKeyCache.get(this);
793
- if (!cache) {
794
- cache = {};
795
- readKeyCache.set(this, cache);
796
- }
797
- cache[keyID] = key;
798
- }
773
+ // We want to check the cache here, to skip re-computing the group content
774
+ const cachedSecret = this.readKeyCache.get(keyID);
775
+
776
+ if (cachedSecret) {
777
+ return cachedSecret;
799
778
  }
800
- return key;
801
- }
802
779
 
803
- getUncachedReadKey(keyID: KeyID): KeySecret | undefined {
804
780
  if (!this.verified) {
805
781
  throw new Error(
806
782
  "CoValueCore: getUncachedReadKey called on coValue without verified state",
807
783
  );
808
784
  }
809
785
 
786
+ // Getting the readKey from accounts
810
787
  if (this.verified.header.ruleset.type === "group") {
811
788
  const content = expectGroup(
812
- this.getCurrentContent({ ignorePrivateTransactions: true }), // to prevent recursion
813
- );
814
- const keyForEveryone = content.get(`${keyID}_for_everyone`);
815
- if (keyForEveryone) {
816
- return keyForEveryone;
817
- }
818
-
819
- // Try to find key revelation for us
820
- const currentAgentOrAccountID = accountOrAgentIDfromSessionID(
821
- this.node.currentSessionID,
789
+ // load the account without private transactions, because we are here
790
+ // to be able to decrypt those
791
+ this.getCurrentContent({ ignorePrivateTransactions: true }),
822
792
  );
823
793
 
824
- // being careful here to avoid recursion
825
- const lookupAccountOrAgentID = isAccountID(currentAgentOrAccountID)
826
- ? this.id === currentAgentOrAccountID
827
- ? this.crypto.getAgentID(this.node.agentSecret) // in accounts, the read key is revealed for the primitive agent
828
- : currentAgentOrAccountID // current account ID
829
- : currentAgentOrAccountID; // current agent ID
830
-
831
- const lastReadyKeyEdit = content.lastEditAt(
832
- `${keyID}_for_${lookupAccountOrAgentID}`,
833
- );
834
-
835
- if (lastReadyKeyEdit?.value) {
836
- const revealer = lastReadyKeyEdit.by;
837
- const revealerAgent = this.node
838
- .resolveAccountAgent(revealer, "Expected to know revealer")
839
- ._unsafeUnwrap({ withStackTrace: true });
840
-
841
- const secret = this.crypto.unseal(
842
- lastReadyKeyEdit.value,
843
- this.crypto.getAgentSealerSecret(this.node.agentSecret), // being careful here to avoid recursion
844
- this.crypto.getAgentSealerID(revealerAgent),
845
- {
846
- in: this.id,
847
- tx: lastReadyKeyEdit.tx,
848
- },
849
- );
850
-
851
- if (secret) {
852
- return secret as KeySecret;
853
- }
854
- }
855
-
856
- // Try to find indirect revelation through previousKeys
857
-
858
- for (const co of content.keys()) {
859
- if (isKeyForKeyField(co) && co.startsWith(keyID)) {
860
- const encryptingKeyID = co.split("_for_")[1] as KeyID;
861
- const encryptingKeySecret = this.getReadKey(encryptingKeyID);
862
-
863
- if (!encryptingKeySecret) {
864
- continue;
865
- }
866
-
867
- const encryptedPreviousKey = content.get(co)!;
868
-
869
- const secret = this.crypto.decryptKeySecret(
870
- {
871
- encryptedID: keyID,
872
- encryptingID: encryptingKeyID,
873
- encrypted: encryptedPreviousKey,
874
- },
875
- encryptingKeySecret,
876
- );
877
-
878
- if (secret) {
879
- return secret as KeySecret;
880
- } else {
881
- logger.warn(
882
- `Encrypting ${encryptingKeyID} key didn't decrypt ${keyID}`,
883
- );
884
- }
885
- }
886
- }
887
-
888
- // try to find revelation to parent group read keys
889
- for (const co of content.keys()) {
890
- if (isParentGroupReference(co)) {
891
- const parentGroupID = getParentGroupId(co);
892
- const parentGroup = this.node.expectCoValueLoaded(
893
- parentGroupID,
894
- "Expected parent group to be loaded",
895
- );
896
-
897
- const parentKeys = this.findValidParentKeys(
898
- keyID,
899
- content,
900
- parentGroup,
901
- );
902
-
903
- for (const parentKey of parentKeys) {
904
- const revelationForParentKey = content.get(
905
- `${keyID}_for_${parentKey.id}`,
906
- );
907
-
908
- if (revelationForParentKey) {
909
- const secret = parentGroup.crypto.decryptKeySecret(
910
- {
911
- encryptedID: keyID,
912
- encryptingID: parentKey.id,
913
- encrypted: revelationForParentKey,
914
- },
915
- parentKey.secret,
916
- );
917
-
918
- if (secret) {
919
- return secret as KeySecret;
920
- } else {
921
- logger.warn(
922
- `Encrypting parent ${parentKey.id} key didn't decrypt ${keyID}`,
923
- );
924
- }
925
- }
926
- }
927
- }
928
- }
929
-
930
- return undefined;
794
+ return content.getReadKey(keyID);
931
795
  } else if (this.verified.header.ruleset.type === "ownedByGroup") {
932
- return this.node
933
- .expectCoValueLoaded(this.verified.header.ruleset.group)
934
- .getReadKey(keyID);
796
+ return expectGroup(
797
+ this.node
798
+ .expectCoValueLoaded(this.verified.header.ruleset.group)
799
+ .getCurrentContent(),
800
+ ).getReadKey(keyID);
935
801
  } else {
936
802
  throw new Error(
937
803
  "Only groups or values owned by groups have read secrets",
@@ -939,28 +805,6 @@ export class CoValueCore {
939
805
  }
940
806
  }
941
807
 
942
- findValidParentKeys(keyID: KeyID, group: RawGroup, parentGroup: CoValueCore) {
943
- const validParentKeys: { id: KeyID; secret: KeySecret }[] = [];
944
-
945
- for (const co of group.keys()) {
946
- if (isKeyForKeyField(co) && co.startsWith(keyID)) {
947
- const encryptingKeyID = co.split("_for_")[1] as KeyID;
948
- const encryptingKeySecret = parentGroup.getReadKey(encryptingKeyID);
949
-
950
- if (!encryptingKeySecret) {
951
- continue;
952
- }
953
-
954
- validParentKeys.push({
955
- id: encryptingKeyID,
956
- secret: encryptingKeySecret,
957
- });
958
- }
959
- }
960
-
961
- return validParentKeys;
962
- }
963
-
964
808
  getGroup(): RawGroup {
965
809
  if (!this.verified) {
966
810
  throw new Error(
@@ -1,6 +1,10 @@
1
1
  import { Result, err, ok } from "neverthrow";
2
2
  import { AnyRawCoValue } from "../coValue.js";
3
- import { MAX_RECOMMENDED_TX_SIZE } from "../config.js";
3
+ import {
4
+ createContentMessage,
5
+ exceedsRecommendedSize,
6
+ getTransactionSize,
7
+ } from "../coValueContentMessage.js";
4
8
  import {
5
9
  CryptoProvider,
6
10
  Encrypted,
@@ -14,7 +18,6 @@ import { RawCoID, SessionID, TransactionID } from "../ids.js";
14
18
  import { Stringified } from "../jsonStringify.js";
15
19
  import { JsonObject, JsonValue } from "../jsonValue.js";
16
20
  import { PermissionsDef as RulesetDef } from "../permissions.js";
17
- import { getPriorityFromHeader } from "../priority.js";
18
21
  import { CoValueKnownState, NewContentMessage } from "../sync.js";
19
22
  import { InvalidHashError, InvalidSignatureError } from "./coValueCore.js";
20
23
  import { TryAddTransactionsError } from "./coValueCore.js";
@@ -151,6 +154,17 @@ export class VerifiedState {
151
154
  return ok(true as const);
152
155
  }
153
156
 
157
+ getLastSignatureCheckpoint(sessionID: SessionID): number {
158
+ const sessionLog = this.sessions.get(sessionID);
159
+
160
+ if (!sessionLog?.signatureAfter) return -1;
161
+
162
+ return Object.keys(sessionLog.signatureAfter).reduce(
163
+ (max, idx) => Math.max(max, parseInt(idx)),
164
+ -1,
165
+ );
166
+ }
167
+
154
168
  private doAddTransactions(
155
169
  sessionID: SessionID,
156
170
  newTransactions: Transaction[],
@@ -165,24 +179,14 @@ export class VerifiedState {
165
179
  }
166
180
 
167
181
  const signatureAfter = sessionLog?.signatureAfter ?? {};
168
-
169
- const lastInbetweenSignatureIdx = Object.keys(signatureAfter).reduce(
170
- (max, idx) => (parseInt(idx) > max ? parseInt(idx) : max),
171
- -1,
172
- );
182
+ const lastInbetweenSignatureIdx =
183
+ this.getLastSignatureCheckpoint(sessionID);
173
184
 
174
185
  const sizeOfTxsSinceLastInbetweenSignature = transactions
175
186
  .slice(lastInbetweenSignatureIdx + 1)
176
- .reduce(
177
- (sum, tx) =>
178
- sum +
179
- (tx.privacy === "private"
180
- ? tx.encryptedChanges.length
181
- : tx.changes.length),
182
- 0,
183
- );
187
+ .reduce((sum, tx) => sum + getTransactionSize(tx), 0);
184
188
 
185
- if (sizeOfTxsSinceLastInbetweenSignature > MAX_RECOMMENDED_TX_SIZE) {
189
+ if (exceedsRecommendedSize(sizeOfTxsSinceLastInbetweenSignature)) {
186
190
  signatureAfter[transactions.length - 1] = newSignature;
187
191
  }
188
192
 
@@ -242,13 +246,11 @@ export class VerifiedState {
242
246
  return this._cachedNewContentSinceEmpty;
243
247
  }
244
248
 
245
- let currentPiece: NewContentMessage = {
246
- action: "content",
247
- id: this.id,
248
- header: knownState?.header ? undefined : this.header,
249
- priority: getPriorityFromHeader(this.header),
250
- new: {},
251
- };
249
+ let currentPiece: NewContentMessage = createContentMessage(
250
+ this.id,
251
+ this.header,
252
+ !knownState?.header,
253
+ );
252
254
 
253
255
  const pieces = [currentPiece];
254
256
 
@@ -299,25 +301,16 @@ export class VerifiedState {
299
301
  const oldPieceSize = pieceSize;
300
302
  for (let txIdx = firstNewTxIdx; txIdx < afterLastNewTxIdx; txIdx++) {
301
303
  const tx = log.transactions[txIdx]!;
302
- pieceSize +=
303
- tx.privacy === "private"
304
- ? tx.encryptedChanges.length
305
- : tx.changes.length;
304
+ pieceSize += getTransactionSize(tx);
306
305
  }
307
306
 
308
- if (pieceSize >= MAX_RECOMMENDED_TX_SIZE) {
307
+ if (exceedsRecommendedSize(pieceSize)) {
309
308
  if (!currentPiece.expectContentUntil && pieces.length === 1) {
310
309
  currentPiece.expectContentUntil =
311
310
  this.knownStateWithStreaming().sessions;
312
311
  }
313
312
 
314
- currentPiece = {
315
- action: "content",
316
- id: this.id,
317
- header: undefined,
318
- new: {},
319
- priority: getPriorityFromHeader(this.header),
320
- };
313
+ currentPiece = createContentMessage(this.id, this.header, false);
321
314
  pieces.push(currentPiece);
322
315
  pieceSize = pieceSize - oldPieceSize;
323
316
  }