cojson 0.6.6 → 0.7.0-alpha.0

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 (56) hide show
  1. package/.eslintrc.cjs +1 -0
  2. package/.turbo/turbo-build.log +35 -0
  3. package/CHANGELOG.md +6 -0
  4. package/dist/coValue.js.map +1 -1
  5. package/dist/coValueCore.js.map +1 -1
  6. package/dist/coValues/account.js +5 -5
  7. package/dist/coValues/account.js.map +1 -1
  8. package/dist/coValues/coList.js +39 -58
  9. package/dist/coValues/coList.js.map +1 -1
  10. package/dist/coValues/coMap.js +20 -61
  11. package/dist/coValues/coMap.js.map +1 -1
  12. package/dist/coValues/coStream.js +14 -64
  13. package/dist/coValues/coStream.js.map +1 -1
  14. package/dist/coValues/group.js +57 -59
  15. package/dist/coValues/group.js.map +1 -1
  16. package/dist/coreToCoValue.js +17 -12
  17. package/dist/coreToCoValue.js.map +1 -1
  18. package/dist/index.js +8 -8
  19. package/dist/index.js.map +1 -1
  20. package/dist/localNode.js +54 -38
  21. package/dist/localNode.js.map +1 -1
  22. package/dist/permissions.js +2 -2
  23. package/dist/permissions.js.map +1 -1
  24. package/dist/sync.js +3 -3
  25. package/dist/sync.js.map +1 -1
  26. package/dist/tests/testUtils.js +6 -11
  27. package/dist/tests/testUtils.js.map +1 -1
  28. package/dist/typeUtils/expectGroup.js +2 -2
  29. package/dist/typeUtils/expectGroup.js.map +1 -1
  30. package/dist/typeUtils/isCoValue.js +8 -8
  31. package/dist/typeUtils/isCoValue.js.map +1 -1
  32. package/package.json +52 -53
  33. package/src/coValue.ts +21 -21
  34. package/src/coValueCore.ts +8 -8
  35. package/src/coValues/account.ts +14 -26
  36. package/src/coValues/coList.ts +58 -97
  37. package/src/coValues/coMap.ts +27 -129
  38. package/src/coValues/coStream.ts +31 -137
  39. package/src/coValues/group.ts +52 -46
  40. package/src/coreToCoValue.ts +16 -12
  41. package/src/index.ts +27 -36
  42. package/src/jsonValue.ts +1 -1
  43. package/src/localNode.ts +88 -75
  44. package/src/media.ts +4 -4
  45. package/src/permissions.ts +2 -2
  46. package/src/sync.ts +3 -3
  47. package/src/tests/account.test.ts +12 -12
  48. package/src/tests/coValue.test.ts +149 -182
  49. package/src/tests/coValueCore.test.ts +8 -3
  50. package/src/tests/crypto.test.ts +7 -0
  51. package/src/tests/group.test.ts +13 -6
  52. package/src/tests/permissions.test.ts +648 -840
  53. package/src/tests/sync.test.ts +44 -68
  54. package/src/tests/testUtils.ts +6 -11
  55. package/src/typeUtils/expectGroup.ts +4 -4
  56. package/src/typeUtils/isCoValue.ts +11 -11
@@ -1,11 +1,11 @@
1
1
  import { JsonObject, JsonValue } from "../jsonValue.js";
2
2
  import { AgentID, TransactionID } from "../ids.js";
3
- import { CoID, CoValue } from "../coValue.js";
3
+ import { CoID, RawCoValue } from "../coValue.js";
4
4
  import { isCoValue } from "../typeUtils/isCoValue.js";
5
5
  import { CoValueCore } from "../coValueCore.js";
6
6
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
7
7
  import { AccountID } from "./account.js";
8
- import type { Group } from "./group.js";
8
+ import type { RawGroup } from "./group.js";
9
9
 
10
10
  type MapOp<K extends string, V extends JsonValue | undefined> = {
11
11
  txID: TransactionID;
@@ -25,12 +25,12 @@ export type MapOpPayload<K extends string, V extends JsonValue | undefined> =
25
25
  key: K;
26
26
  };
27
27
 
28
- export class CoMapView<
28
+ export class RawCoMapView<
29
29
  Shape extends { [key: string]: JsonValue | undefined } = {
30
30
  [key: string]: JsonValue | undefined;
31
31
  },
