@dxos/echo-pipeline 0.4.9 → 0.4.10-main.06ef97a

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 (39) hide show
  1. package/dist/lib/browser/{chunk-RTEEJ723.mjs → chunk-RA6MLCZM.mjs} +14 -27
  2. package/dist/lib/browser/chunk-RA6MLCZM.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +314 -12
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +1 -1
  7. package/dist/lib/node/{chunk-7VZVCCNF.cjs → chunk-KGIYLJBT.cjs} +20 -33
  8. package/dist/lib/node/chunk-KGIYLJBT.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +335 -32
  10. package/dist/lib/node/index.cjs.map +4 -4
  11. package/dist/lib/node/meta.json +1 -1
  12. package/dist/lib/node/testing/index.cjs +11 -11
  13. package/dist/types/src/automerge/automerge-doc-loader.d.ts +66 -0
  14. package/dist/types/src/automerge/automerge-doc-loader.d.ts.map +1 -0
  15. package/dist/types/src/automerge/automerge-doc-loader.test.d.ts +2 -0
  16. package/dist/types/src/automerge/automerge-doc-loader.test.d.ts.map +1 -0
  17. package/dist/types/src/automerge/automerge-host.d.ts +2 -1
  18. package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
  19. package/dist/types/src/automerge/index.d.ts +3 -0
  20. package/dist/types/src/automerge/index.d.ts.map +1 -1
  21. package/dist/types/src/automerge/reference.d.ts +15 -0
  22. package/dist/types/src/automerge/reference.d.ts.map +1 -0
  23. package/dist/types/src/automerge/types.d.ts +67 -0
  24. package/dist/types/src/automerge/types.d.ts.map +1 -0
  25. package/dist/types/src/space/space.d.ts +4 -8
  26. package/dist/types/src/space/space.d.ts.map +1 -1
  27. package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
  28. package/package.json +30 -30
  29. package/src/automerge/automerge-doc-loader.test.ts +97 -0
  30. package/src/automerge/automerge-doc-loader.ts +241 -0
  31. package/src/automerge/automerge-host.ts +15 -6
  32. package/src/automerge/index.ts +3 -0
  33. package/src/automerge/reference.ts +31 -0
  34. package/src/automerge/types.ts +83 -0
  35. package/src/db-host/data-service.ts +1 -1
  36. package/src/space/space.test.ts +7 -7
  37. package/src/space/space.ts +6 -21
  38. package/dist/lib/browser/chunk-RTEEJ723.mjs.map +0 -7
  39. package/dist/lib/node/chunk-7VZVCCNF.cjs.map +0 -7
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automerge-doc-loader.d.ts","sourceRoot":"","sources":["../../../../src/automerge/automerge-doc-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAmB,KAAK,IAAI,EAAE,MAAM,gCAAgC,CAAC;AAC/G,OAAO,EAAqB,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAGhE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEzD,KAAK,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;AAE5C,MAAM,WAAW,uBAAuB;IACtC,sBAAsB,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAEpD,aAAa,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;IAEvC,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5E,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,qBAAqB,IAAI,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC7C,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC/D,oBAAoB,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACtD,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7E;;OAEG;IACH,qBAAqB,IAAI,MAAM,EAAE,CAAC;CACnC;AAED;;GAEG;AACH,qBAAa,2BAA4B,YAAW,uBAAuB;IAevE,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK;IAfxB,OAAO,CAAC,mBAAmB,CAAoC;IAC/D;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAA0C;IACjF;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAqB;IAEjE,SAAgB,sBAAsB,8BAAqC;gBAGxD,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,IAAI;IAG9B,aAAa,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE;IAIzB,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjF,kBAAkB,CAAC,QAAQ,EAAE,MAAM;IAgBnC,oBAAoB,CAAC,KAAK,EAAE,kBAAkB;IAW9C,qBAAqB,IAAI,SAAS,CAAC,QAAQ,CAAC;IAK5C,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC;IAY9D,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM;IAIrE,qBAAqB,IAAI,MAAM,EAAE;IAOxC,OAAO,CAAC,kBAAkB;YAyBZ,cAAc;IAyB5B,OAAO,CAAC,oCAAoC;IAS5C,OAAO,CAAC,cAAc;YAOR,2BAA2B;CA2B1C;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,EAAE;QACf,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAAC;KAChC,CAAC;CACH"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=automerge-doc-loader.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"automerge-doc-loader.test.d.ts","sourceRoot":"","sources":["../../../../src/automerge/automerge-doc-loader.test.ts"],"names":[],"mappings":""}
@@ -1,7 +1,7 @@
1
1
  import { Repo, type DocumentId } from '@dxos/automerge/automerge-repo';
