cojson 0.18.26 → 0.18.28

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 (161) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/dist/PeerKnownStates.d.ts +4 -3
  4. package/dist/PeerKnownStates.d.ts.map +1 -1
  5. package/dist/PeerKnownStates.js +27 -18
  6. package/dist/PeerKnownStates.js.map +1 -1
  7. package/dist/PeerState.d.ts +3 -2
  8. package/dist/PeerState.d.ts.map +1 -1
  9. package/dist/PeerState.js.map +1 -1
  10. package/dist/SyncStateManager.d.ts +2 -2
  11. package/dist/SyncStateManager.d.ts.map +1 -1
  12. package/dist/SyncStateManager.js +2 -10
  13. package/dist/SyncStateManager.js.map +1 -1
  14. package/dist/coValueContentMessage.d.ts +1 -1
  15. package/dist/coValueContentMessage.d.ts.map +1 -1
  16. package/dist/coValueContentMessage.js +1 -1
  17. package/dist/coValueContentMessage.js.map +1 -1
  18. package/dist/coValueCore/SessionMap.d.ts +6 -3
  19. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  20. package/dist/coValueCore/SessionMap.js +41 -8
  21. package/dist/coValueCore/SessionMap.js.map +1 -1
  22. package/dist/coValueCore/branching.d.ts +5 -4
  23. package/dist/coValueCore/branching.d.ts.map +1 -1
  24. package/dist/coValueCore/branching.js +22 -4
  25. package/dist/coValueCore/branching.js.map +1 -1
  26. package/dist/coValueCore/coValueCore.d.ts +29 -25
  27. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  28. package/dist/coValueCore/coValueCore.js +163 -126
  29. package/dist/coValueCore/coValueCore.js.map +1 -1
  30. package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts +3 -0
  31. package/dist/coValueCore/decryptTransactionChangesAndMeta.d.ts.map +1 -0
  32. package/dist/coValueCore/decryptTransactionChangesAndMeta.js +34 -0
  33. package/dist/coValueCore/decryptTransactionChangesAndMeta.js.map +1 -0
  34. package/dist/coValueCore/verifiedState.d.ts +12 -6
  35. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  36. package/dist/coValueCore/verifiedState.js +28 -56
  37. package/dist/coValueCore/verifiedState.js.map +1 -1
  38. package/dist/coValues/coMap.d.ts.map +1 -1
  39. package/dist/coValues/coMap.js.map +1 -1
  40. package/dist/coValues/coStream.d.ts.map +1 -1
  41. package/dist/coValues/coStream.js.map +1 -1
  42. package/dist/exports.d.ts +3 -2
  43. package/dist/exports.d.ts.map +1 -1
  44. package/dist/exports.js +2 -1
  45. package/dist/exports.js.map +1 -1
  46. package/dist/knownState.d.ts +58 -2
  47. package/dist/knownState.d.ts.map +1 -1
  48. package/dist/knownState.js +79 -5
  49. package/dist/knownState.js.map +1 -1
  50. package/dist/localNode.js +1 -1
  51. package/dist/localNode.js.map +1 -1
  52. package/dist/permissions.d.ts.map +1 -1
  53. package/dist/permissions.js +18 -20
  54. package/dist/permissions.js.map +1 -1
  55. package/dist/storage/knownState.d.ts +1 -1
  56. package/dist/storage/knownState.d.ts.map +1 -1
  57. package/dist/storage/knownState.js +2 -3
  58. package/dist/storage/knownState.js.map +1 -1
  59. package/dist/storage/storageAsync.d.ts +2 -1
  60. package/dist/storage/storageAsync.d.ts.map +1 -1
  61. package/dist/storage/storageAsync.js +5 -6
  62. package/dist/storage/storageAsync.js.map +1 -1
  63. package/dist/storage/storageSync.d.ts +2 -1
  64. package/dist/storage/storageSync.d.ts.map +1 -1
  65. package/dist/storage/storageSync.js +5 -5
  66. package/dist/storage/storageSync.js.map +1 -1
  67. package/dist/storage/types.d.ts +2 -1
  68. package/dist/storage/types.d.ts.map +1 -1
  69. package/dist/sync.d.ts +2 -12
  70. package/dist/sync.d.ts.map +1 -1
  71. package/dist/sync.js +9 -38
  72. package/dist/sync.js.map +1 -1
  73. package/dist/tests/PeerKnownStates.test.js +1 -1
  74. package/dist/tests/PeerKnownStates.test.js.map +1 -1
  75. package/dist/tests/PeerState.test.js +19 -0
  76. package/dist/tests/PeerState.test.js.map +1 -1
  77. package/dist/tests/PureJSCrypto.test.js.map +1 -1
  78. package/dist/tests/StorageApiAsync.test.js +1 -1
  79. package/dist/tests/StorageApiAsync.test.js.map +1 -1
  80. package/dist/tests/StorageApiSync.test.js +1 -2
  81. package/dist/tests/StorageApiSync.test.js.map +1 -1
  82. package/dist/tests/StoreQueue.test.js.map +1 -1
  83. package/dist/tests/SyncStateManager.test.js +1 -1
  84. package/dist/tests/SyncStateManager.test.js.map +1 -1
  85. package/dist/tests/branching.test.js +237 -28
  86. package/dist/tests/branching.test.js.map +1 -1
  87. package/dist/tests/coValueContentMessage.test.js +1 -1
  88. package/dist/tests/coValueContentMessage.test.js.map +1 -1
  89. package/dist/tests/coValueCore.loadFromStorage.test.d.ts +2 -0
  90. package/dist/tests/coValueCore.loadFromStorage.test.d.ts.map +1 -0
  91. package/dist/tests/coValueCore.loadFromStorage.test.js +395 -0
  92. package/dist/tests/coValueCore.loadFromStorage.test.js.map +1 -0
  93. package/dist/tests/coValueCore.loadingState.test.d.ts +2 -0
  94. package/dist/tests/coValueCore.loadingState.test.d.ts.map +1 -0
  95. package/dist/tests/{coValueCoreLoadingState.test.js → coValueCore.loadingState.test.js} +4 -12
  96. package/dist/tests/coValueCore.loadingState.test.js.map +1 -0
  97. package/dist/tests/coValueCore.test.js +30 -5
  98. package/dist/tests/coValueCore.test.js.map +1 -1
  99. package/dist/tests/knownState.test.d.ts +2 -0
  100. package/dist/tests/knownState.test.d.ts.map +1 -0
  101. package/dist/tests/knownState.test.js +510 -0
  102. package/dist/tests/knownState.test.js.map +1 -0
  103. package/dist/tests/messagesTestUtils.d.ts.map +1 -1
  104. package/dist/tests/messagesTestUtils.js.map +1 -1
  105. package/dist/tests/priority.test.js.map +1 -1
  106. package/dist/tests/sync.mesh.test.js +4 -34
  107. package/dist/tests/sync.mesh.test.js.map +1 -1
  108. package/dist/tests/sync.storage.test.js.map +1 -1
  109. package/dist/tests/sync.upload.test.js.map +1 -1
  110. package/dist/tests/testUtils.d.ts +7 -1
  111. package/dist/tests/testUtils.d.ts.map +1 -1
  112. package/dist/tests/testUtils.js +12 -0
  113. package/dist/tests/testUtils.js.map +1 -1
  114. package/package.json +3 -3
  115. package/src/PeerKnownStates.ts +36 -22
  116. package/src/PeerState.ts +2 -1
  117. package/src/SyncStateManager.ts +4 -17
  118. package/src/coValueContentMessage.ts +2 -1
  119. package/src/coValueCore/SessionMap.ts +66 -11
  120. package/src/coValueCore/branching.ts +37 -13
  121. package/src/coValueCore/coValueCore.ts +224 -177
  122. package/src/coValueCore/decryptTransactionChangesAndMeta.ts +56 -0
  123. package/src/coValueCore/verifiedState.ts +32 -64
  124. package/src/coValues/coMap.ts +1 -5
  125. package/src/coValues/coStream.ts +1 -5
  126. package/src/exports.ts +2 -2
  127. package/src/knownState.ts +118 -12
  128. package/src/localNode.ts +1 -1
  129. package/src/permissions.ts +21 -22
  130. package/src/storage/knownState.ts +9 -3
  131. package/src/storage/storageAsync.ts +15 -7
  132. package/src/storage/storageSync.ts +16 -8
  133. package/src/storage/types.ts +2 -1
  134. package/src/sync.ts +14 -60
  135. package/src/tests/PeerKnownStates.test.ts +1 -1
  136. package/src/tests/PeerState.test.ts +29 -3
  137. package/src/tests/PureJSCrypto.test.ts +0 -1
  138. package/src/tests/StorageApiAsync.test.ts +3 -6
  139. package/src/tests/StorageApiSync.test.ts +2 -6
  140. package/src/tests/StoreQueue.test.ts +3 -2
  141. package/src/tests/SyncStateManager.test.ts +1 -1
  142. package/src/tests/branching.test.ts +392 -45
  143. package/src/tests/coValueContentMessage.test.ts +2 -2
  144. package/src/tests/coValueCore.loadFromStorage.test.ts +540 -0
  145. package/src/tests/{coValueCoreLoadingState.test.ts → coValueCore.loadingState.test.ts} +3 -16
  146. package/src/tests/coValueCore.test.ts +40 -5
  147. package/src/tests/knownState.test.ts +665 -0
  148. package/src/tests/messagesTestUtils.ts +2 -1
  149. package/src/tests/priority.test.ts +0 -2
  150. package/src/tests/sync.mesh.test.ts +11 -38
  151. package/src/tests/sync.storage.test.ts +0 -1
  152. package/src/tests/sync.upload.test.ts +0 -1
  153. package/src/tests/testUtils.ts +22 -2
  154. package/dist/coValueCore/decodeTransactionChangesAndMeta.d.ts +0 -3
  155. package/dist/coValueCore/decodeTransactionChangesAndMeta.d.ts.map +0 -1
  156. package/dist/coValueCore/decodeTransactionChangesAndMeta.js +0 -59
  157. package/dist/coValueCore/decodeTransactionChangesAndMeta.js.map +0 -1
  158. package/dist/tests/coValueCoreLoadingState.test.d.ts +0 -2
  159. package/dist/tests/coValueCoreLoadingState.test.d.ts.map +0 -1
  160. package/dist/tests/coValueCoreLoadingState.test.js.map +0 -1
  161. package/src/coValueCore/decodeTransactionChangesAndMeta.ts +0 -81
