cojson 0.7.35-unique.2 → 0.7.35

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 (76) hide show
  1. package/.turbo/turbo-test.log +321 -253
  2. package/CHANGELOG.md +3 -2
  3. package/dist/PeerState.js +58 -0
  4. package/dist/PeerState.js.map +1 -0
  5. package/dist/PriorityBasedMessageQueue.js +51 -0
  6. package/dist/PriorityBasedMessageQueue.js.map +1 -0
  7. package/dist/base64url.js.map +1 -1
  8. package/dist/coValue.js.map +1 -1
  9. package/dist/coValueCore.js +3 -0
  10. package/dist/coValueCore.js.map +1 -1
  11. package/dist/coValues/account.js +2 -2
  12. package/dist/coValues/account.js.map +1 -1
  13. package/dist/coValues/coList.js.map +1 -1
  14. package/dist/coValues/coMap.js.map +1 -1
  15. package/dist/coValues/coStream.js +14 -15
  16. package/dist/coValues/coStream.js.map +1 -1
  17. package/dist/coValues/group.js +8 -8
  18. package/dist/coValues/group.js.map +1 -1
  19. package/dist/coreToCoValue.js.map +1 -1
  20. package/dist/crypto/PureJSCrypto.js.map +1 -1
  21. package/dist/crypto/WasmCrypto.js.map +1 -1
  22. package/dist/crypto/crypto.js.map +1 -1
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/jsonStringify.js.map +1 -1
  26. package/dist/localNode.js +2 -2
  27. package/dist/localNode.js.map +1 -1
  28. package/dist/permissions.js.map +1 -1
  29. package/dist/priority.js +31 -0
  30. package/dist/priority.js.map +1 -0
  31. package/dist/storage/FileSystem.js.map +1 -1
  32. package/dist/storage/chunksAndKnownStates.js +2 -0
  33. package/dist/storage/chunksAndKnownStates.js.map +1 -1
  34. package/dist/storage/index.js.map +1 -1
  35. package/dist/streamUtils.js.map +1 -1
  36. package/dist/sync.js +7 -18
  37. package/dist/sync.js.map +1 -1
  38. package/dist/tests/PeerState.test.js +80 -0
  39. package/dist/tests/PeerState.test.js.map +1 -0
  40. package/dist/tests/PriorityBasedMessageQueue.test.js +97 -0
  41. package/dist/tests/PriorityBasedMessageQueue.test.js.map +1 -0
  42. package/dist/tests/coMap.test.js.map +1 -1
  43. package/dist/tests/coStream.test.js +34 -1
  44. package/dist/tests/coStream.test.js.map +1 -1
  45. package/dist/tests/permissions.test.js.map +1 -1
  46. package/dist/tests/priority.test.js +61 -0
  47. package/dist/tests/priority.test.js.map +1 -0
  48. package/dist/tests/sync.test.js +323 -12
  49. package/dist/tests/sync.test.js.map +1 -1
  50. package/dist/tests/testUtils.js.map +1 -1
  51. package/dist/typeUtils/accountOrAgentIDfromSessionID.js.map +1 -1
  52. package/dist/typeUtils/expectGroup.js.map +1 -1
  53. package/dist/typeUtils/isAccountID.js.map +1 -1
  54. package/package.json +3 -3
  55. package/src/PeerState.ts +74 -0
  56. package/src/PriorityBasedMessageQueue.ts +77 -0
  57. package/src/coValueCore.ts +10 -7
  58. package/src/coValues/account.ts +5 -5
  59. package/src/coValues/coList.ts +4 -4
  60. package/src/coValues/coMap.ts +3 -3
  61. package/src/coValues/coStream.ts +29 -26
  62. package/src/coValues/group.ts +11 -15
  63. package/src/ids.ts +2 -2
  64. package/src/index.ts +5 -5
  65. package/src/localNode.ts +11 -12
  66. package/src/permissions.ts +5 -5
  67. package/src/priority.ts +39 -0
  68. package/src/storage/chunksAndKnownStates.ts +2 -0
  69. package/src/sync.ts +19 -34
  70. package/src/tests/PeerState.test.ts +92 -0
  71. package/src/tests/PriorityBasedMessageQueue.test.ts +111 -0
  72. package/src/tests/coStream.test.ts +58 -1
  73. package/src/tests/priority.test.ts +75 -0
  74. package/src/tests/sync.test.ts +487 -25
  75. package/src/typeUtils/accountOrAgentIDfromSessionID.ts +3 -3
  76. package/src/typeUtils/isAccountID.ts +2 -2
