cojson 0.1.12 → 0.2.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 (50) hide show
  1. package/dist/coValue.d.ts +1 -1
  2. package/dist/coValueCore.d.ts +4 -3
  3. package/dist/coValueCore.js +5 -4
  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 +10 -1
  11. package/dist/coValues/coStream.js +43 -5
  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 +4 -1
  18. package/dist/index.js +3 -1
  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/sync.js +1 -2
  31. package/dist/sync.js.map +1 -1
  32. package/package.json +2 -2
  33. package/src/coValue.ts +1 -1
  34. package/src/coValueCore.test.ts +11 -10
  35. package/src/coValueCore.ts +9 -6
  36. package/src/coValues/coList.ts +2 -1
  37. package/src/coValues/coMap.ts +11 -12
  38. package/src/coValues/coStream.ts +54 -6
  39. package/src/crypto.ts +22 -4
  40. package/src/group.ts +1 -1
  41. package/src/index.ts +5 -1
  42. package/src/{fastJsonStableStringify.ts → jsonStringify.ts} +23 -11
  43. package/src/jsonValue.ts +1 -1
  44. package/src/media.ts +9 -0
  45. package/src/node.ts +1 -1
  46. package/src/permissions.ts +5 -2
  47. package/src/sync.test.ts +16 -18
  48. package/src/sync.ts +1 -2
  49. package/dist/fastJsonStableStringify.d.ts +0 -1
  50. package/dist/fastJsonStableStringify.js.map +0 -1
package/src/index.ts CHANGED
@@ -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 {
@@ -90,6 +93,7 @@ export type {
90
93
  AgentSecret,
91
94
  InviteSecret,
92
95
  SyncMessage,
96
+ Media
93
97
  };
94
98
 
95
99
  // 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
  }
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:
@@ -465,13 +463,13 @@ test("No matter the optimistic known state, node respects invalid known state me
465
463
  privacy: "trusting" as const,
466
464
  madeAt: map.core.sessions[node.currentSessionID]!
467
465
  .transactions[1]!.madeAt,
468
- changes: [
466
+ changes: stableStringify([
469
467
  {
470
468
  op: "set",
471
469
  key: "goodbye",
472
470
  value: "world",
473
471
  } satisfies MapOpPayload<string, string>,
474
- ],
472
+ ]),
475
473
  },
476
474
  ],
477
475
  lastSignature:
@@ -568,13 +566,13 @@ test("If we add a server peer, all updates to all coValues are sent to it, even
568
566
  privacy: "trusting" as const,
569
567
  madeAt: map.core.sessions[node.currentSessionID]!
570
568
  .transactions[0]!.madeAt,
571
- changes: [
569
+ changes: stableStringify([
572
570
  {
573
571
  op: "set",
574
572
  key: "hello",
575
573
  value: "world",
576
574
  } satisfies MapOpPayload<string, string>,
577
- ],
575
+ ]),
578
576
  },
579
577
  ],
580
578
  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;
@@ -269,7 +269,6 @@ export class SyncManager {
269
269
  );
270
270
  }
271
271
  }
272
- console.log("DONE!!!");
273
272
  } catch (e) {
274
273
  console.error(`Error reading from peer ${peer.id}`, e);
275
274
  }
@@ -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"}