32
- Meta extends JsonObject | null = JsonObject | null
33
- > implements CoValue
32
+ Meta extends JsonObject | null = JsonObject | null,
33
+ > implements RawCoValue
34
34
  {
35
35
  /** @category 6. Meta */
36
36
  id: CoID<this>;
@@ -88,7 +88,7 @@ export class CoMapView<
88
88
  }
89
89
 
90
90
  /** @category 6. Meta */
91
- get group(): Group {
91
+ get group(): RawGroup {
92
92
  return this.core.getGroup();
93
93
  }
94
94
 
@@ -250,16 +250,16 @@ export class CoMapView<
250
250
  }
251
251
 
252
252
  /** A collaborative map with precise shape `Shape` and optional static metadata `Meta` */
253
- export class CoMap<
253
+ export class RawCoMap<
254
254
  Shape extends { [key: string]: JsonValue | undefined } = {
255
255
  [key: string]: JsonValue | undefined;
256
256
  },
257
- Meta extends JsonObject | null = JsonObject | null
257
+ Meta extends JsonObject | null = JsonObject | null,
258
258
  >
259
- extends CoMapView<Shape, Meta>
260
- implements CoValue
259
+ extends RawCoMapView<Shape, Meta>
260
+ implements RawCoValue
261
261
  {
262
- /** Returns a new version of this CoMap with a new value for the given key.
262
+ /** Set a new value for the given key.
263
263
  *
264
264
  * If `privacy` is `"private"` **(default)**, both `key` and `value` are encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
265
265
  *
@@ -270,64 +270,25 @@ export class CoMap<
270
270
  set<K extends keyof Shape & string>(
271
271
  key: K,
272
272
  value: Shape[K],
273
- privacy?: "private" | "trusting"
274
- ): this;
275
- set(
276
- kv: {
277
- [K in keyof Shape & string]?: Shape[K];
278
- },
279
- privacy?: "private" | "trusting"
280
- ): this;
281
- set<K extends keyof Shape & string>(
282
- ...args:
283
- | [
284
- {
285
- [K in keyof Shape & string]?: Shape[K];
286
- },
287
- ("private" | "trusting")?
288
- ]
289
- | [K, Shape[K], ("private" | "trusting")?]
290
- ): this {
291
- if (typeof args[0] === "string") {
292
- const [key, value, privacy = "private"] = args;
293
- this.core.makeTransaction(
294
- [
295
- {
296
- op: "set",
297
- key,
298
- value: isCoValue(value) ? value.id : value,
299
- },
300
- ],
301
- privacy
302
- );
303
- } else {
304
- const [kv, privacy = "private"] = args as [
273
+ privacy: "private" | "trusting" = "private"
274
+ ): void {
275
+ this.core.makeTransaction(
276
+ [
305
277
  {
306
- [K in keyof Shape & string]: Shape[K] extends CoValue
307
- ? Shape[K] | CoID<Shape[K]>
308
- : Shape[K];
278
+ op: "set",
279
+ key,
280
+ value: isCoValue(value) ? value.id : value,
309
281
  },
310
- "private" | "trusting" | undefined
311
- ];
312
-
313
- for (const [key, value] of Object.entries(kv)) {
314
- this.core.makeTransaction(
315
- [
316
- {
317
- op: "set",
318
- key,
319
- value: isCoValue(value) ? value.id : value,
320
- },
321
- ],
322
- privacy
323
- );
324
- }
325
- }
282
+ ],
283
+ privacy
284
+ );
285
+
286
+ const after = new RawCoMap(this.core) as this;
326
287
 
327
- return new CoMap(this.core) as this;
288
+ this.ops = after.ops;
328
289
  }
329
290
 
330
- /** Returns a new version of this CoMap with the given key deleted (setting it to undefined).
291
+ /** Delete the given key (setting it to undefined).
331
292
  *
332
293
  * If `privacy` is `"private"` **(default)**, `key` is encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
333
294
  *
@@ -338,7 +299,7 @@ export class CoMap<
338
299
  delete(
339
300
  key: keyof Shape & string,
340
301
  privacy: "private" | "trusting" = "private"
341
- ): this {
302
+ ) {
342
303
  this.core.makeTransaction(
343
304
  [
344
305
  {
@@ -349,71 +310,8 @@ export class CoMap<
349
310
  privacy
350
311
  );
351
312
 
352
- return new CoMap(this.core) as this;
353
- }
313
+ const after = new RawCoMap(this.core) as this;
354
314
 
355
- /** @category 2. Editing */
356
- mutate(mutator: (mutable: MutableCoMap<Shape, Meta>) => void): this {
357
- const mutable = new MutableCoMap<Shape, Meta>(this.core);
358
- mutator(mutable);
359
- return new (this.constructor as new (core: CoValueCore) => this)(
360
- this.core
361
- );
362
- }
363
-
364
- /** @deprecated Use `mutate` instead. */
365
- edit(mutator: (mutable: MutableCoMap<Shape, Meta>) => void): this {
366
- return this.mutate(mutator);
367
- }
368
- }
369
-
370
- export class MutableCoMap<
371
- Shape extends { [key: string]: JsonValue | undefined } = {
372
- [key: string]: JsonValue | undefined;
373
- },
374
- Meta extends JsonObject | null = JsonObject | null
375
- >
376
- extends CoMapView<Shape, Meta>
377
- implements CoValue
378
- {
379
- /** Sets a new value for the given key.
380
- *
381
- * If `privacy` is `"private"` **(default)**, both `key` and `value` are encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
382
- *
383
- * If `privacy` is `"trusting"`, both `key` and `value` are stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
384
- *
385
- * @category 2. Mutation
386
- */
387
- set<K extends keyof Shape & string>(
388
- key: K,
389
- value: Shape[K],
390
- privacy: "private" | "trusting" = "private"
391
- ): void {
392
- // eslint-disable-next-line @typescript-eslint/ban-types
393
- const after = (CoMap.prototype.set as Function).call(
394
- this,
395
- key,
396
- value,
397
- privacy
398
- ) as CoMap<Shape, Meta>;
399
- this.ops = after.ops;
400
- }
401
-
402
- /** Deletes the value for the given key (setting it to undefined).
403
- *
404
- * If `privacy` is `"private"` **(default)**, `key` is encrypted in the transaction, only readable by other members of the group this `CoMap` belongs to. Not even sync servers can see the content in plaintext.
405
- *
406
- * If `privacy` is `"trusting"`, `key` is stored in plaintext in the transaction, visible to everyone who gets a hold of it, including sync servers.
407
- * @category 2. Mutation
408
- */
409
- delete(
410
- key: keyof Shape & string,
411
- privacy: "private" | "trusting" = "private"
412
- ): void {
413
- const after = CoMap.prototype.delete.call(this, key, privacy) as CoMap<
414
- Shape,
415
- Meta
416
- >;
417
315
  this.ops = after.ops;
418
316
  }
419
317
  }