@@ -7,7 +7,7 @@ import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfrom
7
7
  import { RawGroup } from "./group.js";
8
8
  import { AgentID, SessionID, TransactionID } from "../ids.js";
9
9
  import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
10
- import { RawAccountID } from "./account.js";
10
+ import { AccountID } from "./account.js";
11
11
 
12
12
  export type BinaryStreamInfo = {
13
13
  mimeType: string;
@@ -96,22 +96,27 @@ export class RawCoStreamView<
96
96
  }
97
97
 
98
98
  getSingleStream(): Item[] | undefined {
99
- if (Object.keys(this.items).length === 0) {
99
+ const streams = Object.values(this.items);
100
+ const firstStream = streams[0];
101
+
102
+ if (!firstStream) {
100
103
  return undefined;
101
- } else if (Object.keys(this.items).length !== 1) {
104
+ }
105
+
106
+ if (streams.length > 1) {
102
107
  throw new Error(
103
108
  "CoStream.getSingleStream() can only be called when there is exactly one stream",
104
109
  );
105
110
  }
106
111
 
107
- return Object.values(this.items)[0]?.map((item) => item.value);
112
+ return firstStream.map((item) => item.value);
108
113
  }
109
114
 
110
115
  sessions(): SessionID[] {
111
116
  return Object.keys(this.items) as SessionID[];
112
117
  }
113
118
 
114
- accounts(): Set<RawAccountID> {
119
+ accounts(): Set<AccountID> {
115
120
  return new Set(
116
121
  this.sessions()
117
122
  .map(accountOrAgentIDfromSessionID)
@@ -124,7 +129,7 @@ export class RawCoStreamView<
124
129
  n: number,
125
130
  ):
126
131
  | {
127
- by: RawAccountID | AgentID;
132
+ by: AccountID | AgentID;
128
133
  tx: TransactionID;
129
134
  at: Date;
130
135
  value: Item;
@@ -146,7 +151,7 @@ export class RawCoStreamView<
146
151
 
147
152
  lastItemIn(sessionID: SessionID):
148
153
  | {
149
- by: RawAccountID | AgentID;
154
+ by: AccountID | AgentID;
150
155
  tx: TransactionID;
151
156
  at: Date;
152
157
  value: Item;
@@ -170,9 +175,9 @@ export class RawCoStreamView<
170
175
  }
171
176
  }
172
177
 
173
- lastItemBy(account: RawAccountID | AgentID):
178
+ lastItemBy(account: AccountID | AgentID):
174
179
  | {
175
- by: RawAccountID | AgentID;
180
+ by: AccountID | AgentID;
176
181
  tx: TransactionID;
177
182
  at: Date;
178
183
  value: Item;
@@ -180,7 +185,7 @@ export class RawCoStreamView<
180
185
  | undefined {
181
186
  let latestItem:
182
187
  | {
183
- by: RawAccountID | AgentID;
188
+ by: AccountID | AgentID;
184
189
  tx: TransactionID;
185
190
  at: Date;
186
191
  value: Item;
@@ -205,7 +210,7 @@ export class RawCoStreamView<
205
210
  return latestItem;
206
211
  }
207
212
 
208
- *itemsBy(account: RawAccountID | AgentID) {
213
+ *itemsBy(account: AccountID | AgentID) {
209
214
  // TODO: this can be made more lazy without a huge collect and sort
210
215
  const items = [
211
216
  ...Object.keys(this.items).flatMap((sessionID) =>
@@ -264,14 +269,26 @@ export class RawBinaryCoStreamView<
264
269
  extends RawCoStreamView<BinaryStreamItem, Meta>
265
270
  implements RawCoValue
266
271
  {
272
+ isBinaryStreamEnded() {
273
+ const items = this.getSingleStream();
274
+
275
+ if (!items || items.length === 0) {
276
+ return false;
277
+ }
278
+
279
+ const lastItem = items[items.length - 1];
280
+
281
+ return lastItem?.type === "end";
282
+ }
283
+
267
284
  getBinaryChunks(
268
285
  allowUnfinished?: boolean,
269
286
  ):
270
287
  | (BinaryStreamInfo & { chunks: Uint8Array[]; finished: boolean })
271
288
  | undefined {
272
- // const before = performance.now();
273
289
  const items = this.getSingleStream();
274
290
 
291
+ // No active streams
275
292
  if (!items) return;
276
293
 
277
294
  const start = items[0];
@@ -288,9 +305,6 @@ export class RawBinaryCoStreamView<
288
305
  const chunks: Uint8Array[] = [];
289
306
 
290
307
  let finished = false;
291
- // let totalLength = 0;
292
-
293
- let lastProgressUpdate = Date.now();
294
308
 
295
309
  for (const item of items.slice(1)) {
296
310
  if (item.type === "end") {
@@ -306,20 +320,9 @@ export class RawBinaryCoStreamView<
306
320
  const chunk = base64URLtoBytes(
307
321
  item.chunk.slice(binary_U_prefixLength),
308
322
  );
309
- // totalLength += chunk.length;
310
323
  chunks.push(chunk);
311
-
312
- if (Date.now() - lastProgressUpdate > 100) {
313
- lastProgressUpdate = Date.now();
314
- }
315
324
  }
316
325
 
317
- // const after = performance.now();
318
- // console.log(
319
- // "getBinaryChunks bandwidth in MB/s",
320
- // (1000 * totalLength) / (after - before) / (1024 * 1024)
321
- // );
322
-
323
326
  return {
324
327
  mimeType: start.mimeType,
325
328
  fileName: start.fileName,
@@ -5,10 +5,9 @@ import { JsonObject } from "../jsonValue.js";
5
5
  import { RawBinaryCoStream, RawCoStream } from "./coStream.js";
6
6
  import { Encrypted, KeyID, KeySecret, Sealed } from "../crypto/crypto.js";
7
7
  import { AgentID, isAgentID } from "../ids.js";
8
- import { RawAccount, RawAccountID, ControlledAccountOrAgent } from "./account.js";
8
+ import { RawAccount, AccountID, ControlledAccountOrAgent } from "./account.js";
9
9
  import { Role } from "../permissions.js";
10
10
  import { base58 } from "@scure/base";
11
- import { CoValueUniqueness } from "../coValueCore.js";
12
11
 
13
12
  export const EVERYONE = "everyone" as const;
14
13
  export type Everyone = "everyone";
@@ -16,10 +15,10 @@ export type Everyone = "everyone";
16
15
  export type GroupShape = {
17
16
  profile: CoID<RawCoMap> | null;
18
17
  root: CoID<RawCoMap> | null;
19
- [key: RawAccountID | AgentID]: Role;
18
+ [key: AccountID | AgentID]: Role;
20
19
  [EVERYONE]?: Role;
21
20
  readKey?: KeyID;
22
- [revelationFor: `${KeyID}_for_${RawAccountID | AgentID}`]: Sealed<KeySecret>;
21
+ [revelationFor: `${KeyID}_for_${AccountID | AgentID}`]: Sealed<KeySecret>;
23
22
  [revelationFor: `${KeyID}_for_${Everyone}`]: KeySecret;
24
23
  [oldKeyForNewKey: `${KeyID}_for_${KeyID}`]: Encrypted<
25
24
  KeySecret,
@@ -56,12 +55,12 @@ export class RawGroup<
56
55
  *
57
56
  * @category 1. Role reading
58
57
  */
59
- roleOf(accountID: RawAccountID): Role | undefined {
58
+ roleOf(accountID: AccountID): Role | undefined {
60
59
  return this.roleOfInternal(accountID);
61
60
  }
62
61
 
63
62
  /** @internal */
64
- roleOfInternal(accountID: RawAccountID | AgentID): Role | undefined {
63
+ roleOfInternal(accountID: AccountID | AgentID): Role | undefined {
65
64
  return this.get(accountID);
66
65
  }
67
66
 
@@ -157,7 +156,7 @@ export class RawGroup<
157
156
  } else {
158
157
  return false;
159
158
  }
160
- }) as (RawAccountID | AgentID)[];
159
+ }) as (AccountID | AgentID)[];
161
160
 
162
161
  const maybeCurrentReadKey = this.core.getCurrentReadKey();
163
162
 
@@ -256,7 +255,6 @@ export class RawGroup<
256
255
  init?: M["_shape"],
257
256
  meta?: M["headerMeta"],
258
257
  initPrivacy: "trusting" | "private" = "private",
259
- uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
260
258
  ): M {
261
259
  const map = this.core.node
262
260
  .createCoValue({
@@ -266,7 +264,7 @@ export class RawGroup<
266
264
  group: this.id,
267
265
  },
268
266
  meta: meta || null,
269
- ...uniqueness
267
+ ...this.core.crypto.createdNowUnique(),
270
268
  })
271
269
  .getCurrentContent() as M;
272
270
 
@@ -289,7 +287,6 @@ export class RawGroup<
289
287
  init?: L["_item"][],
290
288
  meta?: L["headerMeta"],
291
289
  initPrivacy: "trusting" | "private" = "private",
292
- uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
293
290
  ): L {
294
291
  const list = this.core.node
295
292
  .createCoValue({
@@ -299,7 +296,7 @@ export class RawGroup<
299
296
  group: this.id,
300
297
  },
301
298
  meta: meta || null,
302
- ...uniqueness
299
+ ...this.core.crypto.createdNowUnique(),
303
300
  })
304
301
  .getCurrentContent() as L;
305
302
 
@@ -313,7 +310,7 @@ export class RawGroup<
313
310
  }
314
311
 
315
312
  /** @category 3. Value creation */
316
- createStream<C extends RawCoStream>(meta?: C["headerMeta"], uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()): C {
313
+ createStream<C extends RawCoStream>(meta?: C["headerMeta"]): C {
317
314
  return this.core.node
318
315
  .createCoValue({
319
316
  type: "costream",
@@ -322,7 +319,7 @@ export class RawGroup<
322
319
  group: this.id,
323
320
  },
324
321
  meta: meta || null,
325
- ...uniqueness
322
+ ...this.core.crypto.createdNowUnique(),
326
323
  })
327
324
  .getCurrentContent() as C;
328
325
  }
@@ -330,7 +327,6 @@ export class RawGroup<
330
327
  /** @category 3. Value creation */
331
328
  createBinaryStream<C extends RawBinaryCoStream>(
332
329
  meta: C["headerMeta"] = { type: "binary" },
333
- uniqueness: CoValueUniqueness = this.core.crypto.createdNowUnique()
334
330
  ): C {
335
331
  return this.core.node
336
332
  .createCoValue({
@@ -340,7 +336,7 @@ export class RawGroup<
340
336
  group: this.id,
341
337
  },
342
338
  meta: meta,
343
- ...uniqueness
339
+ ...this.core.crypto.createdNowUnique(),
344
340
  })
345
341
  .getCurrentContent() as C;
346
342
  }
package/src/ids.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RawAccountID } from "./coValues/account.js";
1
+ import { AccountID } from "./coValues/account.js";
2
2
  import { base58 } from "@scure/base";
3
3
  import { shortHashLength } from "./crypto/crypto.js";
4
4
 
@@ -28,4 +28,4 @@ export function isAgentID(id: string): id is AgentID {
28
28
  );
29
29
  }
30
30
 
31
- export type SessionID = `${RawAccountID | AgentID}_session_z${string}`;
31
+ export type SessionID = `${AccountID | AgentID}_session_z${string}`;
package/src/index.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  import {
2
2
  CoValueCore,
3
- type CoValueUniqueness,
4
3
  newRandomSessionID,
5
4
  MAX_RECOMMENDED_TX_SIZE,
6
5
  idforHeader,
7
6
  } from "./coValueCore.js";
8
7
  import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
9
8
  import { LocalNode } from "./localNode.js";
10
- import type { RawCoValue } from "./coValue.js";
9
+ import { type RawCoValue } from "./coValue.js";
11
10
  import { RawCoMap } from "./coValues/coMap.js";
12
11
  import { RawCoList } from "./coValues/coList.js";
13
12
  import { RawCoStream, RawBinaryCoStream } from "./coValues/coStream.js";
@@ -51,7 +50,7 @@ import type {
51
50
  import { DisconnectedError, PingTimeoutError } from "./sync.js";
52
51
  import type { AgentSecret } from "./crypto/crypto.js";
53
52
  import type {
54
- RawAccountID,
53
+ AccountID,
55
54
  AccountMeta,
56
55
  RawAccountMigration,
57
56
  } from "./coValues/account.js";
@@ -62,6 +61,7 @@ type Value = JsonValue | AnyRawCoValue;
62
61
 
63
62
  import { LSMStorage, BlockFilename, WalFilename } from "./storage/index.js";
64
63
  import { FileSystem } from "./storage/FileSystem.js";
64
+ import { getPriorityFromHeader } from "./priority.js";
65
65
 
66
66
  /** @hidden */
67
67
  export const cojsonInternals = {
@@ -81,6 +81,7 @@ export const cojsonInternals = {
81
81
  idforHeader,
82
82
  StreamingHash,
83
83
  Channel,
84
+ getPriorityFromHeader,
84
85
  };
85
86
 
86
87
  export {
@@ -97,7 +98,7 @@ export {
97
98
  CoID,
98
99
  AnyRawCoValue,
99
100
  RawAccount,
100
- RawAccountID,
101
+ AccountID,
101
102
  AccountMeta,
102
103
  RawAccountMigration,
103
104
  RawProfile as Profile,
@@ -131,7 +132,6 @@ export type {
131
132
  OutgoingSyncQueue,
132
133
  DisconnectedError,
133
134
  PingTimeoutError,
134
- CoValueUniqueness
135
135
  };
136
136
 
137
137
  // eslint-disable-next-line @typescript-eslint/no-namespace
package/src/localNode.ts CHANGED
@@ -2,7 +2,6 @@ import { AgentSecret, CryptoProvider } from "./crypto/crypto.js";
2
2
  import {
3
3
  CoValueCore,
4
4
  CoValueHeader,
5
- CoValueUniqueness,
6
5
  newRandomSessionID,
7
6
  } from "./coValueCore.js";
8
7
  import {
@@ -20,7 +19,7 @@ import {
20
19
  ControlledAccountOrAgent,
21
20
  RawControlledAccount,
22
21
  ControlledAgent,
23
- RawAccountID,
22
+ AccountID,
24
23
  RawProfile,
25
24
  RawAccountMigration,
26
25
  InvalidAccountAgentIDError,
@@ -82,7 +81,7 @@ export class LocalNode {
82
81
  initialAgentSecret?: AgentSecret;
83
82
  }): Promise<{
84
83
  node: LocalNode;
85
- accountID: RawAccountID;
84
+ accountID: AccountID;
86
85
  accountSecret: AgentSecret;
87
86
  sessionID: SessionID;
88
87
  }> {
@@ -174,7 +173,7 @@ export class LocalNode {
174
173
  crypto,
175
174
  migration,
176
175
  }: {
177
- accountID: RawAccountID;
176
+ accountID: AccountID;
178
177
  accountSecret: AgentSecret;
179
178
  sessionID: SessionID | undefined;
180
179
  peersToLoadFrom: Peer[];
@@ -471,7 +470,7 @@ export class LocalNode {
471
470
  }
472
471
 
473
472
  /** @internal */
474
- expectProfileLoaded(id: RawAccountID, expectation?: string): RawProfile {
473
+ expectProfileLoaded(id: AccountID, expectation?: string): RawProfile {
475
474
  const account = this.expectCoValueLoaded(id, expectation);
476
475
  const profileID = expectGroup(account.getCurrentContent()).get(
477
476
  "profile",
@@ -534,7 +533,7 @@ export class LocalNode {
534
533
 
535
534
  /** @internal */
536
535
  resolveAccountAgent(
537
- id: RawAccountID | AgentID,
536
+ id: AccountID | AgentID,
538
537
  expectation?: string,
539
538
  ): Result<AgentID, ResolveAccountAgentError> {
540
539
  if (isAgentID(id)) {
@@ -561,7 +560,7 @@ export class LocalNode {
561
560
  }
562
561
 
563
562
  resolveAccountAgentAsync(
564
- id: RawAccountID | AgentID,
563
+ id: AccountID | AgentID,
565
564
  expectation?: string,
566
565
  ): ResultAsync<AgentID, ResolveAccountAgentError> {
567
566
  if (isAgentID(id)) {
@@ -607,12 +606,12 @@ export class LocalNode {
607
606
  /**
608
607
  * @deprecated use Account.createGroup() instead
609
608
  */
610
- createGroup(uniqueness: CoValueUniqueness = this.crypto.createdNowUnique()): RawGroup {
609
+ createGroup(): RawGroup {
611
610
  const groupCoValue = this.createCoValue({
612
611
  type: "comap",
613
612
  ruleset: { type: "group", initialAdmin: this.account.id },
614
613
  meta: null,
615
- ...uniqueness
614
+ ...this.crypto.createdNowUnique(),
616
615
  });
617
616
 
618
617
  const group = expectGroup(groupCoValue.getCurrentContent());
@@ -732,19 +731,19 @@ export type LoadCoValueCoreError = {
732
731
  type: "ErrorLoadingCoValueCore";
733
732
  error: unknown;
734
733
  expectation?: string;
735
- id: RawAccountID;
734
+ id: AccountID;
736
735
  };
737
736
 
738
737
  export type AccountUnavailableFromAllPeersError = {
739
738
  type: "AccountUnavailableFromAllPeers";
740
739
  expectation?: string;
741
- id: RawAccountID;
740
+ id: AccountID;
742
741
  };
743
742
 
744
743
  export type UnexpectedlyNotAccountError = {
745
744
  type: "UnexpectedlyNotAccount";
746
745
  expectation?: string;
747
- id: RawAccountID;
746
+ id: AccountID;
748
747
  };
749
748
 
750
749
  export type ResolveAccountAgentError =
@@ -5,13 +5,13 @@ import { KeyID } from "./crypto/crypto.js";
5
5
  import { CoValueCore, Transaction } from "./coValueCore.js";
6
6
  import { accountOrAgentIDfromSessionID } from "./typeUtils/accountOrAgentIDfromSessionID.js";
7
7
  import { AgentID, RawCoID, SessionID, TransactionID } from "./ids.js";
8
- import { RawAccount, RawAccountID, RawProfile } from "./coValues/account.js";
8
+ import { RawAccount, AccountID, RawProfile } from "./coValues/account.js";
9
9
  import { parseJSON } from "./jsonStringify.js";
10
10
  import { EVERYONE, Everyone } from "./coValues/group.js";
11
11
  import { expectGroup } from "./typeUtils/expectGroup.js";
12
12
 
13
13
  export type PermissionsDef =
14
- | { type: "group"; initialAdmin: RawAccountID | AgentID }
14
+ | { type: "group"; initialAdmin: AccountID | AgentID }
15
15
  | { type: "ownedByGroup"; group: RawCoID }
16
16
  | { type: "unsafeAllowAll" };
17
17
 
@@ -53,7 +53,7 @@ export function determineValidTransactions(
53
53
  }
54
54
 
55
55
  const memberState: {
56
- [agent: RawAccountID | AgentID]: Role;
56
+ [agent: AccountID | AgentID]: Role;
57
57
  [EVERYONE]?: Role;
58
58
  } = {};
59
59
 
@@ -99,7 +99,7 @@ export function determineValidTransactions(
99
99
  }
100
100
 
101
101
  const change = changes[0] as
102
- | MapOpPayload<RawAccountID | AgentID | Everyone, Role>
102
+ | MapOpPayload<AccountID | AgentID | Everyone, Role>
103
103
  | MapOpPayload<"readKey", JsonValue>
104
104
  | MapOpPayload<"profile", CoID<RawProfile>>;
105
105
  if (changes.length !== 1) {
@@ -303,7 +303,7 @@ export function isKeyForKeyField(co: string): co is `${KeyID}_for_${KeyID}` {
303
303
 
304
304
  export function isKeyForAccountField(
305
305
  co: string,
306
- ): co is `${KeyID}_for_${RawAccountID | AgentID}` {
306
+ ): co is `${KeyID}_for_${AccountID | AgentID}` {
307
307
  return (
308
308
  (co.startsWith("key_") &&
309
309
  (co.includes("_for_sealer") || co.includes("_for_co"))) ||
@@ -0,0 +1,39 @@
1
+ import { type CoValueHeader } from "./coValueCore.js";
2
+
3
+ /**
4
+ * The priority of a `CoValue` determines how much priority is given
5
+ * to its content messages.
6
+ *
7
+ * The priority value is handled as weight in the weighed round robin algorithm
8
+ * used to determine the order in which messages are sent.
9
+ *
10
+ * Follows the HTTP urgency range and order:
11
+ * - https://www.rfc-editor.org/rfc/rfc9218.html#name-urgency
12
+ */
13
+ export const CO_VALUE_PRIORITY = {
14
+ HIGH: 0,
15
+ MEDIUM: 3,
16
+ LOW: 6,
17
+ } as const;
18
+
19
+ export type CoValuePriority = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
20
+
21
+ export function getPriorityFromHeader(header: CoValueHeader | undefined | boolean): CoValuePriority {
22
+ if (typeof header === "boolean" || !header) {
23
+ return CO_VALUE_PRIORITY.MEDIUM;
24
+ }
25
+
26
+ if (header.meta?.type === "account") {
27
+ return CO_VALUE_PRIORITY.HIGH;
28
+ }
29
+
30
+ if (header.ruleset.type === "group") {
31
+ return CO_VALUE_PRIORITY.HIGH;
32
+ }
33
+
34
+ if (header.type === "costream" && header.meta?.type === "binary") {
35
+ return CO_VALUE_PRIORITY.LOW;
36
+ }
37
+
38
+ return CO_VALUE_PRIORITY.MEDIUM;
39
+ }
@@ -1,5 +1,6 @@
1
1
  import { RawCoID, SessionID } from "../ids.js";
2
2
  import { MAX_RECOMMENDED_TX_SIZE } from "../index.js";
3
+ import { getPriorityFromHeader } from "../priority.js";
3
4
  import { CoValueKnownState, NewContentMessage } from "../sync.js";
4
5
  import { CoValueChunk } from "./index.js";
5
6
 
@@ -15,6 +16,7 @@ export function contentSinceChunk(
15
16
  action: "content",
16
17
  header: known?.header ? undefined : chunk.header,
17
18
  new: {},
19
+ priority: getPriorityFromHeader(chunk.header),
18
20
  });
19
21
 
20
22
  for (const [sessionID, sessionsEntry] of Object.entries(
package/src/sync.ts CHANGED
@@ -3,6 +3,8 @@ import { CoValueHeader, Transaction } from "./coValueCore.js";
3
3
  import { CoValueCore } from "./coValueCore.js";
4
4
  import { LocalNode, newLoadingState } from "./localNode.js";
5
5
  import { RawCoID, SessionID } from "./ids.js";
6
+ import { PeerState } from "./PeerState.js";
7
+ import { CoValuePriority } from "./priority.js";
6
8
 
7
9
  export type CoValueKnownState = {
8
10
  id: RawCoID;
@@ -38,6 +40,7 @@ export type NewContentMessage = {
38
40
  action: "content";
39
41
  id: RawCoID;
40
42
  header?: CoValueHeader;
43
+ priority: CoValuePriority;
41
44
  new: {
42
45
  [sessionID: SessionID]: SessionNewContent;
43
46
  };
@@ -76,17 +79,6 @@ export interface Peer {
76
79
  crashOnClose: boolean;
77
80
  }
78
81
 
79
- export interface PeerState {
80
- id: PeerID;
81
- optimisticKnownStates: { [id: RawCoID]: CoValueKnownState };
82
- toldKnownState: Set<RawCoID>;
83
- incoming: IncomingSyncStream;
84
- outgoing: OutgoingSyncQueue;
85
- role: "peer" | "server" | "client";
86
- priority?: number;
87
- crashOnClose: boolean;
88
- }
89
-
90
82
  export function combinedKnownStates(
91
83
  stateA: CoValueKnownState,
92
84
  stateB: CoValueKnownState,
@@ -141,7 +133,7 @@ export class SyncManager {
141
133
 
142
134
  for (const peer of eligiblePeers) {
143
135
  // console.log("loading", id, "from", peer.id);
144
- await peer.outgoing.push({
136
+ await peer.pushOutgoingMessage({
145
137
  action: "load",
146
138
  id: id,
147
139
  header: false,
@@ -227,7 +219,7 @@ export class SyncManager {
227
219
  id,
228
220
  header: false,
229
221
  sessions: {},
230
- }).catch((e) => {
222
+ }).catch((e: unknown) => {
231
223
  console.error("Error sending load", e);
232
224
  });
233
225
  return;
@@ -244,7 +236,7 @@ export class SyncManager {
244
236
  this.trySendToPeer(peer, {
245
237
  action: "load",
246
238
  ...coValue.knownState(),
247
- }).catch((e) => {
239
+ }).catch((e: unknown) => {
248
240
  console.error("Error sending load", e);
249
241
  });
250
242
  }
@@ -274,7 +266,7 @@ export class SyncManager {
274
266
  action: "known",
275
267
  asDependencyOf,
276
268
  ...coValue.knownState(),
277
- }).catch((e) => {
269
+ }).catch((e: unknown) => {
278
270
  console.error("Error sending known state", e);
279
271
  });
280
272
 
@@ -282,7 +274,10 @@ export class SyncManager {
282
274
  }
283
275
  }
284
276
 
285
- async sendNewContentIncludingDependencies(id: RawCoID, peer: PeerState) {
277
+ async sendNewContentIncludingDependencies(
278
+ id: RawCoID,
279
+ peer: PeerState,
280
+ ) {
286
281
  const coValue = this.local.expectCoValueLoaded(id);
287
282
 
288
283
  await Promise.all(
@@ -310,9 +305,11 @@ export class SyncManager {
310
305
  // } header: ${!!piece.header}`,
311
306
  // // Object.values(piece.new).map((s) => s.newTransactions)
312
307
  // );
313
- this.trySendToPeer(peer, piece).catch((e) => {
308
+
309
+ this.trySendToPeer(peer, piece).catch((e: unknown) => {
314
310
  console.error("Error sending content piece", e);
315
311
  });
312
+
316
313
  if (performance.now() - lastYield > 10) {
317
314
  await new Promise<void>((resolve) => {
318
315
  setTimeout(resolve, 0);
@@ -336,16 +333,7 @@ export class SyncManager {
336
333
  }
337
334
 
338
335
  addPeer(peer: Peer) {
339
- const peerState: PeerState = {
340
- id: peer.id,
341
- optimisticKnownStates: {},
342
- incoming: peer.incoming,
343
- outgoing: peer.outgoing,
344
- toldKnownState: new Set(),
345
- role: peer.role,
346
- priority: peer.priority,
347
- crashOnClose: peer.crashOnClose,
348
- };
336
+ const peerState = new PeerState(peer);
349
337
  this.peers[peer.id] = peerState;
350
338
 
351
339
  if (peer.role === "server") {
@@ -420,7 +408,7 @@ export class SyncManager {
420
408
  }
421
409
 
422
410
  trySendToPeer(peer: PeerState, msg: SyncMessage) {
423
- return peer.outgoing.push(msg);
411
+ return peer.pushOutgoingMessage(msg);
424
412
  }
425
413
 
426
414
  async handleLoad(msg: LoadMessage, peer: PeerState) {
@@ -679,7 +667,8 @@ export class SyncManager {
679
667
  newTransactions.length + " new transactions",
680
668
  "after: " + newContentForSession.after,
681
669
  "our last known tx idx initially: " + ourKnownTxIdx,
682
- "our last known tx idx now: " + coValue.sessionLogs.get(sessionID)?.transactions.length,
670
+ "our last known tx idx now: " +
671
+ coValue.sessionLogs.get(sessionID)?.transactions.length,
683
672
  );
684
673
  continue;
685
674
  }
@@ -774,11 +763,7 @@ export class SyncManager {
774
763
 
775
764
  gracefulShutdown() {
776
765
  for (const peer of Object.values(this.peers)) {
777
- console.debug("Gracefully closing", peer.id);
778
- peer.outgoing.close();
779
- peer.incoming = (async function* () {
780
- yield "Disconnected" as const;
781
- })();
766
+ peer.gracefulShutdown();
782
767
  }
783
768
  }
784
769
  }