cojson 0.8.5 → 0.8.12

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 (49) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/native/PeerKnownStates.js +63 -0
  3. package/dist/native/PeerKnownStates.js.map +1 -0
  4. package/dist/native/PeerState.js +5 -1
  5. package/dist/native/PeerState.js.map +1 -1
  6. package/dist/native/coValueState.js +74 -0
  7. package/dist/native/coValueState.js.map +1 -0
  8. package/dist/native/exports.js +39 -0
  9. package/dist/native/exports.js.map +1 -0
  10. package/dist/native/index.native.js +2 -39
  11. package/dist/native/index.native.js.map +1 -1
  12. package/dist/native/localNode.js +29 -51
  13. package/dist/native/localNode.js.map +1 -1
  14. package/dist/native/storage/index.js +2 -2
  15. package/dist/native/storage/index.js.map +1 -1
  16. package/dist/native/sync.js +89 -109
  17. package/dist/native/sync.js.map +1 -1
  18. package/dist/web/PeerKnownStates.js +63 -0
  19. package/dist/web/PeerKnownStates.js.map +1 -0
  20. package/dist/web/PeerState.js +5 -1
  21. package/dist/web/PeerState.js.map +1 -1
  22. package/dist/web/coValueState.js +74 -0
  23. package/dist/web/coValueState.js.map +1 -0
  24. package/dist/web/exports.js +39 -0
  25. package/dist/web/exports.js.map +1 -0
  26. package/dist/web/index.web.js +2 -39
  27. package/dist/web/index.web.js.map +1 -1
  28. package/dist/web/localNode.js +29 -51
  29. package/dist/web/localNode.js.map +1 -1
  30. package/dist/web/storage/index.js +2 -2
  31. package/dist/web/storage/index.js.map +1 -1
  32. package/dist/web/sync.js +89 -109
  33. package/dist/web/sync.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/PeerKnownStates.ts +108 -0
  36. package/src/PeerState.ts +8 -2
  37. package/src/coValueState.ts +107 -0
  38. package/src/exports.ts +149 -0
  39. package/src/index.native.ts +2 -152
  40. package/src/index.web.ts +2 -152
  41. package/src/localNode.ts +43 -90
  42. package/src/storage/index.ts +2 -2
  43. package/src/sync.ts +95 -148
  44. package/src/tests/PeerKnownStates.test.ts +100 -0
  45. package/src/tests/PeerState.test.ts +0 -11
  46. package/src/tests/sync.test.ts +2 -2
  47. package/.turbo/turbo-build.log +0 -16
  48. package/.turbo/turbo-lint.log +0 -4
  49. package/.turbo/turbo-test.log +0 -1001