@@ -1,10 +1,10 @@
1
1
  import { JsonObject, JsonValue } from "../jsonValue.js";
2
- import { CoValue, CoID } from "../coValue.js";
2
+ import { RawCoValue, CoID } from "../coValue.js";
3
3
  import { isAccountID } from "../typeUtils/isAccountID.js";
4
4
  import { isCoValue } from "../typeUtils/isCoValue.js";
5
5
  import { CoValueCore } from "../coValueCore.js";
6
6
  import { accountOrAgentIDfromSessionID } from "../typeUtils/accountOrAgentIDfromSessionID.js";
7
- import { Group } from "./group.js";
7
+ import { RawGroup } from "./group.js";
8
8
  import { AgentID, SessionID, TransactionID } from "../ids.js";
9
9
  import { base64URLtoBytes, bytesToBase64url } from "../base64url.js";
10
10
  import { AccountID } from "./account.js";
@@ -41,10 +41,10 @@ export type CoStreamItem<Item extends JsonValue> = {
41
41
  madeAt: number;
42
42
  };
43
43
 
44
- export class CoStreamView<
44
+ export class RawCoStreamView<
45
45
  Item extends JsonValue = JsonValue,
46
46
  Meta extends JsonObject | null = JsonObject | null
47
- > implements CoValue
47
+ > implements RawCoValue
48
48
  {
49
49
  id: CoID<this>;
50
50
  type = "costream" as const;
@@ -65,7 +65,7 @@ export class CoStreamView<
65
65
  return this.core.header.meta as Meta;
66
66
  }
67
67
 
68
- get group(): Group {
68
+ get group(): RawGroup {
69
69
  return this.core.getGroup();
70
70
  }
71
71
 
@@ -95,9 +95,7 @@ export class CoStreamView<
95
95
  }
