cojson 0.1.12 → 0.2.1

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 (54) hide show
  1. package/dist/coValue.d.ts +1 -1
  2. package/dist/coValueCore.d.ts +10 -4
  3. package/dist/coValueCore.js +91 -46
  4. package/dist/coValueCore.js.map +1 -1
  5. package/dist/coValues/coList.js +2 -1
  6. package/dist/coValues/coList.js.map +1 -1
  7. package/dist/coValues/coMap.d.ts +7 -12
  8. package/dist/coValues/coMap.js +2 -1
  9. package/dist/coValues/coMap.js.map +1 -1
  10. package/dist/coValues/coStream.d.ts +11 -2
  11. package/dist/coValues/coStream.js +61 -14
  12. package/dist/coValues/coStream.js.map +1 -1
  13. package/dist/crypto.d.ts +8 -0
  14. package/dist/crypto.js +10 -3
  15. package/dist/crypto.js.map +1 -1
  16. package/dist/group.d.ts +1 -1
  17. package/dist/index.d.ts +6 -3
  18. package/dist/index.js +5 -3
  19. package/dist/index.js.map +1 -1
  20. package/dist/jsonStringify.d.ts +6 -0
  21. package/dist/{fastJsonStableStringify.js → jsonStringify.js} +10 -6
  22. package/dist/jsonStringify.js.map +1 -0
  23. package/dist/jsonValue.d.ts +1 -1
  24. package/dist/media.d.ts +8 -0
  25. package/dist/media.js +2 -0
  26. package/dist/media.js.map +1 -0
  27. package/dist/node.js +1 -1
  28. package/dist/permissions.js +4 -2
  29. package/dist/permissions.js.map +1 -1
  30. package/dist/streamUtils.js +14 -5
  31. package/dist/streamUtils.js.map +1 -1
  32. package/dist/sync.js +35 -15
  33. package/dist/sync.js.map +1 -1
  34. package/package.json +2 -2
  35. package/src/coValue.test.ts +113 -4
  36. package/src/coValue.ts +1 -1
  37. package/src/coValueCore.test.ts +11 -10
  38. package/src/coValueCore.ts +162 -75
  39. package/src/coValues/coList.ts +2 -1
  40. package/src/coValues/coMap.ts +11 -12
  41. package/src/coValues/coStream.ts +73 -21
  42. package/src/crypto.ts +22 -4
  43. package/src/group.ts +1 -1
  44. package/src/index.ts +7 -2
  45. package/src/{fastJsonStableStringify.ts → jsonStringify.ts} +23 -11
  46. package/src/jsonValue.ts +1 -1
  47. package/src/media.ts +9 -0
  48. package/src/node.ts +1 -1
  49. package/src/permissions.ts +5 -2
  50. package/src/streamUtils.ts +26 -6
  51. package/src/sync.test.ts +19 -20
  52. package/src/sync.ts +47 -26
  53. package/dist/fastJsonStableStringify.d.ts +0 -1
  54. package/dist/fastJsonStableStringify.js.map +0 -1
package/src/crypto.ts CHANGED
@@ -7,7 +7,7 @@ import { AgentID, RawCoID, TransactionID } from "./ids.js";
7
7
  import { base64URLtoBytes, bytesToBase64url } from "./base64url.js";
8
8
 
9
9
  import { createBLAKE3 } from 'hash-wasm';
10
- import { stableStringify } from "./fastJsonStableStringify.js";
10
+ import { Stringified, parseJSON, stableStringify } from "./jsonStringify.js";
11
11
 
12
12
  let blake3Instance: Awaited<ReturnType<typeof createBLAKE3>>;
13
13
  let blake3HashOnce: (data: Uint8Array) => Uint8Array;
@@ -316,11 +316,11 @@ export function encryptKeySecret(keys: {
316
316
  };
317
317
  }
318
318
 