@@ -2,7 +2,6 @@ import { Result, err, ok } from "neverthrow";
2
2
  import { ControlledAccountOrAgent } from "../coValues/account.js";
3
3
  import type {
4
4
  CryptoProvider,
5
- Hash,
6
5
  KeyID,
7
6
  KeySecret,
8
7
  SessionLogImpl,
@@ -10,12 +9,17 @@ import type {
10
9
  SignerID,
11
10
  } from "../crypto/crypto.js";
12
11
  import { RawCoID, SessionID } from "../ids.js";
13
- import { parseJSON, stableStringify, Stringified } from "../jsonStringify.js";
12
+ import { parseJSON, Stringified } from "../jsonStringify.js";
14
13
  import { JsonObject, JsonValue } from "../jsonValue.js";
15
- import { CoValueKnownState } from "../sync.js";
16
14
  import { TryAddTransactionsError } from "./coValueCore.js";
17
15
  import { Transaction } from "./verifiedState.js";
18
16
  import { exceedsRecommendedSize } from "../coValueContentMessage.js";
17
+ import {
18
+ CoValueKnownState,
19
+ KnownStateSessions,
20
+ updateSessionCounter,
21
+ cloneKnownState,
22
+ } from "../knownState.js";
19
23
 
20
24
  export type SessionLog = {
21
25
  signerID?: SignerID;
@@ -24,15 +28,31 @@ export type SessionLog = {
24
28
  lastSignature: Signature | undefined;
25
29
  signatureAfter: { [txIdx: number]: Signature | undefined };
26
30
  txSizeSinceLastInbetweenSignature: number;
31
+ sessionID: SessionID;
27
32
  };
28
33
 
29
34
  export class SessionMap {
30
35
  sessions: Map<SessionID, SessionLog> = new Map();
31
36
 
37
+ // Known state related properies, mutated when adding transactions to the session map
38
+ knownState: CoValueKnownState = { id: this.id, header: true, sessions: {} };
39
+ knownStateWithStreaming: CoValueKnownState | undefined;
40
+ streamingKnownState?: KnownStateSessions;
41
+
32
42
  constructor(
33
43
  private readonly id: RawCoID,
34
44
  private readonly crypto: CryptoProvider,
35
- ) {}
45
+ streamingKnownState?: KnownStateSessions,
46
+ ) {
47
+ if (streamingKnownState) {
48
+ this.streamingKnownState = { ...streamingKnownState };
49
+ this.knownStateWithStreaming = {
50
+ id: this.id,
51
+ header: true,
52
+ sessions: { ...streamingKnownState },
53
+ };
54
+ }
55
+ }
36
56
 
37
57
  get(sessionID: SessionID): SessionLog | undefined {
38
58
  return this.sessions.get(sessionID);
@@ -51,6 +71,7 @@ export class SessionMap {
51
71
  lastSignature: undefined,
52
72
  signatureAfter: {},
53
73
  txSizeSinceLastInbetweenSignature: 0,
74
+ sessionID,
54
75
  };
55
76
  this.sessions.set(sessionID, sessionLog);
56
77
  }
@@ -164,18 +185,43 @@ export class SessionMap {
164
185
  0,
165
186
  );
166
187
 
188
+ const transactionsCount = sessionLog.transactions.length;
189
+
167
190
  if (exceedsRecommendedSize(sessionLog.txSizeSinceLastInbetweenSignature)) {
168
- sessionLog.signatureAfter[sessionLog.transactions.length - 1] = signature;
191
+ sessionLog.signatureAfter[transactionsCount - 1] = signature;
169
192
  sessionLog.txSizeSinceLastInbetweenSignature = 0;
170
193
  }
171
- }
172
194
 
173
- knownState(): CoValueKnownState {
174
- const sessions: CoValueKnownState["sessions"] = {};
175
- for (const [sessionID, sessionLog] of this.sessions.entries()) {
176
- sessions[sessionID] = sessionLog.transactions.length;
195
+ // Update the known state with the new transactions count
196
+ updateSessionCounter(
197
+ this.knownState.sessions,
198
+ sessionLog.sessionID,
199
+ transactionsCount,
200
+ );
201
+
202
+ // Check if the updated session matched the streaming state
203
+ // If so, we can delete the session from the streaming state to mark it as synced
204
+ if (this.streamingKnownState) {
205
+ const streamingCount = this.streamingKnownState[sessionLog.sessionID];
206
+ if (streamingCount && streamingCount <= transactionsCount) {
207
+ delete this.streamingKnownState[sessionLog.sessionID];
208
+
209
+ if (Object.keys(this.streamingKnownState).length === 0) {
210
+ // Mark the streaming as done by deleting the streaming statuses
211
+ this.streamingKnownState = undefined;
212
+ this.knownStateWithStreaming = undefined;
213
+ }
214
+ }
215
+ }
216
+
217
+ if (this.knownStateWithStreaming) {
218
+ // Update the streaming known state with the new transactions count
219
+ updateSessionCounter(
220
+ this.knownStateWithStreaming.sessions,
221
+ sessionLog.sessionID,
222
+ transactionsCount,
223
+ );
177
224
  }
178
- return { id: this.id, header: true, sessions };
179
225
  }
180
226
 
181
227
  decryptTransaction(
@@ -244,9 +290,18 @@ export class SessionMap {
244
290
  txSizeSinceLastInbetweenSignature:
245
291
  sessionLog.txSizeSinceLastInbetweenSignature,
246
292
  signerID: sessionLog.signerID,
293
+ sessionID,
247
294
  });
248
295
  }
249
296
 
297
+ clone.streamingKnownState = this.streamingKnownState
298
+ ? { ...this.streamingKnownState }
299
+ : undefined;
300
+ clone.knownState = cloneKnownState(this.knownState);
301
+ clone.knownStateWithStreaming = this.knownStateWithStreaming
302
+ ? cloneKnownState(this.knownStateWithStreaming)
303
+ : undefined;
304
+
250
305
  return clone;
251
306
  }