2
2
  import { type Stream } from '@dxos/codec-protobuf';
3
3
  import { PublicKey } from '@dxos/keys';
4
- import { type HostInfo, type SyncRepoRequest, type SyncRepoResponse } from '@dxos/protocols/proto/dxos/echo/service';
4
+ import { type FlushRequest, type HostInfo, type SyncRepoRequest, type SyncRepoResponse } from '@dxos/protocols/proto/dxos/echo/service';
5
5
  import { type Directory } from '@dxos/random-access-storage';
6
6
  import { type AutomergeReplicator } from '@dxos/teleport-extension-automerge-replicator';
7
7
  export type { DocumentId };
@@ -34,6 +34,7 @@ export declare class AutomergeHost {
34
34
  private _automergeDocs;
35
35
  private _automergePeers;
36
36
  close(): Promise<void>;
37
+ flush({ documentIds }: FlushRequest): Promise<void>;
37
38
  syncRepo(request: SyncRepoRequest): Stream<SyncRepoResponse>;
38
39
  sendSyncMessage(request: SyncRepoRequest): Promise<void>;
39
40
  getHostInfo(): Promise<HostInfo>;
@@ -1 +1 @@
1
- {"version":3,"file":"automerge-host.d.ts","sourceRoot":"","sources":["../../../../src/automerge/automerge-host.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,IAAI,EAEJ,KAAK,UAAU,EAIhB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AACrH,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AASzF,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B,CAAC;AAEF,qBACa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0B;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;IAGnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoE;IAEvG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoC;IACtE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAkB;IAEtC,cAAc,cAAqB;gBAE9B,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,mBAAmB;IAkFxD,IAAI,IAAI,IAAI,IAAI,CAEf;YAEa,WAAW;IAOzB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,eAAe;IAIjB,KAAK;IAUX,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAI5D,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;IAQtC,eAAe,IAAI,mBAAmB;IAItC,eAAe,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;CAI1D;AAoBD,eAAO,MAAM,kBAAkB,QAAS,GAAG,KAAG,MAAM,GAAG,IAQtD,CAAC"}
1
+ {"version":3,"file":"automerge-host.d.ts","sourceRoot":"","sources":["../../../../src/automerge/automerge-host.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,IAAI,EAEJ,KAAK,UAAU,EAIhB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,+CAA+C,CAAC;AASzF,YAAY,EAAE,UAAU,EAAE,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B,CAAC;AAEF,qBACa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA0B;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA0B;IAGnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC;;OAEG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoE;IAEvG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoC;IACtE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAkB;IAEtC,cAAc,cAAqB;gBAE9B,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,mBAAmB;IAmFxD,IAAI,IAAI,IAAI,IAAI,CAEf;YAEa,WAAW;IAOzB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,SAAS;IA8BjB,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,eAAe;IAIjB,KAAK;IAUL,KAAK,CAAC,EAAE,WAAW,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzD,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC;IAI5D,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;IAQtC,eAAe,IAAI,mBAAmB;IAItC,eAAe,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS;CAI1D;AAoBD,eAAO,MAAM,kBAAkB,QAAS,GAAG,KAAG,MAAM,GAAG,IAQtD,CAAC"}
@@ -1,5 +1,8 @@
1
1
  export * from './automerge-host';
2
2
  export * from './automerge-storage-adapter';
3
+ export * from './automerge-doc-loader';
3
4
  export * from './local-host-network-adapter';
4
5
  export * from './mesh-network-adapter';
6
+ export * from './types';
7
+ export * from './reference';
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/automerge/index.ts"],"names":[],"mappings":"AAIA,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/automerge/index.ts"],"names":[],"mappings":"AAIA,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,wBAAwB,CAAC;AACvC,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Reference } from '@dxos/echo-db';
2
+ export declare const REFERENCE_TYPE_TAG = "dxos.echo.model.document.Reference";
3
+ /**
4
+ * Reference as it is stored in Automerge document.
5
+ */
6
+ export type EncodedReferenceObject = {
7
+ '@type': typeof REFERENCE_TYPE_TAG;
8
+ itemId: string | null;
9
+ protocol: string | null;
10
+ host: string | null;
11
+ };
12
+ export declare const encodeReference: (reference: Reference) => EncodedReferenceObject;
13
+ export declare const decodeReference: (value: any) => Reference;
14
+ export declare const isEncodedReferenceObject: (value: any) => value is EncodedReferenceObject;
15
+ //# sourceMappingURL=reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../../../../src/automerge/reference.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,eAAO,MAAM,kBAAkB,uCAAuC,CAAC;AAEvE;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,OAAO,EAAE,OAAO,kBAAkB,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,eAAe,cAAe,SAAS,KAAG,sBAMrD,CAAC;AAEH,eAAO,MAAM,eAAe,UAAW,GAAG,cACyC,CAAC;AAEpF,eAAO,MAAM,wBAAwB,UAAW,GAAG,oCACmC,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { type EncodedReferenceObject } from './reference';
2
+ export type SpaceState = {
3
+ rootUrl?: string;
4
+ };
5
+ export interface SpaceDoc {
6
+ access?: {
7
+ spaceKey: string;
8
+ };
9
+ /**
10
+ * Objects inlined in the current document.
11
+ */
12
+ objects?: {
13
+ [key: string]: ObjectStructure;
14
+ };
15
+ /**
16
+ * Object id points to an automerge doc url where the object is embedded.
17
+ */
18
+ links?: {
19
+ [echoId: string]: string;
20
+ };
21
+ }
22
+ /**
23
+ * Representation of an ECHO object in an AM document.
24
+ */
25
+ export type ObjectStructure = {
26
+ data: Record<string, any>;
27
+ meta: ObjectMeta;
28
+ system: ObjectSystem;
29
+ };
30
+ /**
31
+ * Echo object metadata.
32
+ */
33
+ export type ObjectMeta = {
34
+ /**
35
+ * Foreign keys.
36
+ */
37
+ keys: ForeignKey[];
38
+ };
39
+ /**
40
+ * Reference to an object in a foreign database.
41
+ */
42
+ export type ForeignKey = {
43
+ /**
44
+ * Name of the foreign database/system.
45
+ * E.g. `github.com`.
46
+ */
47
+ source?: string;
48
+ /**
49
+ * Id within the foreign database.
50
+ */
51
+ id?: string;
52
+ };
53
+ /**
54
+ * Automerge object system properties.
55
+ * (Is automerge specific.)
56
+ */
57
+ export type ObjectSystem = {
58
+ /**
59
+ * Deletion marker.
60
+ */
61
+ deleted?: boolean;
62
+ /**
63
+ * Object reference ('protobuf' protocol) type.
64
+ */
65
+ type?: EncodedReferenceObject;
66
+ };
67
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/automerge/types.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,UAAU,GAAG;IAEvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF;;OAEG;IACH,OAAO,CAAC,EAAE;QACR,CAAC,GAAG,EAAE,MAAM,GAAG,eAAe,CAAC;KAChC,CAAC;IACF;;OAEG;IACH,KAAK,CAAC,EAAE;QACN,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACtB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;OAEG;IACH,IAAI,EAAE,UAAU,EAAE,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,IAAI,CAAC,EAAE,sBAAsB,CAAC;CAC/B,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { Event } from '@dxos/async';
2
- import { type Context } from '@dxos/context';
2
+ import { Resource, type Context } from '@dxos/context';
3
3
  import { type FeedInfo } from '@dxos/credentials';
4
4
  import { type FeedOptions, type FeedWrapper } from '@dxos/feed-store';
5
5
  import { type PublicKey } from '@dxos/keys';
@@ -28,7 +28,7 @@ export type CreatePipelineParams = {
28
28
  /**
29
29
  * Spaces are globally addressable databases with access control.
30
30
  */
31
- export declare class Space {
31
+ export declare class Space extends Resource {
32
32
  private readonly _addFeedMutex;
33
33
  readonly onCredentialProcessed: Callback<AsyncCallback<Credential>>;
34
34
  readonly stateUpdate: Event<void>;
@@ -38,7 +38,6 @@ export declare class Space {
38
38
  private readonly _feedProvider;
39
39
  private readonly _controlPipeline;
40
40
  private readonly _snapshotManager;
41
- private _isOpen;
42
41
  private _controlFeed?;
43
42
  private _dataFeed?;
44
43
  constructor(params: SpaceParams);
@@ -59,11 +58,8 @@ export declare class Space {
59
58
  * Use for diagnostics.
60
59
  */
61
60
  getControlFeeds(): FeedInfo[];
62
- /**
63
- * Use for diagnostics.
64
- */
65
- open(ctx: Context): Promise<void>;
66
- close(): Promise<void>;
61
+ protected _open(ctx: Context): Promise<void>;
62
+ protected _close(): Promise<void>;
67
63
  }
68
64
  export {};
69
65
  //# sourceMappingURL=space.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"space.d.ts","sourceRoot":"","sources":["../../../../src/space/space.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAmC,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,6CAA6C,CAAC;AAC5F,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,KAAK,YAAY,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;AAElG,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC;IAGrB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,SAAS,CAAC;CAElB,CAAC;AAEF;;GAEG;AAEH,qBAEa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C,SAAgB,qBAAqB,sCAA6C;IAClF,SAAgB,WAAW,cAAe;IAC1C,SACgB,QAAQ,EAAE,aAAa,CAAC;IAExC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAY;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IAEnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IAEnD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAA2B;IAChD,OAAO,CAAC,SAAS,CAAC,CAA2B;gBAEjC,MAAM,EAAE,WAAW;IAqC/B,IAEI,GAAG,cAEN;IAED,IAAI,MAAM,YAET;IAED,IAAI,cAAc,IAAI,SAAS,CAE9B;IAED,IAAI,cAAc,0BAEjB;IAED,IAAI,WAAW,0BAEd;IAED,IAAI,UAAU,2CAEb;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,gBAAgB,CAEtC;IAED,IAAI,eAAe,IAAI,eAAe,CAErC;IAEK,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC;IAO7C,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC;IAMhD;;OAEG;IACH,eAAe,IAAI,QAAQ,EAAE;IAI7B;;OAEG;IAMG,IAAI,CAAC,GAAG,EAAE,OAAO;IAejB,KAAK;CAaZ"}
1
+ {"version":3,"file":"space.d.ts","sourceRoot":"","sources":["../../../../src/space/space.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAmC,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAkB,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEtE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sCAAsC,CAAC;AACxE,OAAO,EAAgB,KAAK,UAAU,EAAE,MAAM,6CAA6C,CAAC;AAC5F,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,KAAK,YAAY,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;AAElG,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IACtC,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,EAAE,SAAS,CAAC;IAGrB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,SAAS,CAAC;CAElB,CAAC;AAEF;;GAEG;AAEH,qBAEa,KAAM,SAAQ,QAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C,SAAgB,qBAAqB,sCAA6C;IAClF,SAAgB,WAAW,cAAe;IAC1C,SACgB,QAAQ,EAAE,aAAa,CAAC;IAExC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAY;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAe;IAE7C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IAEnD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAkB;IAEnD,OAAO,CAAC,YAAY,CAAC,CAA2B;IAChD,OAAO,CAAC,SAAS,CAAC,CAA2B;gBAEjC,MAAM,EAAE,WAAW;IAsC/B,IAEI,GAAG,cAEN;IAED,IAAI,MAAM,YAET;IAED,IAAI,cAAc,IAAI,SAAS,CAE9B;IAED,IAAI,cAAc,0BAEjB;IAED,IAAI,WAAW,0BAEd;IAED,IAAI,UAAU,2CAEb;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,gBAAgB,CAEtC;IAED,IAAI,eAAe,IAAI,eAAe,CAErC;IAEK,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC;IAO7C,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,WAAW,CAAC;IAMhD;;OAEG;IACH,eAAe,IAAI,QAAQ,EAAE;cAKJ,KAAK,CAAC,GAAG,EAAE,OAAO;cAWlB,MAAM;CAShC"}
@@ -26,7 +26,7 @@ export declare class TestAgentBuilder {
26
26
  private readonly _storage;
27
27
  private readonly _networkManagerProvider;
28
28
  constructor({ storage, networkManagerProvider }?: TestAgentBuilderOptions);
29
- close(): Promise<void[][]>;
29
+ close(): Promise<Space[][]>;
30
30
  get agents(): TestAgent[];
31
31
  getAgent(deviceKey: PublicKey): TestAgent | undefined;
32
32
  createPeer(): Promise<TestAgent>;
@@ -50,7 +50,7 @@ export declare class TestAgent {
50
50
  private _blobStore?;
51
51
  get blobStore(): BlobStore;
52
52
  constructor(_networkManagerProvider: NetworkManagerProvider, _feedBuilder: TestFeedBuilder, identityKey: PublicKey, deviceKey: PublicKey);
53
- close(): Promise<void[]>;
53
+ close(): Promise<Space[]>;
54
54
  get spaces(): Space[];
55
55
  getSpace(spaceKey: PublicKey): Space | undefined;
56
56
  private _spaceManager?;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/echo-pipeline",
3
- "version": "0.4.9",
3
+ "version": "0.4.10-main.06ef97a",
4
4
  "description": "ECHO database.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -36,35 +36,35 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "crc-32": "^1.2.2",
39
- "@dxos/automerge": "0.4.9",
40
- "@dxos/codec-protobuf": "0.4.9",
41
- "@dxos/async": "0.4.9",
42
- "@dxos/context": "0.4.9",
43
- "@dxos/credentials": "0.4.9",
44
- "@dxos/debug": "0.4.9",
45
- "@dxos/crypto": "0.4.9",
46
- "@dxos/echo-db": "0.4.9",
47
- "@dxos/feed-store": "0.4.9",
48
- "@dxos/hypercore": "0.4.9",
49
- "@dxos/keyring": "0.4.9",
50
- "@dxos/invariant": "0.4.9",
51
- "@dxos/messaging": "0.4.9",
52
- "@dxos/log": "0.4.9",
53
- "@dxos/keys": "0.4.9",
54
- "@dxos/network-manager": "0.4.9",
55
- "@dxos/node-std": "0.4.9",
56
- "@dxos/protocols": "0.4.9",
57
- "@dxos/rpc": "0.4.9",
58
- "@dxos/random-access-storage": "0.4.9",
59
- "@dxos/teleport": "0.4.9",
60
- "@dxos/teleport-extension-automerge-replicator": "0.4.9",
61
- "@dxos/teleport-extension-gossip": "0.4.9",
62
- "@dxos/teleport-extension-object-sync": "0.4.9",
63
- "@dxos/timeframe": "0.4.9",
64
- "@dxos/teleport-extension-replicator": "0.4.9",
65
- "@dxos/tracing": "0.4.9",
66
- "@dxos/typings": "0.4.9",
67
- "@dxos/util": "0.4.9"
39
+ "@dxos/async": "0.4.10-main.06ef97a",
40
+ "@dxos/codec-protobuf": "0.4.10-main.06ef97a",
41
+ "@dxos/automerge": "0.4.10-main.06ef97a",
42
+ "@dxos/context": "0.4.10-main.06ef97a",
43
+ "@dxos/credentials": "0.4.10-main.06ef97a",
44
+ "@dxos/crypto": "0.4.10-main.06ef97a",
45
+ "@dxos/echo-db": "0.4.10-main.06ef97a",
46
+ "@dxos/debug": "0.4.10-main.06ef97a",
47
+ "@dxos/feed-store": "0.4.10-main.06ef97a",
48
+ "@dxos/invariant": "0.4.10-main.06ef97a",
49
+ "@dxos/hypercore": "0.4.10-main.06ef97a",
50
+ "@dxos/keyring": "0.4.10-main.06ef97a",
51
+ "@dxos/keys": "0.4.10-main.06ef97a",
52
+ "@dxos/messaging": "0.4.10-main.06ef97a",
53
+ "@dxos/network-manager": "0.4.10-main.06ef97a",
54
+ "@dxos/log": "0.4.10-main.06ef97a",
55
+ "@dxos/node-std": "0.4.10-main.06ef97a",
56
+ "@dxos/random-access-storage": "0.4.10-main.06ef97a",
57
+ "@dxos/rpc": "0.4.10-main.06ef97a",
58
+ "@dxos/protocols": "0.4.10-main.06ef97a",
59
+ "@dxos/teleport": "0.4.10-main.06ef97a",
60
+ "@dxos/teleport-extension-gossip": "0.4.10-main.06ef97a",
61
+ "@dxos/teleport-extension-automerge-replicator": "0.4.10-main.06ef97a",
62
+ "@dxos/teleport-extension-object-sync": "0.4.10-main.06ef97a",
63
+ "@dxos/teleport-extension-replicator": "0.4.10-main.06ef97a",
64
+ "@dxos/tracing": "0.4.10-main.06ef97a",
65
+ "@dxos/util": "0.4.10-main.06ef97a",
66
+ "@dxos/timeframe": "0.4.10-main.06ef97a",
67
+ "@dxos/typings": "0.4.10-main.06ef97a"
68
68
  },
69
69
  "devDependencies": {
70
70
  "fast-check": "^3.15.1",
@@ -0,0 +1,97 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { expect } from 'chai';
6
+
7
+ import { sleep } from '@dxos/async';
8
+ import { Repo } from '@dxos/automerge/automerge-repo';
9
+ import { Context } from '@dxos/context';
10
+ import { PublicKey } from '@dxos/keys';
11
+ import { describe, test } from '@dxos/test';
12
+
13
+ import {
14
+ type AutomergeDocumentLoader,
15
+ AutomergeDocumentLoaderImpl,
16
+ type ObjectDocumentLoaded,
17
+ } from './automerge-doc-loader';
18
+ import { type SpaceDoc } from './types';
19
+
20
+ const ctx = new Context();
21
+ const SPACE_KEY = PublicKey.random();
22
+ const randomId = () => PublicKey.random().toHex();
23
+ describe('AutomergeDocumentLoader', () => {
24
+ test('space access is set on root doc handle and it is accessible', async () => {
25
+ const { loader, spaceRootDocHandle } = await setupTest();
26
+ expect(loader.getSpaceRootDocHandle()).not.to.throw;
27
+ expect(spaceRootDocHandle.docSync()?.access?.spaceKey).to.eq(SPACE_KEY.toHex());
28
+ });
29
+
30
+ test('new object document is linked with space and root document', async () => {
31
+ const objectId = randomId();
32
+ const { loader, spaceRootDocHandle } = await setupTest();
33
+ const objectDocHandle = loader.createDocumentForObject(objectId);
34
+ const handle = spaceRootDocHandle.docSync();
35
+ expect(objectDocHandle.docSync()?.access?.spaceKey).to.eq(SPACE_KEY.toHex());
36
+ expect(handle?.links[objectId]).to.eq(objectDocHandle.url);
37
+ });
38
+
39
+ test('listener is invoked after a document is loaded', async () => {
40
+ const objectId = randomId();
41
+ const { loader, repo } = await setupTest();
42
+ const handle = repo.create<SpaceDoc>();
43
+ const docLoadInfo = waitForDocumentLoad(loader, { objectId, handle });
44
+ loadLinkedObjects(loader, { [objectId]: handle.url });
45
+ await sleep(10);
46
+ expect(docLoadInfo.loaded).to.be.true;
47
+ });
48
+
49
+ test('listener is not invoked if an object was rebound during document loading', async () => {
50
+ const objectId = randomId();
51
+ const { loader, repo } = await setupTest();
52
+ const oldDocHandle = repo.create<SpaceDoc>();
53
+ const newDocHandle = repo.create<SpaceDoc>();
54
+ const docLoadInfo = waitForDocumentLoad(loader, { objectId, handle: oldDocHandle });
55
+ loadLinkedObjects(loader, { [objectId]: oldDocHandle.url });
56
+ loader.onObjectBoundToDocument(newDocHandle, objectId);
57
+ await sleep(10);
58
+ expect(docLoadInfo.loaded).to.be.false;
59
+ });
60
+
61
+ test('document link is not loaded if object exists as inline object', async () => {
62
+ const objectId = randomId();
63
+ const { loader, repo } = await setupTest();
64
+ const existingHandle = repo.create<SpaceDoc>();
65
+ loader.onObjectBoundToDocument(existingHandle, objectId);
66
+ const newDocHandle = repo.create<SpaceDoc>();
67
+ const docLoadInfo = waitForDocumentLoad(loader, { objectId, handle: newDocHandle });
68
+ loadLinkedObjects(loader, { [objectId]: existingHandle.url });
69
+ await sleep(10);
70
+ expect(docLoadInfo.loaded).to.be.false;
71
+ });
72
+
73
+ const setupTest = async () => {
74
+ const repo = new Repo({ network: [] });
75
+ const loader = new AutomergeDocumentLoaderImpl(SPACE_KEY, repo);
76
+ const spaceRootDocHandle = repo.create<SpaceDoc>();
77
+ await loader.loadSpaceRootDocHandle(ctx, {
78
+ rootUrl: spaceRootDocHandle.url,
79
+ });
80
+ return { loader, spaceRootDocHandle, repo };
81
+ };
82
+
83
+ const loadLinkedObjects = (loader: AutomergeDocumentLoader, links: SpaceDoc['links']) => {
84
+ Object.keys(links ?? {}).forEach((objectId) => loader.loadObjectDocument(objectId));
85
+ loader.onObjectLinksUpdated(links);
86
+ };
87
+
88
+ const waitForDocumentLoad = (loader: AutomergeDocumentLoader, expected: ObjectDocumentLoaded) => {
89
+ const docLoadInfo = { loaded: false };
90
+ loader.onObjectDocumentLoaded.on((data) => {
91
+ expect(data.objectId).to.eq(expected.objectId);
92
+ expect(data.handle.url).to.eq(expected.handle.url);
93
+ docLoadInfo.loaded = true;
94
+ });
95
+ return docLoadInfo;
96
+ };
97
+ });
@@ -0,0 +1,241 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Event } from '@dxos/async';
6
+ import { type DocHandle, type AutomergeUrl, type DocumentId, type Repo } from '@dxos/automerge/automerge-repo';
7
+ import { cancelWithContext, type Context } from '@dxos/context';
8
+ import { warnAfterTimeout } from '@dxos/debug';
9
+ import { invariant } from '@dxos/invariant';
10
+ import { type PublicKey } from '@dxos/keys';
11
+ import { log } from '@dxos/log';
12
+
13
+ import { type SpaceState, type SpaceDoc } from './types';
14
+
15
+ type SpaceDocumentLinks = SpaceDoc['links'];
16
+
17
+ export interface AutomergeDocumentLoader {
18
+ onObjectDocumentLoaded: Event<ObjectDocumentLoaded>;
19
+
20
+ getAllHandles(): DocHandle<SpaceDoc>[];
21
+
22
+ loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void>;
23
+ loadObjectDocument(objectId: string): void;
24
+ getSpaceRootDocHandle(): DocHandle<SpaceDoc>;
25
+ createDocumentForObject(objectId: string): DocHandle<SpaceDoc>;
26
+ onObjectLinksUpdated(links: SpaceDocumentLinks): void;
27
+ onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string): void;
28
+
29
+ /**
30
+ * @returns objectIds for which we had document handles or were loading one.
31
+ */
32
+ clearHandleReferences(): string[];
33
+ }
34
+
35
+ /**
36
+ * Manages object <-> docHandle binding and automerge document loading.
37
+ */
38
+ export class AutomergeDocumentLoaderImpl implements AutomergeDocumentLoader {
39
+ private _spaceRootDocHandle: DocHandle<SpaceDoc> | null = null;
40
+ /**
41
+ * An object id pointer to a handle of the document where the object is stored inline.
42
+ */
43
+ private readonly _objectDocumentHandles = new Map<string, DocHandle<SpaceDoc>>();
44
+ /**
45
+ * If object was requested via loadObjectDocument but root document links weren't updated yet
46
+ * loading will be triggered in onObjectLinksUpdated callback.
47
+ */
48
+ private readonly _objectsPendingDocumentLoad = new Set<string>();
49
+
50
+ public readonly onObjectDocumentLoaded = new Event<ObjectDocumentLoaded>();
51
+
52
+ constructor(
53
+ private readonly _spaceKey: PublicKey,
54
+ private readonly _repo: Repo,
55
+ ) {}
56
+
57
+ getAllHandles(): DocHandle<SpaceDoc>[] {
58
+ return [...new Set(this._objectDocumentHandles.values())];
59
+ }
60
+
61
+ public async loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void> {
62
+ if (this._spaceRootDocHandle != null) {
63
+ return;
64
+ }
65
+ if (!spaceState.rootUrl) {
66
+ log.error('Database opened with no rootUrl', { spaceKey: this._spaceKey });
67
+ this._createContextBoundSpaceRootDocument(ctx);
68
+ } else {
69
+ const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);
70
+ const doc = existingDocHandle.docSync();
71
+ invariant(doc);
72
+ if (doc.access == null) {
73
+ this._initDocAccess(existingDocHandle);
74
+ }
75
+ this._spaceRootDocHandle = existingDocHandle;
76
+ }
77
+ }
78
+
79
+ public loadObjectDocument(objectId: string) {
80
+ invariant(this._spaceRootDocHandle);
81
+ if (this._objectDocumentHandles.has(objectId) || this._objectsPendingDocumentLoad.has(objectId)) {
82
+ return;
83
+ }
84
+ const spaceRootDoc = this._spaceRootDocHandle.docSync();
85
+ invariant(spaceRootDoc);
86
+ const documentUrl = (spaceRootDoc.links ?? {})[objectId];
87
+ if (documentUrl == null) {
88
+ this._objectsPendingDocumentLoad.add(objectId);
89
+ log.info('loading delayed until object links are initialized', { objectId });
90
+ return;
91
+ }
92
+ this._loadLinkedObjects({ [objectId]: documentUrl });
93
+ }
94
+
95
+ public onObjectLinksUpdated(links: SpaceDocumentLinks) {
96
+ if (!links) {
97
+ return;
98
+ }
99
+ const linksAwaitingLoad = Object.entries(links).filter(([objectId]) =>
100
+ this._objectsPendingDocumentLoad.has(objectId),
101
+ );
102
+ this._loadLinkedObjects(Object.fromEntries(linksAwaitingLoad));
103
+ linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));
104
+ }
105
+
106
+ public getSpaceRootDocHandle(): DocHandle<SpaceDoc> {
107
+ invariant(this._spaceRootDocHandle);
108
+ return this._spaceRootDocHandle;
109
+ }
110
+
111
+ public createDocumentForObject(objectId: string): DocHandle<SpaceDoc> {
112
+ invariant(this._spaceRootDocHandle);
113
+ const spaceDocHandle = this._repo.create<SpaceDoc>();
114
+ this._initDocAccess(spaceDocHandle);
115
+ this.onObjectBoundToDocument(spaceDocHandle, objectId);
116
+ this._spaceRootDocHandle.change((newDoc: SpaceDoc) => {
117
+ newDoc.links ??= {};
118
+ newDoc.links[objectId] = spaceDocHandle.url;
119
+ });
120
+ return spaceDocHandle;
121
+ }
122
+
123
+ public onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string) {
124
+ this._objectDocumentHandles.set(objectId, handle);
125
+ }
126
+
127
+ public clearHandleReferences(): string[] {
128
+ const objectsWithHandles = [...this._objectDocumentHandles.keys()];
129
+ this._objectDocumentHandles.clear();
130
+ this._spaceRootDocHandle = null;
131
+ return objectsWithHandles;
132
+ }
133
+
134
+ private _loadLinkedObjects(links: SpaceDocumentLinks) {
135
+ if (!links) {
136
+ return;
137
+ }
138
+ for (const [objectId, automergeUrl] of Object.entries(links)) {
139
+ const logMeta = { objectId, automergeUrl };
140
+ const objectDocumentHandle = this._objectDocumentHandles.get(objectId);
141
+ if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {
142
+ log.warn('object already inlined in a different document, ignoring the link', {
143
+ ...logMeta,
144
+ actualDocumentUrl: objectDocumentHandle.url,
145
+ });
146
+ continue;
147
+ }
148
+ if (objectDocumentHandle?.url === automergeUrl) {
149
+ log.warn('object document was already loaded', logMeta);
150
+ continue;
151
+ }
152
+ const handle = this._repo.find<SpaceDoc>(automergeUrl as DocumentId);
153
+ log.debug('document loading triggered', logMeta);
154
+ this._objectDocumentHandles.set(objectId, handle);
155
+ void this._createObjectOnDocumentLoad(handle, objectId);
156
+ }
157
+ }
158
+
159
+ private async _initDocHandle(ctx: Context, url: string) {
160
+ const docHandle = this._repo.find<SpaceDoc>(url as DocumentId);
161
+ while (true) {
162
+ try {
163
+ await warnAfterTimeout(5_000, 'Automerge root doc load timeout (AutomergeDb)', async () => {
164
+ await cancelWithContext(ctx, docHandle.whenReady()); // TODO(dmaretskyi): Temporary 5s timeout for debugging.
165
+ });
166
+ break;
167
+ } catch (err) {
168
+ if (`${err}`.includes('Timeout')) {
169
+ log.info('wraparound', { id: docHandle.documentId, state: docHandle.state });
170
+ continue;
171
+ }
172
+
173
+ throw err;
174
+ }
175
+ }
176
+
177
+ if (docHandle.state === 'unavailable') {
178
+ throw new Error('Automerge document is unavailable');
179
+ }
180
+
181
+ return docHandle;
182
+ }
183
+
184
+ private _createContextBoundSpaceRootDocument(ctx: Context) {
185
+ const docHandle = this._repo.create<SpaceDoc>();
186
+ this._spaceRootDocHandle = docHandle;
187
+ ctx.onDispose(() => {
188
+ docHandle.delete();
189
+ this._spaceRootDocHandle = null;
190
+ });
191
+ }
192
+
193
+ private _initDocAccess(handle: DocHandle<SpaceDoc>) {
194
+ handle.change((newDoc: SpaceDoc) => {
195
+ newDoc.access ??= { spaceKey: this._spaceKey.toHex() };
196
+ newDoc.access.spaceKey = this._spaceKey.toHex();
197
+ });
198
+ }
199
+
200
+ private async _createObjectOnDocumentLoad(handle: DocHandle<SpaceDoc>, objectId: string) {
201
+ try {
202
+ await handle.doc(['ready']);
203
+ const logMeta = { objectId, docUrl: handle.url };
204
+ if (this.onObjectDocumentLoaded.listenerCount() === 0) {
205
+ log.info('document loaded after all listeners were removed', logMeta);
206
+ return;
207
+ }
208
+ const objectDocHandle = this._objectDocumentHandles.get(objectId);
209
+ if (objectDocHandle?.url !== handle.url) {
210
+ log.warn('object was rebound while a document was loading, discarding handle', logMeta);
211
+ return;
212
+ }
213
+ this.onObjectDocumentLoaded.emit({ handle, objectId });
214
+ } catch (err) {
215
+ const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;
216
+ log.warn('failed to load a document', {
217
+ objectId,
218
+ automergeUrl: handle.url,
219
+ retryLoading: shouldRetryLoading,
220
+ err,
221
+ });
222
+ if (shouldRetryLoading) {
223
+ await this._createObjectOnDocumentLoad(handle, objectId);
224
+ }
225
+ }
226
+ }
227
+ }
228
+
229
+ export interface ObjectDocumentLoaded {
230
+ handle: DocHandle<SpaceDoc>;
231
+ objectId: string;
232
+ }
233
+
234
+ export interface DocumentChanges {
235
+ createdObjectIds: string[];
236
+ updatedObjectIds: string[];
237
+ objectsToRebind: string[];
238
+ linkedDocuments: {
239
+ [echoId: string]: AutomergeUrl;
240
+ };
241
+ }