319
- function decrypt<T extends JsonValue, N extends JsonValue>(
319
+ function decryptRaw<T extends JsonValue, N extends JsonValue>(
320
320
  encrypted: Encrypted<T, N>,
321
321
  keySecret: KeySecret,
322
322
  nOnceMaterial: N
323
- ): T | undefined {
323
+ ): Stringified<T> {
324
324
  const keySecretBytes = base58.decode(
325
325
  keySecret.substring("keySecret_z".length)
326
326
  );
@@ -333,13 +333,31 @@ function decrypt<T extends JsonValue, N extends JsonValue>(
333
333
  );
334
334
  const plaintext = xsalsa20(keySecretBytes, nOnce, ciphertext);
335
335
 
336
+ return textDecoder.decode(plaintext) as Stringified<T>;
337
+
338
+ }
339
+
340
+ function decrypt<T extends JsonValue, N extends JsonValue>(
341
+ encrypted: Encrypted<T, N>,
342
+ keySecret: KeySecret,
343
+ nOnceMaterial: N
344
+ ): T | undefined {
336
345
  try {
337
- return JSON.parse(textDecoder.decode(plaintext));
346
+ return parseJSON(decryptRaw(encrypted, keySecret, nOnceMaterial));
338
347
  } catch (e) {
348
+ console.error("Decryption error", e)
339
349
  return undefined;
340
350
  }
341
351
  }
342
352
 
353
+ export function decryptRawForTransaction<T extends JsonValue>(
354
+ encrypted: Encrypted<T, { in: RawCoID; tx: TransactionID }>,
355
+ keySecret: KeySecret,
356
+ nOnceMaterial: { in: RawCoID; tx: TransactionID }
357
+ ): Stringified<T> | undefined {
358
+ return decryptRaw(encrypted, keySecret, nOnceMaterial);
359
+ }
360
+
343
361
  export function decryptForTransaction<T extends JsonValue>(
344
362
  encrypted: Encrypted<T, { in: RawCoID; tx: TransactionID }>,
345
363
  keySecret: KeySecret,
package/src/group.ts CHANGED
@@ -238,7 +238,7 @@ export class Group {
238
238
 
239
239
  /** Creates a new `CoMap` within this group, with the specified specialized
240
240
  * `CoMap` type `M` and optional static metadata. */
241
- createMap<M extends CoMap<{ [key: string]: JsonValue }, JsonObject | null>>(
241
+ createMap<M extends CoMap<{ [key: string]: JsonValue | undefined; }, JsonObject | null>>(
242
242
  meta?: M["meta"]
243
243
  ): M {
244
244
  return this.node
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CoValueCore, newRandomSessionID } from "./coValueCore.js";
1
+ import { CoValueCore, newRandomSessionID, MAX_RECOMMENDED_TX_SIZE } from "./coValueCore.js";
2
2
  import { LocalNode } from "./node.js";
3
3
  import type { CoValue, ReadableCoValue } from "./coValue.js";
4
4
  import { CoMap, WriteableCoMap } from "./coValues/coMap.js";
@@ -25,6 +25,7 @@ import { AnonymousControlledAccount, ControlledAccount } from "./account.js";
25
25
  import { rawCoIDtoBytes, rawCoIDfromBytes } from "./ids.js";
26
26
  import { Group, expectGroupContent } from "./group.js";
27
27
  import { base64URLtoBytes, bytesToBase64url } from "./base64url.js";
28
+ import { parseJSON } from "./jsonStringify.js";
28
29
 
29
30
  import type { SessionID, AgentID } from "./ids.js";
30
31
  import type { CoID, CoValueImpl } from "./coValue.js";
@@ -34,6 +35,7 @@ import type { SyncMessage, Peer } from "./sync.js";
34
35
  import type { AgentSecret } from "./crypto.js";
35
36
  import type { AccountID, Profile } from "./account.js";
36
37
  import type { InviteSecret } from "./group.js";
38
+ import type * as Media from "./media.js";
37
39
 
38
40
  type Value = JsonValue | CoValueImpl;
39
41
 
@@ -53,7 +55,8 @@ export const cojsonInternals = {
53
55
  shortHashLength,
54
56
  expectGroupContent,
55
57
  base64URLtoBytes,
56
- bytesToBase64url
58
+ bytesToBase64url,
59
+ parseJSON
57
60
  };
58
61
 
59
62
  export {
@@ -71,6 +74,7 @@ export {
71
74
  AnonymousControlledAccount,
72
75
  ControlledAccount,
73
76
  cryptoReady as cojsonReady,
77
+ MAX_RECOMMENDED_TX_SIZE
74
78
  };
75
79
 
76
80
  export type {
@@ -90,6 +94,7 @@ export type {
90
94
  AgentSecret,
91
95
  InviteSecret,
92
96
  SyncMessage,
97
+ Media
93
98
  };
94
99
 
95
100
  // eslint-disable-next-line @typescript-eslint/no-namespace
@@ -1,24 +1,32 @@
1
1
  // adapted from fast-json-stable-stringify (https://github.com/epoberezkin/fast-json-stable-stringify)
2
2
 
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- export function stableStringify(data: any): string | undefined {
3
+ export type Stringified<T> = string & { __type: T };
4
+
5
+ export function stableStringify<T>(data: T): Stringified<T>
6
+ export function stableStringify(data: undefined): undefined
7
+ export function stableStringify<T>(data: T | undefined): Stringified<T> | undefined {
5
8
  const cycles = false;
6
9
 
7
10
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
11
  const seen: any[] = [];
9
- let node = data;
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ let node = data as any;
10
14
 
11
15
  if (node && node.toJSON && typeof node.toJSON === "function") {
12
16
  node = node.toJSON();
13
17
  }
14
18
 
15
19
  if (node === undefined) return;
16
- if (typeof node == "number") return isFinite(node) ? "" + node : "null";
20
+ if (typeof node == "number")
21
+ return (isFinite(node) ? "" + node : "null") as Stringified<T>;
17
22
  if (typeof node !== "object") {
18
- if (typeof node === "string" && (node.startsWith("encrypted_U") || node.startsWith("binary_U"))) {
19
- return `"${node}"`;
23
+ if (
24
+ typeof node === "string" &&
25
+ (node.startsWith("encrypted_U") || node.startsWith("binary_U"))
26
+ ) {
27
+ return `"${node}"` as Stringified<T>;
20
28
  }
21
- return JSON.stringify(node);
29
+ return JSON.stringify(node) as Stringified<T>;
22
30
  }
23
31
 
24
32
  let i, out;
@@ -28,13 +36,13 @@ export function stableStringify(data: any): string | undefined {
28
36
  if (i) out += ",";
29
37
  out += stableStringify(node[i]) || "null";
30
38
  }
31
- return out + "]";
39
+ return (out + "]") as Stringified<T>;
32
40
  }
33
41
 
34
- if (node === null) return "null";
42
+ if (node === null) return "null" as Stringified<T>;
35
43
 
36
44
  if (seen.indexOf(node) !== -1) {
37
- if (cycles) return JSON.stringify("__cycle__");
45
+ if (cycles) return JSON.stringify("__cycle__") as Stringified<T>;
38
46
  throw new TypeError("Converting circular structure to JSON");
39
47
  }
40
48
 
@@ -50,5 +58,9 @@ export function stableStringify(data: any): string | undefined {
50
58
  out += JSON.stringify(key) + ":" + value;
51
59
  }
52
60
  seen.splice(seenIndex, 1);
53
- return "{" + out + "}";
61
+ return ("{" + out + "}") as Stringified<T>;
54
62
  }
63
+
64
+ export function parseJSON<T>(json: Stringified<T>): T {
65
+ return JSON.parse(json);
66
+ }
package/src/jsonValue.ts CHANGED
@@ -3,4 +3,4 @@ import { RawCoID } from './ids.js';
3
3
  export type JsonAtom = string | number | boolean | null;
4
4
  export type JsonValue = JsonAtom | JsonArray | JsonObject | RawCoID;
5
5
  export type JsonArray = JsonValue[];
6
- export type JsonObject = { [key: string]: JsonValue; };
6
+ export type JsonObject = { [key: string]: JsonValue | undefined; };
package/src/media.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { CoMap } from './coValues/coMap.js'
2
+ import { CoID } from './coValue.js'
3
+ import { BinaryCoStream } from './coValues/coStream.js'
4
+
5
+ export type ImageDefinition = CoMap<{
6
+ originalSize: [number, number];
7
+ placeholderDataURL?: string;
8
+ [res: `${number}x${number}`]: CoID<BinaryCoStream>;
9
+ }>;
package/src/node.ts CHANGED
@@ -208,7 +208,7 @@ export class LocalNode {
208
208
  reject(
209
209
  new Error("Couldn't find invite before timeout")
210
210
  ),
211
- 1000
211
+ 2000
212
212
  );
213
213
  });
214
214
 
@@ -15,6 +15,7 @@ import {
15
15
  AccountID,
16
16
  Profile,
17
17
  } from "./account.js";
18
+ import { parseJSON } from "./jsonStringify.js";
18
19
 
19
20
  export type PermissionsDef =
20
21
  | { type: "group"; initialAdmin: AccountID | AgentID }
@@ -76,11 +77,13 @@ export function determineValidTransactions(
76
77
  // console.log("before", { memberState, validTransactions });
77
78
  const transactor = accountOrAgentIDfromSessionID(sessionID);
78
79
 
79
- const change = tx.changes[0] as
80
+ const changes = parseJSON(tx.changes)
81
+
82
+ const change = changes[0] as
80
83
  | MapOpPayload<AccountID | AgentID, Role>
81
84
  | MapOpPayload<"readKey", JsonValue>
82
85
  | MapOpPayload<"profile", CoID<Profile>>;
83
- if (tx.changes.length !== 1) {
86
+ if (changes.length !== 1) {
84
87
  console.warn("Group transaction must have exactly one change");
85
88
  continue;
86
89
  }
@@ -34,7 +34,14 @@ export function connectedPeers(
34
34
  trace &&
35
35
  console.debug(
36
36
  `${peer2id} -> ${peer1id}`,
37
- JSON.stringify(chunk, null, 2)
37
+ JSON.stringify(
38
+ chunk,
39
+ (k, v) =>
40
+ (k === "changes" || k === "encryptedChanges")
41
+ ? v.slice(0, 20) + "..."
42
+ : v,
43
+ 2
44
+ )
38
45
  );
39
46
  controller.enqueue(chunk);
40
47
  },
@@ -52,7 +59,14 @@ export function connectedPeers(
52
59
  trace &&
53
60
  console.debug(
54
61
  `${peer1id} -> ${peer2id}`,
55
- JSON.stringify(chunk, null, 2)
62
+ JSON.stringify(
63
+ chunk,
64
+ (k, v) =>
65
+ (k === "changes" || k === "encryptedChanges")
66
+ ? v.slice(0, 20) + "..."
67
+ : v,
68
+ 2
69
+ )
56
70
  );
57
71
  controller.enqueue(chunk);
58
72
  },
@@ -102,16 +116,22 @@ export function newStreamPair<T>(): [ReadableStream<T>, WritableStream<T>] {
102
116
  },
103
117
  });
104
118
 
119
+ let lastWritePromise = Promise.resolve();
120
+
105
121
  const writable = new WritableStream<T>({
106
122
  async write(chunk) {
107
123
  const enqueue = await enqueuePromise;
108
124
  if (readerClosed) {
109
125
  throw new Error("Reader closed");
110
126
  } else {
111
- // make sure write resolves before corresponding read
112
- setTimeout(() => {
113
- enqueue(chunk);
114
- })
127
+ // make sure write resolves before corresponding read, but make sure writes are still in order
128
+ await lastWritePromise;
129
+ lastWritePromise = new Promise((resolve) => {
130
+ setTimeout(() => {
131
+ enqueue(chunk);
132
+ resolve();
133
+ });
134
+ });
115
135
  }
116
136
  },
117
137
  async abort(reason) {
package/src/sync.test.ts CHANGED
@@ -8,12 +8,10 @@ import {
8
8
  randomAnonymousAccountAndSessionID,
9
9
  shouldNotResolve,
10
10
  } from "./testUtils.js";
11
- import {
12
- connectedPeers,
13
- newStreamPair
14
- } from "./streamUtils.js";
11
+ import { connectedPeers, newStreamPair } from "./streamUtils.js";
15
12
  import { AccountID } from "./account.js";
16
13
  import { cojsonReady } from "./index.js";
14
+ import { stableStringify } from "./jsonStringify.js";
17
15
 
18
16
  beforeEach(async () => {
19
17
  await cojsonReady;
@@ -84,13 +82,13 @@ test("Node replies with initial tx and header to empty subscribe", async () => {
84
82
  privacy: "trusting" as const,
85
83
  madeAt: map.core.sessions[node.currentSessionID]!
86
84
  .transactions[0]!.madeAt,
87
- changes: [
85
+ changes: stableStringify([
88
86
  {
89
87
  op: "set",
90
88
  key: "hello",
91
89
  value: "world",
92
90
  } satisfies MapOpPayload<string, string>,
93
- ],
91
+ ]),
94
92
  },
95
93
  ],
96
94
  lastSignature:
@@ -162,13 +160,13 @@ test("Node replies with only new tx to subscribe with some known state", async (
162
160
  privacy: "trusting" as const,
163
161
  madeAt: map.core.sessions[node.currentSessionID]!
164
162
  .transactions[1]!.madeAt,
165
- changes: [
163
+ changes: stableStringify([
166
164
  {
167
165
  op: "set",
168
166
  key: "goodbye",
169
167
  value: "world",
170
168
  } satisfies MapOpPayload<string, string>,
171
- ],
169
+ ]),
172
170
  },
173
171
  ],
174
172
  lastSignature:
@@ -251,13 +249,13 @@ test("After subscribing, node sends own known state and new txs to peer", async
251
249
  privacy: "trusting" as const,
252
250
  madeAt: map.core.sessions[node.currentSessionID]!
253
251
  .transactions[0]!.madeAt,
254
- changes: [
252
+ changes: stableStringify([
255
253
  {
256
254
  op: "set",
257
255
  key: "hello",
258
256
  value: "world",
259
257
  } satisfies MapOpPayload<string, string>,
260
- ],
258
+ ]),
261
259
  },
262
260
  ],
263
261
  lastSignature:
@@ -283,13 +281,13 @@ test("After subscribing, node sends own known state and new txs to peer", async
283
281
  privacy: "trusting" as const,
284
282
  madeAt: map.core.sessions[node.currentSessionID]!
285
283
  .transactions[1]!.madeAt,
286
- changes: [
284
+ changes: stableStringify([
287
285
  {
288
286
  op: "set",
289
287
  key: "goodbye",
290
288
  value: "world",
291
289
  } satisfies MapOpPayload<string, string>,
292
- ],
290
+ ]),
293
291
  },
294
292
  ],
295
293
  lastSignature:
@@ -362,13 +360,13 @@ test("Client replies with known new content to tellKnownState from server", asyn
362
360
  privacy: "trusting" as const,
363
361
  madeAt: map.core.sessions[node.currentSessionID]!
364
362
  .transactions[0]!.madeAt,
365
- changes: [
363
+ changes: stableStringify([
366
364
  {
367
365
  op: "set",
368
366
  key: "hello",
369
367
  value: "world",
370
368
  } satisfies MapOpPayload<string, string>,
371
- ],
369
+ ]),
372
370
  },
373
371
  ],
374
372
  lastSignature:
@@ -438,8 +436,9 @@ test("No matter the optimistic known state, node respects invalid known state me
438
436
  editable.set("goodbye", "world", "trusting");
439
437
  });
440
438
 
441
- const _mapEditMsg1 = await reader.read();
442
- const _mapEditMsg2 = await reader.read();
439
+ const _mapEditMsgs = await reader.read();
440
+
441
+ console.log("Sending correction");
443
442
 
444
443
  await writer.write({
445
444
  action: "known",
@@ -465,13 +464,13 @@ test("No matter the optimistic known state, node respects invalid known state me
465
464
  privacy: "trusting" as const,
466
465
  madeAt: map.core.sessions[node.currentSessionID]!
467
466
  .transactions[1]!.madeAt,
468
- changes: [
467
+ changes: stableStringify([
469
468
  {
470
469
  op: "set",
471
470
  key: "goodbye",
472
471
  value: "world",
473
472
  } satisfies MapOpPayload<string, string>,
474
- ],
473
+ ]),
475
474
  },
476
475
  ],
477
476
  lastSignature:
@@ -568,13 +567,13 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
568
567
  privacy: "trusting" as const,
569
568
  madeAt: map.core.sessions[node.currentSessionID]!
570
569
  .transactions[0]!.madeAt,
571
- changes: [
570
+ changes: stableStringify([
572
571
  {
573
572
  op: "set",
574
573
  key: "hello",
575
574
  value: "world",
576
575
  } satisfies MapOpPayload<string, string>,
577
- ],
576
+ ]),
578
577
  },
579
578
  ],
580
579
  lastSignature:
package/src/sync.ts CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  WritableStreamDefaultWriter,
10
10
  } from "isomorphic-streams";
11
11
  import { RawCoID, SessionID } from "./ids.js";
12
- import { stableStringify } from "./fastJsonStableStringify.js";
12
+ import { stableStringify } from "./jsonStringify.js";
13
13
 
14
14
  export type CoValueKnownState = {
15
15
  id: RawCoID;
@@ -215,14 +215,32 @@ export class SyncManager {
215
215
  await this.sendNewContentIncludingDependencies(id, peer);
216
216
  }
217
217
 
218
- const newContent = coValue.newContentSince(
218
+ const newContentPieces = coValue.newContentSince(
219
219
  peer.optimisticKnownStates[id]
220
220
  );
221
221
 
222
- if (newContent) {
223
- await this.trySendToPeer(peer, newContent);
222
+ if (newContentPieces) {
223
+ const optimisticKnownStateBefore =
224
+ peer.optimisticKnownStates[id] || emptyKnownState(id);
225
+
226
+ const sendPieces = async () => {
227
+ for (const [i, piece] of newContentPieces.entries()) {
228
+ // console.log(
229
+ // `${id} -> ${peer.id}: Sending content piece ${i + 1}/${newContentPieces.length} header: ${!!piece.header}`,
230
+ // // Object.values(piece.new).map((s) => s.newTransactions)
231
+ // );
232
+ await this.trySendToPeer(peer, piece);
233
+ }
234
+ };
235
+
236
+ sendPieces().catch((e) => {
237
+ console.error("Error sending new content piece, retrying", e);
238
+ peer.optimisticKnownStates[id] = optimisticKnownStateBefore;
239
+ return this.sendNewContentIncludingDependencies(id, peer);
240
+ });
241
+
224
242
  peer.optimisticKnownStates[id] = combinedKnownStates(
225
- peer.optimisticKnownStates[id] || emptyKnownState(id),
243
+ optimisticKnownStateBefore,
226
244
  coValue.knownState()
227
245
  );
228
246
  }
@@ -261,6 +279,9 @@ export class SyncManager {
261
279
  for await (const msg of peerState.incoming) {
262
280
  try {
263
281
  await this.handleSyncMessage(msg, peerState);
282
+ await new Promise<void>((resolve) => {
283
+ setTimeout(resolve, 0);
284
+ });
264
285
  } catch (e) {
265
286
  console.error(
266
287
  `Error reading from peer ${peer.id}, handling msg`,
@@ -269,7 +290,6 @@ export class SyncManager {
269
290
  );
270
291
  }
271
292
  }
272
- console.log("DONE!!!");
273
293
  } catch (e) {
274
294
  console.error(`Error reading from peer ${peer.id}`, e);
275
295
  }
@@ -446,6 +466,10 @@ export class SyncManager {
446
466
  const newTransactions =
447
467
  newContentForSession.newTransactions.slice(alreadyKnownOffset);
448
468
 
469
+ if (newTransactions.length === 0) {
470
+ continue;
471
+ }
472
+
449
473
  const before = performance.now();
450
474
  const success = await coValue.tryAddTransactionsAsync(
451
475
  sessionID,
@@ -455,20 +479,26 @@ export class SyncManager {
455
479
  );
456
480
  const after = performance.now();
457
481
  if (after - before > 10) {
458
- const totalTxLength = newTransactions.map(t => stableStringify(t)!.length).reduce((a, b) => a + b, 0);
482
+ const totalTxLength = newTransactions
483
+ .map((t) =>
484
+ t.privacy === "private"
485
+ ? t.encryptedChanges.length
486
+ : t.changes.length
487
+ )
488
+ .reduce((a, b) => a + b, 0);
459
489
  console.log(
460
- "Adding incoming transactions took",
461
- after - before,
462
- "ms",
463
- totalTxLength,
464
- "bytes = ",
465
- "bandwidth: MB/s",
466
- (1000 * totalTxLength / (after - before)) / (1024 * 1024)
490
+ `Adding incoming transactions took ${(
491
+ after - before
492
+ ).toFixed(2)}ms for ${totalTxLength} bytes = bandwidth: ${(
493
+ (1000 * totalTxLength) /
494
+ (after - before) /
495
+ (1024 * 1024)
496
+ ).toFixed(2)} MB/s`
467
497
  );
468
498
  }
469
499
 
470
500
  if (!success) {
471
- console.error("Failed to add transactions", newTransactions);
501
+ console.error("Failed to add transactions", msg.id, newTransactions);
472
502
  continue;
473
503
  }
474
504
 
@@ -493,18 +523,9 @@ export class SyncManager {
493
523
  }
494
524
 
495
525
  async handleCorrection(msg: KnownStateMessage, peer: PeerState) {
496
- const coValue = this.local.expectCoValueLoaded(msg.id);
526
+ peer.optimisticKnownStates[msg.id] = msg;
497
527
 
498
- peer.optimisticKnownStates[msg.id] = combinedKnownStates(
499
- msg,
500
- coValue.knownState()
501
- );
502
-
503
- const newContent = coValue.newContentSince(msg);
504
-
505
- if (newContent) {
506
- await this.trySendToPeer(peer, newContent);
507
- }
528
+ return this.sendNewContentIncludingDependencies(msg.id, peer);
508
529
  }
509
530
 
510
531
  handleUnsubscribe(_msg: DoneMessage) {
@@ -1 +0,0 @@
1
- export declare function stableStringify(data: any): string | undefined;
@@ -1 +0,0 @@
1
- {"version":3,"file":"fastJsonStableStringify.js","sourceRoot":"","sources":["../src/fastJsonStableStringify.ts"],"names":[],"mappings":"AAAA,sGAAsG;AAEtG,8DAA8D;AAC9D,MAAM,UAAU,eAAe,CAAC,IAAS;IACrC,MAAM,MAAM,GAAG,KAAK,CAAC;IAErB,8DAA8D;IAC9D,MAAM,IAAI,GAAU,EAAE,CAAC;IACvB,IAAI,IAAI,GAAG,IAAI,CAAC;IAEhB,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE;QAC1D,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;KACxB;IAED,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,IAAI,OAAO,IAAI,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IACxE,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;QAC1B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE;YAC7F,OAAO,IAAI,IAAI,GAAG,CAAC;SACtB;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;KAC/B;IAED,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACrB,GAAG,GAAG,GAAG,CAAC;QACV,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC9B,IAAI,CAAC;gBAAE,GAAG,IAAI,GAAG,CAAC;YAClB,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC;SAC7C;QACD,OAAO,GAAG,GAAG,GAAG,CAAC;KACpB;IAED,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAEjC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE;QAC3B,IAAI,MAAM;YAAE,OAAO,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC/C,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;KAChE;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACtC,GAAG,GAAG,EAAE,CAAC;IACT,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,KAAK,GAAG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAEzC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,GAAG;YAAE,GAAG,IAAI,GAAG,CAAC;QACpB,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC;KAC5C;IACD,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAC1B,OAAO,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAC3B,CAAC"}