package/src/localNode.ts CHANGED
@@ -28,10 +28,11 @@ import {
28
28
  import { RawCoValue } from "./coValue.js";
29
29
  import { expectGroup } from "./typeUtils/expectGroup.js";
30
30
  import { err, ok, okAsync, Result, ResultAsync } from "neverthrow";
31
+ import { CoValueState } from "./coValueState.js";
31
32
 
32
33
  /** A `LocalNode` represents a local view of a set of loaded `CoValue`s, from the perspective of a particular account (or primitive cryptographic agent).
33
34
 
34
- A `LocalNode` can have peers that it syncs to, for example some form of local persistence, or a sync server, such as `sync.jazz.tools` (Jazz Global Mesh).
35
+ A `LocalNode` can have peers that it syncs to, for example some form of local persistence, or a sync server, such as `cloud.jazz.tools` (Jazz Cloud).
35
36
 
36
37
  @example
37
38
  You typically get hold of a `LocalNode` using `jazz-react`'s `useJazz()`:
@@ -130,10 +131,9 @@ export class LocalNode {
130
131
  );
131
132
 
132
133
  nodeWithAccount.account = controlledAccount;
133
- nodeWithAccount.coValues[controlledAccount.id] = {
134
- state: "loaded",
135
- coValue: controlledAccount.core,
136
- };
134
+ nodeWithAccount.coValues[controlledAccount.id] = CoValueState.Available(
135
+ controlledAccount.core,
136
+ );
137
137
  controlledAccount.core._cachedContent = undefined;
138
138
 
139
139
  if (!controlledAccount.get("profile")) {
@@ -145,9 +145,9 @@ export class LocalNode {
145
145
  for (const coValueEntry of Object.values(
146
146
  nodeWithAccount.coValues,
147
147
  )) {
148
- if (coValueEntry.state === "loaded") {
148
+ if (coValueEntry.state.type === "available") {
149
149
  void nodeWithAccount.syncManager.syncCoValue(
150
- coValueEntry.coValue,
150
+ coValueEntry.state.coValue,
151
151
  );
152
152
  }
153
153
  }
@@ -214,10 +214,9 @@ export class LocalNode {
214
214
  node.syncManager.local = node;
215
215
 
216
216
  controlledAccount.core.node = node;
217
- node.coValues[accountID] = {
218
- state: "loaded",
219
- coValue: controlledAccount.core,
220
- };
217
+ node.coValues[accountID] = CoValueState.Available(
218
+ controlledAccount.core,
219
+ );
221
220
  controlledAccount.core._cachedContent = undefined;
222
221
 
223
222
  const profileID = account.get("profile");
@@ -257,7 +256,7 @@ export class LocalNode {
257
256
  }
258
257
 
259
258
  const coValue = new CoValueCore(header, this);
260
- this.coValues[coValue.id] = { state: "loaded", coValue: coValue };
259
+ this.coValues[coValue.id] = CoValueState.Available(coValue);
261
260
 
262
261
  void this.syncManager.syncCoValue(coValue);
263
262
 
@@ -270,7 +269,6 @@ export class LocalNode {
270
269
  options: {
271
270
  dontLoadFrom?: PeerID;
272
271
  dontWaitFor?: PeerID;
273
- onProgress?: (progress: number) => void;
274
272
  } = {},
275
273
  ): Promise<CoValueCore | "unavailable"> {
276
274
  if (this.crashed) {
@@ -283,11 +281,11 @@ export class LocalNode {
283
281
  if (!entry) {
284
282
  const peersToWaitFor = new Set(
285
283
  Object.values(this.syncManager.peers)
286
- .filter((peer) => peer.role === "server")
284
+ .filter((peer) => peer.isServerOrStoragePeer())
287
285
  .map((peer) => peer.id),
288
286
  );
289
287
  if (options.dontWaitFor) peersToWaitFor.delete(options.dontWaitFor);
290
- entry = newLoadingState(peersToWaitFor, options.onProgress);
288
+ entry = CoValueState.Unknown(peersToWaitFor);
291
289
 
292
290
  this.coValues[id] = entry;
293
291
 
@@ -302,10 +300,19 @@ export class LocalNode {
302
300
  );
303
301
  });
304
302
  }
305
- if (entry.state === "loaded") {
306
- return Promise.resolve(entry.coValue);
303
+ if (entry.state.type === "available") {
304
+ return Promise.resolve(entry.state.coValue);
307
305
  }
308
- return entry.done;
306
+
307
+ await entry.state.ready;
308
+
309
+ const updatedEntry = this.coValues[id];
310
+
311
+ if (updatedEntry?.state.type === "available") {
312
+ return Promise.resolve(updatedEntry.state.coValue);
313
+ }
314
+
315
+ return "unavailable";
309
316
  }
310
317
 
311
318
  /**
@@ -315,11 +322,8 @@ export class LocalNode {
315
322
  *
316
323
  * @category 3. Low-level
317
324
  */
318
- async load<T extends RawCoValue>(
319
- id: CoID<T>,
320
- onProgress?: (progress: number) => void,
321
- ): Promise<T | "unavailable"> {
322
- const core = await this.loadCoValueCore(id, { onProgress });
325
+ async load<T extends RawCoValue>(id: CoID<T>): Promise<T | "unavailable"> {
326
+ const core = await this.loadCoValueCore(id);
323
327
 
324
328
  if (core === "unavailable") {
325
329
  return "unavailable";
@@ -333,8 +337,8 @@ export class LocalNode {
333
337
  if (!entry) {
334
338
  return undefined;
335
339
  }
336
- if (entry.state === "loaded") {
337
- return entry.coValue.getCurrentContent() as T;
340
+ if (entry.state.type === "available") {
341
+ return entry.state.coValue.getCurrentContent() as T;
338
342
  }
339
343
  return undefined;
340
344
  }
@@ -465,14 +469,14 @@ export class LocalNode {
465
469
  `${expectation ? expectation + ": " : ""}Unknown CoValue ${id}`,
466
470
  );
467
471
  }
468
- if (entry.state === "loading") {
472
+ if (entry.state.type === "unknown") {
469
473
  throw new Error(
470
474
  `${
471
475
  expectation ? expectation + ": " : ""
472
476
  }CoValue ${id} not yet loaded`,
473
477
  );
474
478
  }
475
- return entry.coValue;
479
+ return entry.state.coValue;
476
480
  }
477
481
 
478
482
  /** @internal */
@@ -547,7 +551,7 @@ export class LocalNode {
547
551
  }
548
552
 
549
553
  let coValue: CoValueCore;
550
-
554
+
551
555
  try {
552
556
  coValue = this.expectCoValueLoaded(id, expectation);
553
557
  } catch (e) {
@@ -558,7 +562,7 @@ export class LocalNode {
558
562
  error: e,
559
563
  } satisfies LoadCoValueCoreError);
560
564
  }
561
-
565
+
562
566
  if (
563
567
  coValue.header.type !== "comap" ||
564
568
  coValue.header.ruleset.type !== "group" ||
@@ -673,13 +677,16 @@ export class LocalNode {
673
677
  const [coValueID, entry] =
674
678
  coValuesToCopy[coValuesToCopy.length - 1]!;
675
679
 
676
- if (entry.state === "loading") {
680
+ if (entry.state.type === "unknown") {
677
681
  coValuesToCopy.pop();
678
682
  continue;
679
683
  } else {
680
- const allDepsCopied = entry.coValue
684
+ const allDepsCopied = entry.state.coValue
681
685
  .getDependedOnCoValues()
682
- .every((dep) => newNode.coValues[dep]?.state === "loaded");
686
+ .every(
687
+ (dep) =>
688
+ newNode.coValues[dep]?.state.type === "available",
689
+ );
683
690
 
684
691
  if (!allDepsCopied) {
685
692
  // move to end of queue
@@ -688,15 +695,13 @@ export class LocalNode {
688
695
  }
689
696
 
690
697
  const newCoValue = new CoValueCore(
691
- entry.coValue.header,
698
+ entry.state.coValue.header,
692
699
  newNode,
693
- new Map(entry.coValue.sessionLogs),
700
+ new Map(entry.state.coValue.sessionLogs),
694
701
  );
695
702
 
696
- newNode.coValues[coValueID as RawCoID] = {
697
- state: "loaded",
698
- coValue: newCoValue,
699
- };
703
+ newNode.coValues[coValueID as RawCoID] =
704
+ CoValueState.Available(newCoValue);
700
705
 
701
706
  coValuesToCopy.pop();
702
707
  }
@@ -722,30 +727,6 @@ export class LocalNode {
722
727
  }
723
728
  }
724
729
 
725
- /** @internal */
726
- type CoValueState =
727
- | {
728
- state: "loading";
729
- done: Promise<CoValueCore | "unavailable">;
730
- resolve: (coValue: CoValueCore | "unavailable") => void;
731
- onProgress?: (progress: number) => void;
732
- firstPeerState: {
733
- [peerID: string]:
734
- | {
735
- type: "waiting";
736
- done: Promise<void>;
737
- resolve: () => void;
738
- }
739
- | { type: "available" }
740
- | { type: "unavailable" };
741
- };
742
- }
743
- | {
744
- state: "loaded";
745
- coValue: CoValueCore;
746
- onProgress?: (progress: number) => void;
747
- };
748
-
749
730
  export type LoadCoValueCoreError = {
750
731
  type: "ErrorLoadingCoValueCore";
751
732
  error: unknown;
@@ -770,31 +751,3 @@ export type ResolveAccountAgentError =
770
751
  | LoadCoValueCoreError
771
752
  | AccountUnavailableFromAllPeersError
772
753
  | UnexpectedlyNotAccountError;
773
-
774
- /** @internal */
775
- export function newLoadingState(
776
- currentPeerIds: Set<PeerID>,
777
- onProgress?: (progress: number) => void,
778
- ): CoValueState {
779
- let resolve: (coValue: CoValueCore | "unavailable") => void;
780
-
781
- const promise = new Promise<CoValueCore | "unavailable">((r) => {
782
- resolve = r;
783
- });
784
-
785
- return {
786
- state: "loading",
787
- done: promise,
788
- resolve: resolve!,
789
- onProgress,
790
- firstPeerState: Object.fromEntries(
791
- [...currentPeerIds].map((id) => {
792
- let resolve: () => void;
793
- const done = new Promise<void>((r) => {
794
- resolve = r;
795
- });
796
- return [id, { type: "waiting", done, resolve: resolve! }];
797
- }),
798
- ),
799
- };
800
- }
@@ -79,7 +79,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
79
79
 
80
80
  if (msg.action === "content") {
81
81
  await this.handleNewContent(msg);
82
- } else {
82
+ } else if (msg.action === 'load' || msg.action === 'known') {
83
83
  await this.sendNewContent(msg.id, msg, undefined);
84
84
  }
85
85
  } catch (e) {
@@ -560,7 +560,7 @@ export class LSMStorage<WH, RH, FS extends FileSystem<WH, RH>> {
560
560
  "storage",
561
561
  {
562
562
  peer1role: "client",
563
- peer2role: "server",
563
+ peer2role: "storage",
564
564
  trace,
565
565
  crashOnClose: true,
566
566
  },