cojson 0.17.11 → 0.17.13

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 (97) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +17 -0
  3. package/dist/coValueCore/SessionMap.d.ts +4 -3
  4. package/dist/coValueCore/SessionMap.d.ts.map +1 -1
  5. package/dist/coValueCore/SessionMap.js +15 -4
  6. package/dist/coValueCore/SessionMap.js.map +1 -1
  7. package/dist/coValueCore/coValueCore.d.ts +2 -2
  8. package/dist/coValueCore/coValueCore.d.ts.map +1 -1
  9. package/dist/coValueCore/coValueCore.js +33 -32
  10. package/dist/coValueCore/coValueCore.js.map +1 -1
  11. package/dist/coValueCore/utils.d.ts.map +1 -1
  12. package/dist/coValueCore/utils.js.map +1 -1
  13. package/dist/coValueCore/verifiedState.d.ts +8 -2
  14. package/dist/coValueCore/verifiedState.d.ts.map +1 -1
  15. package/dist/coValueCore/verifiedState.js +7 -4
  16. package/dist/coValueCore/verifiedState.js.map +1 -1
  17. package/dist/crypto/PureJSCrypto.d.ts +4 -3
  18. package/dist/crypto/PureJSCrypto.d.ts.map +1 -1
  19. package/dist/crypto/PureJSCrypto.js +34 -2
  20. package/dist/crypto/PureJSCrypto.js.map +1 -1
  21. package/dist/crypto/WasmCrypto.d.ts +4 -3
  22. package/dist/crypto/WasmCrypto.d.ts.map +1 -1
  23. package/dist/crypto/WasmCrypto.js +10 -4
  24. package/dist/crypto/WasmCrypto.js.map +1 -1
  25. package/dist/crypto/crypto.d.ts +4 -3
  26. package/dist/crypto/crypto.d.ts.map +1 -1
  27. package/dist/localNode.js +1 -1
  28. package/dist/localNode.js.map +1 -1
  29. package/dist/queue/LocalTransactionsSyncQueue.d.ts +15 -0
  30. package/dist/queue/LocalTransactionsSyncQueue.d.ts.map +1 -1
  31. package/dist/queue/LocalTransactionsSyncQueue.js +25 -0
  32. package/dist/queue/LocalTransactionsSyncQueue.js.map +1 -1
  33. package/dist/sync.d.ts +10 -7
  34. package/dist/sync.d.ts.map +1 -1
  35. package/dist/sync.js +33 -31
  36. package/dist/sync.js.map +1 -1
  37. package/dist/tests/PureJSCrypto.test.js +43 -0
  38. package/dist/tests/PureJSCrypto.test.js.map +1 -1
  39. package/dist/tests/WasmCrypto.test.js +55 -0
  40. package/dist/tests/WasmCrypto.test.js.map +1 -1
  41. package/dist/tests/coList.test.js +13 -0
  42. package/dist/tests/coList.test.js.map +1 -1
  43. package/dist/tests/coMap.test.js +14 -0
  44. package/dist/tests/coMap.test.js.map +1 -1
  45. package/dist/tests/coPlainText.test.js +13 -0
  46. package/dist/tests/coPlainText.test.js.map +1 -1
  47. package/dist/tests/coStream.test.js +25 -0
  48. package/dist/tests/coStream.test.js.map +1 -1
  49. package/dist/tests/coValueCore.test.js +28 -2
  50. package/dist/tests/coValueCore.test.js.map +1 -1
  51. package/dist/tests/coreWasm.test.js +1 -1
  52. package/dist/tests/coreWasm.test.js.map +1 -1
  53. package/dist/tests/sync.known.test.d.ts +2 -0
  54. package/dist/tests/sync.known.test.d.ts.map +1 -0
  55. package/dist/tests/sync.known.test.js +78 -0
  56. package/dist/tests/sync.known.test.js.map +1 -0
  57. package/dist/tests/sync.sharding.test.d.ts +2 -0
  58. package/dist/tests/sync.sharding.test.d.ts.map +1 -0
  59. package/dist/tests/sync.sharding.test.js +85 -0
  60. package/dist/tests/sync.sharding.test.js.map +1 -0
  61. package/dist/tests/sync.storage.test.js +31 -1
  62. package/dist/tests/sync.storage.test.js.map +1 -1
  63. package/dist/tests/sync.storageAsync.test.js +1 -1
  64. package/dist/tests/sync.storageAsync.test.js.map +1 -1
  65. package/dist/tests/sync.test.js +31 -2
  66. package/dist/tests/sync.test.js.map +1 -1
  67. package/dist/tests/sync.upload.test.js +26 -0
  68. package/dist/tests/sync.upload.test.js.map +1 -1
  69. package/dist/tests/testUtils.d.ts.map +1 -1
  70. package/dist/tests/testUtils.js +3 -1
  71. package/dist/tests/testUtils.js.map +1 -1
  72. package/package.json +2 -2
  73. package/src/coValueCore/SessionMap.ts +24 -1
  74. package/src/coValueCore/coValueCore.ts +46 -41
  75. package/src/coValueCore/utils.ts +0 -1
  76. package/src/coValueCore/verifiedState.ts +14 -3
  77. package/src/crypto/PureJSCrypto.ts +49 -1
  78. package/src/crypto/WasmCrypto.ts +15 -1
  79. package/src/crypto/crypto.ts +7 -1
  80. package/src/localNode.ts +1 -1
  81. package/src/queue/LocalTransactionsSyncQueue.ts +32 -1
  82. package/src/sync.ts +50 -36
  83. package/src/tests/PureJSCrypto.test.ts +66 -0
  84. package/src/tests/WasmCrypto.test.ts +88 -0
  85. package/src/tests/coList.test.ts +19 -0
  86. package/src/tests/coMap.test.ts +21 -0
  87. package/src/tests/coPlainText.test.ts +18 -0
  88. package/src/tests/coStream.test.ts +36 -0
  89. package/src/tests/coValueCore.test.ts +49 -0
  90. package/src/tests/coreWasm.test.ts +1 -0
  91. package/src/tests/sync.known.test.ts +109 -0
  92. package/src/tests/sync.sharding.test.ts +119 -0
  93. package/src/tests/sync.storage.test.ts +43 -1
  94. package/src/tests/sync.storageAsync.test.ts +1 -1
  95. package/src/tests/sync.test.ts +49 -2
  96. package/src/tests/sync.upload.test.ts +35 -0
  97. package/src/tests/testUtils.ts +3 -1