96
96
  }
97
97
 
98
- getSingleStream():
99
- | (Item)[]
100
- | undefined {
98
+ getSingleStream(): Item[] | undefined {
101
99
  if (Object.keys(this.items).length === 0) {
102
100
  return undefined;
103
101
  } else if (Object.keys(this.items).length !== 1) {
@@ -114,7 +112,11 @@ export class CoStreamView<
114
112
  }
115
113
 
116
114
  accounts(): Set<AccountID> {
117
- return new Set(this.sessions().map(accountOrAgentIDfromSessionID).filter(isAccountID));
115
+ return new Set(
116
+ this.sessions()
117
+ .map(accountOrAgentIDfromSessionID)
118
+ .filter(isAccountID)
119
+ );
118
120
  }
119
121
 
120
122
  nthItemIn(
@@ -224,7 +226,7 @@ export class CoStreamView<
224
226
  }
225
227
 
226
228
  toJSON(): {
227
- [key: SessionID]: (Item )[];
229
+ [key: SessionID]: Item[];
228
230
  } {
229
231
  return Object.fromEntries(
230
232
  Object.entries(this.items).map(([sessionID, items]) => [
@@ -241,44 +243,14 @@ export class CoStreamView<
241
243
  }
242
244
  }
243
245
 
244
- export class CoStream<
246
+ export class RawCoStream<
245
247
  Item extends JsonValue = JsonValue,
246
248
  Meta extends JsonObject | null = JsonObject | null
247
249
  >
248
- extends CoStreamView<Item, Meta>
249
- implements CoValue
250
+ extends RawCoStreamView<Item, Meta>
251
+ implements RawCoValue
250
252
  {
251
- push(
252
- item: Item,
253
- privacy: "private" | "trusting" = "private"
254
- ): this {
255
- this.core.makeTransaction([isCoValue(item) ? item.id : item], privacy);
256
- return new CoStream(this.core) as this;
257
- }
258
-
259
- mutate(mutator: (mutable: MutableCoStream<Item, Meta>) => void): this {
260
- const mutable = new MutableCoStream<Item, Meta>(this.core);
261
- mutator(mutable);
262
- return new CoStream(this.core) as this;
263
- }
264
-
265
- /** @deprecated Use `mutate` instead. */
266
- edit(mutator: (mutable: MutableCoStream<Item, Meta>) => void): this {
267
- return this.mutate(mutator);
268
- }
269
- }
270
-
271
- export class MutableCoStream<
272
- Item extends JsonValue,
273
- Meta extends JsonObject | null = JsonObject | null
274
- >
275
- extends CoStreamView<Item, Meta>
276
- implements CoValue
277
- {
278
- push(
279
- item: Item,
280
- privacy: "private" | "trusting" = "private"
281
- ) {
253
+ push(item: Item, privacy: "private" | "trusting" = "private"): void {
282
254
  this.core.makeTransaction([isCoValue(item) ? item.id : item], privacy);
283
255
  this.fillFromCoValue();
284
256
  }
@@ -286,14 +258,14 @@ export class MutableCoStream<
286
258
 
287
259
  const binary_U_prefixLength = 8; // "binary_U".length;
288
260
 
289
- export class BinaryCoStreamView<
261
+ export class RawBinaryCoStreamView<
290
262
  Meta extends BinaryCoStreamMeta = { type: "binary" }
291
263
  >
292
- extends CoStreamView<BinaryStreamItem, Meta>
293
- implements CoValue
264
+ extends RawCoStreamView<BinaryStreamItem, Meta>
265
+ implements RawCoValue
294
266
  {
295
267
  getBinaryChunks(
296
- allowUnfinished?: boolean,
268
+ allowUnfinished?: boolean
297
269
  ):
298
270
  | (BinaryStreamInfo & { chunks: Uint8Array[]; finished: boolean })
299
271
  | undefined {
@@ -358,35 +330,21 @@ export class BinaryCoStreamView<
358
330
  }
359
331
  }
360
332
 
361
- export class BinaryCoStream<
333
+ export class RawBinaryCoStream<
362
334
  Meta extends BinaryCoStreamMeta = { type: "binary" }
363
335
  >
364
- extends BinaryCoStreamView<Meta>
365
- implements CoValue
336
+ extends RawBinaryCoStreamView<Meta>
337
+ implements RawCoValue
366
338
  {
367
339
  /** @internal */
368
- push(
369
- item: BinaryStreamItem,
370
- privacy?: "private" | "trusting",
371
- ): this
372
- push(
373
- item: BinaryStreamItem,
374
- privacy: "private" | "trusting",
375
- returnNewStream: true
376
- ): this
377
- push(
378
- item: BinaryStreamItem,
379
- privacy: "private" | "trusting",
380
- returnNewStream: false
381
- ): void
382
340
  push(
383
341
  item: BinaryStreamItem,
384
342
  privacy: "private" | "trusting" = "private",
385
- returnNewStream: boolean = true
386
- ): this | void {
343
+ updateView: boolean = true
344
+ ): void {
387
345
  this.core.makeTransaction([item], privacy);
388
- if (returnNewStream) {
389
- return new BinaryCoStream(this.core) as this;
346
+ if (updateView) {
347
+ this.fillFromCoValue();
390
348
  }
391
349
  }
392
350
 
@@ -394,7 +352,7 @@ export class BinaryCoStream<
394
352
  settings: BinaryStreamInfo,
395
353
  privacy: "private" | "trusting" = "private"
396
354
  ): void {
397
- return this.push(
355
+ this.push(
398
356
  {
399
357
  type: "start",
400
358
  ...settings,
@@ -409,7 +367,7 @@ export class BinaryCoStream<
409
367
  privacy: "private" | "trusting" = "private"
410
368
  ): void {
411
369
  // const before = performance.now();
412
- return this.push(
370
+ this.push(
413
371
  {
414
372
  type: "chunk",
415
373
  chunk: `binary_U${bytesToBase64url(chunk)}`,
@@ -424,77 +382,13 @@ export class BinaryCoStream<
424
382
  // );
425
383
  }
426
384
 
427
- endBinaryStream(privacy: "private" | "trusting" = "private"): this {
428
- return this.push(
429
- {
430
- type: "end",
431
- } satisfies BinaryStreamEnd,
432
- privacy,
433
- true
434
- );
435
- }
436
-
437
- mutate(mutator: (mutable: MutableBinaryCoStream<Meta>) => void): this {
438
- const mutable = new MutableBinaryCoStream<Meta>(this.core);
439
- mutator(mutable);
440
- return new BinaryCoStream(this.core) as this;
441
- }
442
-
443
- /** @deprecated Use `mutate` instead. */
444
- edit(mutator: (mutable: MutableBinaryCoStream<Meta>) => void): this {
445
- return this.mutate(mutator);
446
- }
447
- }
448
-
449
- export class MutableBinaryCoStream<
450
- Meta extends BinaryCoStreamMeta = { type: "binary" }
451
- >
452
- extends BinaryCoStreamView<Meta>
453
- implements CoValue
454
- {
455
- /** @internal */
456
- push(item: BinaryStreamItem, privacy: "private" | "trusting" = "private") {
457
- MutableCoStream.prototype.push.call(this, item, privacy);
458
- }
459
-
460
- startBinaryStream(
461
- settings: BinaryStreamInfo,
462
- privacy: "private" | "trusting" = "private"
463
- ) {
464
- this.push(
465
- {
466
- type: "start",
467
- ...settings,
468
- } satisfies BinaryStreamStart,
469
- privacy
470
- );
471
- }
472
-
473
- pushBinaryStreamChunk(
474
- chunk: Uint8Array,
475
- privacy: "private" | "trusting" = "private"
476
- ) {
477
- // const before = performance.now();
478
- this.push(
479
- {
480
- type: "chunk",
481
- chunk: `binary_U${bytesToBase64url(chunk)}`,
482
- } satisfies BinaryStreamChunk,
483
- privacy
484
- );
485
- // const after = performance.now();
486
- // console.log(
487
- // "pushBinaryStreamChunk bandwidth in MB/s",
488
- // (1000 * chunk.length) / (after - before) / (1024 * 1024)
489
- // );
490
- }
491
-
492
385
  endBinaryStream(privacy: "private" | "trusting" = "private") {
493
386
  this.push(
494
387
  {
495
388
  type: "end",
496
389
  } satisfies BinaryStreamEnd,
497
- privacy
390
+ privacy,
391
+ true
498
392
  );
499
393
  }
500
394
  }