252
307
  }
@@ -1,9 +1,11 @@
1
- import type { CoValueCore } from "../exports.js";
1
+ import { logger, type CoValueCore } from "../exports.js";
2
2
  import type { RawCoID, SessionID } from "../ids.js";
3
3
  import { type AvailableCoValueCore, idforHeader } from "./coValueCore.js";
4
4
  import type { CoValueHeader } from "./verifiedState.js";
5
- import type { CoValueKnownState } from "../sync.js";
6
- import { combineKnownStateSessions } from "../knownState.js";
5
+ import {
6
+ combineKnownStateSessions,
7
+ KnownStateSessions,
8
+ } from "../knownState.js";
7
9
 
8
10
  /**
9
11
  * Commit to identify the starting point of the branch
@@ -11,7 +13,7 @@ import { combineKnownStateSessions } from "../knownState.js";
11
13
  * In case of clonflicts, the first commit of this kind is considered the source of truth
12
14
  */
13
15
  export type BranchStartCommit = {
14
- from: CoValueKnownState["sessions"];
16
+ from: KnownStateSessions;
15
17
  };
16
18
 
17
19
  /**
@@ -27,6 +29,7 @@ export type BranchPointerCommit = {
27
29
  */
28
30
  export type MergedTransactionMetadata = {
29
31
  mi: number; // Transaction index and marker of a merge commit
32
+ t?: number; // The difference between the current time and the madeAt value of the original transaction. Used to calculate the original madeAt of the transaction, stored this way to reduce the size of the meta information.
30
33
  s?: SessionID;
31
34
  b?: RawCoID;
32
35
  };