@@ -11,7 +11,7 @@ import type {
11
11
  } from "../crypto/crypto.js";
12
12
  import { RawCoID, SessionID } from "../ids.js";
13
13
  import { parseJSON, stableStringify, Stringified } from "../jsonStringify.js";
14
- import { JsonValue } from "../jsonValue.js";
14
+ import { JsonObject, JsonValue } from "../jsonValue.js";
15
15
  import { CoValueKnownState } from "../sync.js";
16
16
  import { TryAddTransactionsError } from "./coValueCore.js";
17
17
  import { Transaction } from "./verifiedState.js";
@@ -91,6 +91,7 @@ export class SessionMap {
91
91
  changes: JsonValue[],
92
92
  keyID: KeyID,
93
93
  keySecret: KeySecret,
94
+ meta: JsonObject | undefined,
94
95
  ): { signature: Signature; transaction: Transaction } {
95
96
  const sessionLog = this.getOrCreateSessionLog(
96
97
  sessionID,
@@ -104,6 +105,7 @@ export class SessionMap {
104
105
  keyID,
105
106
  keySecret,
106
107
  madeAt,
108
+ meta,
107
109
  );
108
110
 
109
111
  this.addTransactionsToJsLog(
@@ -119,6 +121,7 @@ export class SessionMap {
119
121
  sessionID: SessionID,
120
122
  signerAgent: ControlledAccountOrAgent,
121
123
  changes: JsonValue[],
124
+ meta: JsonObject | undefined,
122
125
  ): { signature: Signature; transaction: Transaction } {
123
126
  const sessionLog = this.getOrCreateSessionLog(
124
127
  sessionID,
@@ -130,6 +133,7 @@ export class SessionMap {
130
133
  signerAgent,
131
134
  changes,
132
135
  madeAt,
136
+ meta,
133
137
  );
134
138
 
135
139
  this.addTransactionsToJsLog(
@@ -193,6 +197,25 @@ export class SessionMap {
193
197
  return parseJSON(decrypted as Stringified<JsonValue[] | undefined>);
194
198
  }
195
199
 
200
+ decryptTransactionMeta(
201
+ sessionID: SessionID,
202
+ txIndex: number,
203
+ keySecret: KeySecret,
204
+ ): JsonObject | undefined {
205
+ const sessionLog = this.sessions.get(sessionID);
206
+ if (!sessionLog?.transactions[txIndex]?.meta) {
207
+ return undefined;
208
+ }
209
+ const decrypted = sessionLog.impl.decryptNextTransactionMetaJson(
210
+ txIndex,
211
+ keySecret,
212
+ );
213
+ if (!decrypted) {
214
+ return undefined;
215
+ }
216
+ return parseJSON(decrypted as Stringified<JsonObject | undefined>);
217
+ }
218
+
196
219
  get size() {
197
220
  return this.sessions.size;
198
221
  }
@@ -14,11 +14,10 @@ import {
14
14
  KeySecret,
15
15
  Signature,
16
16
  SignerID,
17
- StreamingHash,
18
17
  } from "../crypto/crypto.js";
19
18
  import { RawCoID, SessionID, TransactionID } from "../ids.js";
20
- import { parseJSON, stableStringify } from "../jsonStringify.js";
21
- import { JsonValue } from "../jsonValue.js";
19
+ import { JsonObject, JsonValue } from "../jsonValue.js";
20
+ import { parseJSON } from "../jsonStringify.js";
22
21
  import { LocalNode, ResolveAccountAgentError } from "../localNode.js";
23
22
  import { logger } from "../logger.js";
24
23
  import { determineValidTransactions } from "../permissions.js";
@@ -85,6 +84,7 @@ export class CoValueCore {
85
84
  new Set();
86
85
  private readonly _decryptionCache: {
87
86
  [key: Encrypted<JsonValue[], JsonValue>]: JsonValue[] | undefined;
87
+ [key: Encrypted<JsonObject, JsonValue>]: JsonObject | undefined;
88
88
  } = {};
89
89
  private _cachedDependentOn?: Set<RawCoID>;
90
90
  private counter: UpDownCounter;
@@ -552,6 +552,7 @@ export class CoValueCore {
552
552
  makeTransaction(
553
553
  changes: JsonValue[],
554
554
  privacy: "private" | "trusting",
555
+ meta?: JsonObject,
555
556
  ): boolean {
556
557
  if (!this.verified) {
557
558
  throw new Error(
@@ -585,16 +586,22 @@ export class CoValueCore {
585
586
  changes,
586
587
  keyID,
587
588
  keySecret,
589
+ meta,
588
590
  );
589
591
 
590
592
  if (result.transaction.privacy === "private") {
591
593
  this._decryptionCache[result.transaction.encryptedChanges] = changes;
594
+
595
+ if (result.transaction.meta) {
596
+ this._decryptionCache[result.transaction.meta] = meta;
597
+ }
592
598
  }
593
599
  } else {
594
600
  result = this.verified.makeNewTrustingTransaction(
595
601
  sessionID,
596
602
  signerAgent,
597
603
  changes,
604
+ meta,
598
605
  );
599
606
  }
600
607
 
@@ -661,57 +668,55 @@ export class CoValueCore {
661
668
  continue;
662
669
  }
663
670
 
664
- if (tx.privacy === "trusting") {
665
- try {
666
- allTransactions.push({
667
- txID,
668
- madeAt: tx.madeAt,
669
- changes: parseJSON(tx.changes),
670
- trusting: true,
671
- });
672
- } catch (e) {
673
- logger.error("Failed to parse trusting transaction on " + this.id, {
674
- err: e,
675
- txID,
676
- changes: tx.changes.slice(0, 50),
677
- });
671
+ let changes: JsonValue[];
672
+
673
+ if (tx.privacy === "private") {
674
+ if (options?.ignorePrivateTransactions) {
675
+ continue;
678
676
  }
679
- continue;
680
- }
681
677
 
682
- if (options?.ignorePrivateTransactions) {
683
- continue;
684
- }
678
+ const readKey = this.getReadKey(tx.keyUsed);
685
679
 
686
- const readKey = this.getReadKey(tx.keyUsed);
680
+ if (!readKey) {
681
+ continue;
682
+ }
687
683
 
688
- if (!readKey) {
689
- continue;
690
- }
684
+ let decryptedChanges = this._decryptionCache[tx.encryptedChanges];
691
685
 
692
- let decryptedChanges = this._decryptionCache[tx.encryptedChanges];
686
+ if (!decryptedChanges) {
687
+ decryptedChanges = this.verified.decryptTransaction(
688
+ txID.sessionID,
689
+ txID.txIndex,
690
+ readKey,
691
+ );
693
692
 
694
- if (!decryptedChanges) {
695
- decryptedChanges = this.verified.decryptTransaction(
696
- txID.sessionID,
697
- txID.txIndex,
698
- readKey,
699
- );
693
+ this._decryptionCache[tx.encryptedChanges] = decryptedChanges;
694
+ }
700
695
 
701
- this._decryptionCache[tx.encryptedChanges] = decryptedChanges;
702
- }
696
+ if (!decryptedChanges) {
697
+ logger.error("Failed to decrypt transaction despite having key", {
698
+ err: new Error("Failed to decrypt transaction despite having key"),
699
+ });
700
+ continue;
701
+ }
703
702
 
704
- if (!decryptedChanges) {
705
- logger.error("Failed to decrypt transaction despite having key", {
706
- err: new Error("Failed to decrypt transaction despite having key"),
707
- });
708
- continue;
703
+ changes = decryptedChanges;
704
+ } else {
705
+ try {
706
+ changes = parseJSON(tx.changes);
707
+ } catch (e) {
708
+ logger.error("Failed to parse trusting transaction on " + this.id, {
709
+ err: e,
710
+ });
711
+ continue;
712
+ }
709
713
  }
710
714
 
711
715
  allTransactions.push({
712
716
  txID,
713
717
  madeAt: tx.madeAt,
714
- changes: decryptedChanges,
718
+ changes,
719
+ trusting: tx.privacy === "trusting",
715
720
  });
716
721
  }
717
722
 
@@ -2,7 +2,6 @@ import { getGroupDependentKey } from "../ids.js";
2
2
  import { RawCoID, SessionID } from "../ids.js";
3
3
  import { Stringified, parseJSON } from "../jsonStringify.js";
4
4
  import { JsonValue } from "../jsonValue.js";
5
- import { NewContentMessage } from "../sync.js";
6
5
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
7
6
  import { isAccountID } from "../typeUtils/isAccountID.js";
8
7
  import { CoValueHeader, Transaction } from "./verifiedState.js";
@@ -8,19 +8,16 @@ import {
8
8
  import {
9
9
  CryptoProvider,
10
10
  Encrypted,
11
- Hash,
12
11
  KeyID,
13
12
  KeySecret,
14
13
  Signature,
15
14
  SignerID,
16
- StreamingHash,
17
15
  } from "../crypto/crypto.js";
18
16
  import { RawCoID, SessionID, TransactionID } from "../ids.js";
19
17
  import { Stringified } from "../jsonStringify.js";
20
18
  import { JsonObject, JsonValue } from "../jsonValue.js";
21
19
  import { PermissionsDef as RulesetDef } from "../permissions.js";
22
20
  import { CoValueKnownState, NewContentMessage } from "../sync.js";
23
- import { InvalidHashError, InvalidSignatureError } from "./coValueCore.js";
24
21
  import { TryAddTransactionsError } from "./coValueCore.js";
25
22
  import { SessionLog, SessionMap } from "./SessionMap.js";
26
23
  import { ControlledAccountOrAgent } from "../coValues/account.js";
@@ -41,12 +38,14 @@ export type PrivateTransaction = {
41
38
  madeAt: number;
42
39
  keyUsed: KeyID;
43
40
  encryptedChanges: Encrypted<JsonValue[], { in: RawCoID; tx: TransactionID }>;
41
+ meta?: Encrypted<JsonObject, { in: RawCoID; tx: TransactionID }>;
44
42
  };
45
43
 
46
44
  export type TrustingTransaction = {
47
45
  privacy: "trusting";
48
46
  madeAt: number;
49
47
  changes: Stringified<JsonValue[]>;
48
+ meta?: Stringified<JsonObject>;
50
49
  };
51
50
 
52
51
  export type Transaction = PrivateTransaction | TrustingTransaction;
@@ -114,11 +113,13 @@ export class VerifiedState {
114
113
  sessionID: SessionID,
115
114
  signerAgent: ControlledAccountOrAgent,
116
115
  changes: JsonValue[],
116
+ meta: JsonObject | undefined,
117
117
  ) {
118
118
  const result = this.sessions.makeNewTrustingTransaction(
119
119
  sessionID,
120
120
  signerAgent,
121
121
  changes,
122
+ meta,
122
123
  );
123
124
 
124
125
  this._cachedNewContentSinceEmpty = undefined;
@@ -133,6 +134,7 @@ export class VerifiedState {
133
134
  changes: JsonValue[],
134
135
  keyID: KeyID,
135
136
  keySecret: KeySecret,
137
+ meta: JsonObject | undefined,
136
138
  ) {
137
139
  const result = this.sessions.makeNewPrivateTransaction(
138
140
  sessionID,
@@ -140,6 +142,7 @@ export class VerifiedState {
140
142
  changes,
141
143
  keyID,
142
144
  keySecret,
145
+ meta,
143
146
  );
144
147
 
145
148
  this._cachedNewContentSinceEmpty = undefined;
@@ -353,6 +356,14 @@ export class VerifiedState {
353
356
  ): JsonValue[] | undefined {
354
357
  return this.sessions.decryptTransaction(sessionID, txIndex, keySecret);
355
358
  }
359
+
360
+ decryptTransactionMeta(
361
+ sessionID: SessionID,
362
+ txIndex: number,
363
+ keySecret: KeySecret,
364
+ ): JsonObject | undefined {
365
+ return this.sessions.decryptTransactionMeta(sessionID, txIndex, keySecret);
366
+ }
356
367
  }
357
368
 
358
369
  function getNextKnownSignatureIdx(
@@ -10,7 +10,7 @@ import {
10
10
  } from "../coValueCore/verifiedState.js";
11
11
  import { RawCoID, SessionID, TransactionID } from "../ids.js";
12
12
  import { Stringified, stableStringify } from "../jsonStringify.js";
13
- import { JsonValue } from "../jsonValue.js";
13
+ import { JsonObject, JsonValue } from "../jsonValue.js";
14
14
  import { logger } from "../logger.js";
15
15
  import {
16
16
  CryptoProvider,
@@ -328,16 +328,26 @@ export class PureJSSessionLog implements SessionLogImpl {
328
328
  keyID: KeyID,
329
329
  keySecret: KeySecret,
330
330
  madeAt: number,
331
+ meta: JsonObject | undefined,
331
332
  ): { signature: Signature; transaction: PrivateTransaction } {
332
333
  const encryptedChanges = this.crypto.encrypt(changes, keySecret, {
333
334
  in: this.coID,
334
335
  tx: { sessionID: this.sessionID, txIndex: this.transactions.length },
335
336
  });
337
+
338
+ const encryptedMeta = meta
339
+ ? this.crypto.encrypt(meta, keySecret, {
340
+ in: this.coID,
341
+ tx: { sessionID: this.sessionID, txIndex: this.transactions.length },
342
+ })
343
+ : undefined;
344
+
336
345
  const tx = {
337
346
  encryptedChanges: encryptedChanges,
338
347
  madeAt: madeAt,
339
348
  privacy: "private",
340
349
  keyUsed: keyID,
350
+ meta: encryptedMeta,
341
351
  } satisfies Transaction;
342
352
  const signature = this.internalAddNewTransaction(
343
353
  stableStringify(tx),
@@ -353,11 +363,13 @@ export class PureJSSessionLog implements SessionLogImpl {
353
363
  signerAgent: ControlledAccountOrAgent,
354
364
  changes: JsonValue[],
355
365
  madeAt: number,
366
+ meta: JsonObject | undefined,
356
367
  ): { signature: Signature; transaction: TrustingTransaction } {
357
368
  const tx = {
358
369
  changes: stableStringify(changes),
359
370
  madeAt: madeAt,
360
371
  privacy: "trusting",
372
+ meta: meta ? stableStringify(meta) : undefined,
361
373
  } satisfies Transaction;
362
374
  const signature = this.internalAddNewTransaction(
363
375
  stableStringify(tx),
@@ -400,6 +412,42 @@ export class PureJSSessionLog implements SessionLogImpl {
400
412
  }
401
413
  }
402
414
 
415
+ decryptNextTransactionMetaJson(
416
+ txIndex: number,
417
+ keySecret: KeySecret,
418
+ ): string | undefined {
419
+ const txJson = this.transactions[txIndex];
420
+ if (!txJson) {
421
+ throw new Error("Transaction not found");
422
+ }
423
+ const tx = JSON.parse(txJson) as Transaction;
424
+
425
+ if (!tx.meta) {
426
+ return undefined;
427
+ }
428
+
429
+ if (tx.privacy === "private") {
430
+ const nOnceMaterial = {
431
+ in: this.coID,
432
+ tx: { sessionID: this.sessionID, txIndex: txIndex },
433
+ };
434
+
435
+ const nOnce = this.crypto.generateJsonNonce(nOnceMaterial);
436
+
437
+ const ciphertext = base64URLtoBytes(
438
+ tx.meta.substring("encrypted_U".length),
439
+ );
440
+ const keySecretBytes = base58.decode(
441
+ keySecret.substring("keySecret_z".length),
442
+ );
443
+ const plaintext = xsalsa20(keySecretBytes, nOnce, ciphertext);
444
+
445
+ return textDecoder.decode(plaintext);
446
+ } else {
447
+ return tx.meta;
448
+ }
449
+ }
450
+
403
451
  free(): void {
404
452
  // no-op
405
453
  }
@@ -19,7 +19,7 @@ import {
19
19
  import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
20
20
  import { RawCoID, SessionID, TransactionID } from "../ids.js";
21
21
  import { Stringified, stableStringify } from "../jsonStringify.js";
22
- import { JsonValue } from "../jsonValue.js";
22
+ import { JsonObject, JsonValue } from "../jsonValue.js";
23
23
  import { logger } from "../logger.js";
24
24
  import { PureJSCrypto } from "./PureJSCrypto.js";
25
25
  import {
@@ -231,6 +231,7 @@ class SessionLogAdapter {
231
231
  keyID: KeyID,
232
232
  keySecret: KeySecret,
233
233
  madeAt: number,
234
+ meta: JsonObject | undefined,
234
235
  ): { signature: Signature; transaction: PrivateTransaction } {
235
236
  const output = this.sessionLog.addNewPrivateTransaction(
236
237
  stableStringify(changes),
@@ -238,6 +239,7 @@ class SessionLogAdapter {
238
239
  keySecret,
239
240
  keyID,
240
241
  madeAt,
242
+ meta ? stableStringify(meta) : undefined,
241
243
  );
242
244
  const parsedOutput = JSON.parse(output);
243
245
  const transaction: PrivateTransaction = {
@@ -245,6 +247,7 @@ class SessionLogAdapter {
245
247
  madeAt,
246
248
  encryptedChanges: parsedOutput.encrypted_changes,
247
249
  keyUsed: keyID,
250
+ meta: parsedOutput.meta,
248
251
  };
249
252
  return { signature: parsedOutput.signature, transaction };
250
253
  }
@@ -253,17 +256,21 @@ class SessionLogAdapter {
253
256
  signerAgent: ControlledAccountOrAgent,
254
257
  changes: JsonValue[],
255
258
  madeAt: number,
259
+ meta: JsonObject | undefined,
256
260
  ): { signature: Signature; transaction: TrustingTransaction } {
257
261
  const stringifiedChanges = stableStringify(changes);
262
+ const stringifiedMeta = meta ? stableStringify(meta) : undefined;
258
263
  const output = this.sessionLog.addNewTrustingTransaction(
259
264
  stringifiedChanges,
260
265
  signerAgent.currentSignerSecret(),
261
266
  madeAt,
267
+ stringifiedMeta,
262
268
  );
263
269
  const transaction: TrustingTransaction = {
264
270
  privacy: "trusting",
265
271
  madeAt,
266
272
  changes: stringifiedChanges,
273
+ meta: stringifiedMeta,
267
274
  };
268
275
  return { signature: output as Signature, transaction };
269
276
  }
@@ -279,6 +286,13 @@ class SessionLogAdapter {
279
286
  return output;
280
287
  }
281
288
 
289
+ decryptNextTransactionMetaJson(
290
+ txIndex: number,
291
+ keySecret: KeySecret,
292
+ ): string | undefined {
293
+ return this.sessionLog.decryptNextTransactionMetaJson(txIndex, keySecret);
294
+ }
295
+
282
296
  free() {
283
297
  this.sessionLog.free();
284
298
  }
@@ -3,7 +3,7 @@ import { ControlledAccountOrAgent, RawAccountID } from "../coValues/account.js";
3
3
  import { AgentID, RawCoID, TransactionID } from "../ids.js";
4
4
  import { SessionID } from "../ids.js";
5
5
  import { Stringified, parseJSON, stableStringify } from "../jsonStringify.js";
6
- import { JsonValue } from "../jsonValue.js";
6
+ import { JsonObject, JsonValue } from "../jsonValue.js";
7
7
  import { logger } from "../logger.js";
8
8
  import {
9
9
  PrivateTransaction,
@@ -366,15 +366,21 @@ export interface SessionLogImpl {
366
366
  keyID: KeyID,
367
367
  keySecret: KeySecret,
368
368
  madeAt: number,
369
+ meta: JsonObject | undefined,
369
370
  ): { signature: Signature; transaction: PrivateTransaction };
370
371
  addNewTrustingTransaction(
371
372
  signerAgent: ControlledAccountOrAgent,
372
373
  changes: JsonValue[],
373
374
  madeAt: number,
375
+ meta: JsonObject | undefined,
374
376
  ): { signature: Signature; transaction: TrustingTransaction };
375
377
  decryptNextTransactionChangesJson(
376
378
  tx_index: number,
377
379
  key_secret: KeySecret,
378
380
  ): string;
379
381
  free(): void;
382
+ decryptNextTransactionMetaJson(
383
+ tx_index: number,
384
+ key_secret: KeySecret,
385
+ ): string | undefined;
380
386
  }
package/src/localNode.ts CHANGED
@@ -408,7 +408,7 @@ export class LocalNode {
408
408
  coValue.loadingState === "unknown" ||
409
409
  coValue.loadingState === "unavailable"
410
410
  ) {
411
- const peers = this.syncManager.getServerPeers(skipLoadingFromPeer);
411
+ const peers = this.syncManager.getServerPeers(id, skipLoadingFromPeer);
412
412
 
413
413
  if (!this.storage && peers.length === 0) {
414
414
  return coValue;
@@ -4,7 +4,7 @@ import {
4
4
  } from "../coValueContentMessage.js";
5
5
  import { Transaction, VerifiedState } from "../coValueCore/verifiedState.js";
6
6
  import { Signature } from "../crypto/crypto.js";
7
- import { SessionID } from "../ids.js";
7
+ import { RawCoID, SessionID } from "../ids.js";
8
8
  import { NewContentMessage } from "../sync.js";
9
9
  import { LinkedList } from "./LinkedList.js";
10
10
 
@@ -73,8 +73,39 @@ export class LocalTransactionsSyncQueue {
73
73
  this.queue.push(content);
74
74
 
75
75
  this.processPendingSyncs();
76
+
77
+ for (const trackingSet of this.dirtyCoValuesTrackingSets) {
78
+ trackingSet.add(content.id);
79
+ }
76
80
  }
77
81
 
82
+ private dirtyCoValuesTrackingSets: Set<Set<RawCoID>> = new Set();
83
+
84
+ /**
85
+ * It starts tracking all changed CoValues. Returns a `done()` function that returns a set of coValues' ids that have been modified since the start.
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * const tracking = node.syncManager.trackDirtyCoValues();
90
+ * // Any CoValue mutation
91
+ * const tracked = tracking.done();
92
+ * console.log("CoValue mutated: " Array.from(tracked))
93
+ * ```
94
+ */
95
+ trackDirtyCoValues = () => {
96
+ const trackingSet = new Set<RawCoID>();
97
+
98
+ this.dirtyCoValuesTrackingSets.add(trackingSet);
99
+
100
+ return {
101
+ done: () => {
102
+ this.dirtyCoValuesTrackingSets.delete(trackingSet);
103
+
104
+ return trackingSet;
105
+ },
106
+ };
107
+ };
108
+
78
109
  private processingSyncs = false;
79
110
  processPendingSyncs() {
80
111
  if (this.processingSyncs) return;