@@ -35,7 +38,7 @@ export type MergedTransactionMetadata = {
35
38
  * Merge commit located in a branch to track how many transactions have already been merged
36
39
  */
37
40
  export type MergeCommit = {
38
- merged: CoValueKnownState["sessions"];
41
+ merged: KnownStateSessions;
39
42
  branch: RawCoID;
40
43
  };
41
44
 
@@ -142,6 +145,20 @@ export function createBranch(
142
145
  return coValue;
143
146
  }
144
147
 
148
+ const myRole = coValue.safeGetGroup()?.myRole();
149
+
150
+ // We allow branch creation to accounts with at least read access to the source group
151
+ if (!myRole || (myRole === "reader" && !ownerId)) {
152
+ logger.warn(
153
+ "Trying to create a branch without enough access rights, returning the source coValue",
154
+ );
155
+ return coValue;
156
+ }
157
+
158
+ // Accounts without write access store the branch pointer unencrypted to make it possible to handle it as a special case
159
+ // in the permissions checks
160
+ const privacy = myRole === "reader" ? "trusting" : "private";
161
+
145
162
  const header = getBranchHeader({
146
163
  type: coValue.verified.header.type,
147
164
  branchName: name,
@@ -158,7 +175,7 @@ export function createBranch(
158
175
  } satisfies BranchStartCommit);
159
176
 
160
177
  // Create a branch pointer, to identify that we created a branch
161
- coValue.makeTransaction([], "private", {
178
+ coValue.makeTransaction([], privacy, {
162
179
  branch: name,
163
180
  ownerId,
164
181
  } satisfies BranchPointerCommit);
@@ -213,13 +230,10 @@ export function mergeBranch(branch: CoValueCore): CoValueCore {
213
230
 
214
231
  // Look for previous merge commits, to see which transactions needs to be merged
215
232
  // Done mostly for performance reasons, as we could merge all the transactions every time and nothing would change
216
- let mergedTransactions = {} as CoValueKnownState["sessions"];
233
+ let mergedTransactions = {} as KnownStateSessions;
217
234
  for (const item of target.getMergeCommits()) {
218
235
  if (item.branch === branch.id) {
219
- mergedTransactions = combineKnownStateSessions(
220
- mergedTransactions,
221
- item.merged,
222
- );
236
+ combineKnownStateSessions(mergedTransactions, item.merged);
223
237
  }
224
238
  }
225
239
 
@@ -242,12 +256,21 @@ export function mergeBranch(branch: CoValueCore): CoValueCore {
242
256
  // To reduce the cost of the meta we skip the repeated information
243
257
  let lastSessionId: string | undefined = undefined;
244
258
  let lastBranchId: string | undefined = undefined;
259
+ let lastOriginalMadeAt: number = 0;
260
+
261
+ const now = Date.now();
245
262
 
246
263
  for (const tx of branchValidTransactions) {
247
264
  const mergeMeta: MergedTransactionMetadata = {
248
265
  mi: tx.txID.txIndex,
249
266
  };
250
267
 
268
+ // We compress the original made at, to reduce the size of the meta information
269
+ if (tx.madeAt !== lastOriginalMadeAt) {
270
+ // Storing the diff with madeAt to consume less bytes in the meta information
271
+ mergeMeta.t = now - tx.madeAt;
272
+ }
273
+
251
274
  if (lastSessionId !== tx.txID.sessionID) {
252
275
  mergeMeta.s = tx.txID.sessionID;
253
276
  }
@@ -256,16 +279,17 @@ export function mergeBranch(branch: CoValueCore): CoValueCore {
256
279
  mergeMeta.b = tx.txID.branch;
257
280
  }
258
281
 
259
- target.makeTransaction(tx.changes, tx.tx.privacy, mergeMeta, tx.madeAt);
282
+ target.makeTransaction(tx.changes, tx.tx.privacy, mergeMeta, now);
260
283
  lastSessionId = tx.txID.sessionID;
261
284
  lastBranchId = tx.txID.branch;
285
+ lastOriginalMadeAt = tx.madeAt;
262
286
  }
263
287
 
264
288
  // Track the merged transactions for the branch, so future merges will know which transactions have already been merged
265
289
  // Store only the diff of sessions between the branch and already merged transactions
266
290
  const currentSessions = branch.knownState().sessions;
267
291
  const prevMergedSessions = mergedTransactions;
268
- const diff = {} as CoValueKnownState["sessions"];
292
+ const diff = {} as KnownStateSessions;
269
293
 
270
294
  for (const [sessionId, count] of Object.entries(currentSessions) as [
271
295
  SessionID,