@dxos/client-services 0.6.5 → 0.6.6-main.e1a6e1f

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 (52) hide show
  1. package/dist/lib/browser/{chunk-GIAH3RXX.mjs → chunk-DR3GOD3O.mjs} +907 -442
  2. package/dist/lib/browser/chunk-DR3GOD3O.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +28 -13
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +21 -4
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-NDXK2NIM.cjs → chunk-DRNEKKQP.cjs} +1065 -607
  9. package/dist/lib/node/chunk-DRNEKKQP.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +77 -62
  11. package/dist/lib/node/index.cjs.map +3 -3
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +27 -8
  14. package/dist/lib/node/testing/index.cjs.map +3 -3
  15. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  16. package/dist/types/src/packlets/services/service-context.d.ts +6 -1
  17. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  18. package/dist/types/src/packlets/services/service-host.d.ts +1 -0
  19. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  20. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +29 -12
  21. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  22. package/dist/types/src/packlets/spaces/data-space.d.ts +7 -0
  23. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  24. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +35 -0
  25. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -0
  26. package/dist/types/src/packlets/spaces/index.d.ts +1 -0
  27. package/dist/types/src/packlets/spaces/index.d.ts.map +1 -1
  28. package/dist/types/src/packlets/testing/invitation-utils.d.ts +2 -0
  29. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  30. package/dist/types/src/packlets/testing/test-builder.d.ts +3 -1
  31. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  32. package/dist/types/src/packlets/worker/worker-runtime.d.ts +8 -3
  33. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  34. package/dist/types/src/version.d.ts +1 -1
  35. package/dist/types/src/version.d.ts.map +1 -1
  36. package/package.json +38 -36
  37. package/src/packlets/invitations/invitations-handler.test.ts +1 -0
  38. package/src/packlets/invitations/invitations-handler.ts +12 -0
  39. package/src/packlets/invitations/space-invitation-protocol.test.ts +23 -1
  40. package/src/packlets/services/service-context.ts +44 -12
  41. package/src/packlets/services/service-host.ts +26 -4
  42. package/src/packlets/spaces/data-space-manager.test.ts +6 -0
  43. package/src/packlets/spaces/data-space-manager.ts +80 -36
  44. package/src/packlets/spaces/data-space.ts +36 -2
  45. package/src/packlets/spaces/edge-feed-replicator.ts +249 -0
  46. package/src/packlets/spaces/index.ts +1 -0
  47. package/src/packlets/testing/invitation-utils.ts +2 -2
  48. package/src/packlets/testing/test-builder.ts +20 -12
  49. package/src/packlets/worker/worker-runtime.ts +32 -10
  50. package/src/version.ts +1 -5
  51. package/dist/lib/browser/chunk-GIAH3RXX.mjs.map +0 -7
  52. package/dist/lib/node/chunk-NDXK2NIM.cjs.map +0 -7
@@ -7,10 +7,12 @@ export type CreateSessionParams = {
7
7
  systemPort: RpcPort;
8
8
  shellPort?: RpcPort;
9
9
  };
10
- export type WorkerRuntimeCallbacks = {
10
+ export type WorkerRuntimeOptions = {
11
+ channel?: string;
12
+ configProvider: () => MaybePromise<Config>;
11
13
  acquireLock: () => Promise<void>;
12
14
  releaseLock: () => void;
13
- onReset: () => Promise<void>;
15
+ onStop?: () => Promise<void>;
14
16
  };
15
17
  /**
16
18
  * Runtime for the shared worker.
@@ -21,15 +23,18 @@ export declare class WorkerRuntime {
21
23
  private readonly _configProvider;
22
24
  private readonly _acquireLock;
23
25
  private readonly _releaseLock;
26
+ private readonly _onStop?;
24
27
  private readonly _transportFactory;
25
28
  private readonly _ready;
26
29
  private readonly _sessions;
27
30
  private readonly _clientServices;
31
+ private readonly _channel;
32
+ private _broadcastChannel?;
28
33
  private _sessionForNetworking?;
29
34
  private _config;
30
35
  private _signalMetadataTags;
31
36
  private _signalTelemetryEnabled;
32
- constructor(_configProvider: () => MaybePromise<Config>, { acquireLock, releaseLock, onReset }: WorkerRuntimeCallbacks);
37
+ constructor({ channel, configProvider, acquireLock, releaseLock, onStop, }: WorkerRuntimeOptions);
33
38
  get host(): ClientServicesHost;
34
39
  start(): Promise<void>;
35
40
  stop(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"worker-runtime.d.ts","sourceRoot":"","sources":["../../../../../src/packlets/worker/worker-runtime.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,qBAAa,aAAa;IAatB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAZlC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAyC;IAC3E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;IACtD,OAAO,CAAC,qBAAqB,CAAC,CAAgB;IAC9C,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,uBAAuB,CAAkB;gBAG9B,eAAe,EAAE,MAAM,YAAY,CAAC,MAAM,CAAC,EAC5D,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,sBAAsB;IAW/D,IAAI,IAAI,uBAEP;IAEK,KAAK;IA8BL,IAAI;IAMV;;OAEG;IACG,aAAa,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,mBAAmB;IAsC3E;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAoBzB"}
1
+ {"version":3,"file":"worker-runtime.d.ts","sourceRoot":"","sources":["../../../../../src/packlets/worker/worker-runtime.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAW3C,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3C,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAEF;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA6B;IAC7D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAsB;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAa;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAyC;IAC3E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoC;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAsB;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,iBAAiB,CAAC,CAAmB;IAC7C,OAAO,CAAC,qBAAqB,CAAC,CAAgB;IAC9C,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,uBAAuB,CAAkB;gBAErC,EACV,OAA0C,EAC1C,cAAc,EACd,WAAW,EACX,WAAW,EACX,MAAM,GACP,EAAE,oBAAoB;IAavB,IAAI,IAAI,uBAEP;IAEK,KAAK;IAsCL,IAAI;IASV;;OAEG;IACG,aAAa,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,EAAE,mBAAmB;IAoC3E;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAoBzB"}
@@ -1,2 +1,2 @@
1
- export declare const DXOS_VERSION = "0.6.5";
1
+ export declare const DXOS_VERSION = "0.6.6-main.e1a6e1f";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/version.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY,UAAU,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,uBAAuB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/client-services",
3
- "version": "0.6.5",
3
+ "version": "0.6.6-main.e1a6e1f",
4
4
  "description": "DXOS client services implementation",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -43,46 +43,48 @@
43
43
  "src"
44
44
  ],
45
45
  "dependencies": {
46
+ "cbor-x": "^1.5.4",
46
47
  "platform": "^1.3.6",
47
- "@dxos/client-protocol": "0.6.5",
48
- "@dxos/codec-protobuf": "0.6.5",
49
- "@dxos/config": "0.6.5",
50
- "@dxos/context": "0.6.5",
51
- "@dxos/automerge": "0.6.5",
52
- "@dxos/credentials": "0.6.5",
53
- "@dxos/async": "0.6.5",
54
- "@dxos/crypto": "0.6.5",
55
- "@dxos/debug": "0.6.5",
56
- "@dxos/echo-db": "0.6.5",
57
- "@dxos/echo-protocol": "0.6.5",
58
- "@dxos/echo-pipeline": "0.6.5",
59
- "@dxos/feed-store": "0.6.5",
60
- "@dxos/indexing": "0.6.5",
61
- "@dxos/echo-schema": "0.6.5",
62
- "@dxos/invariant": "0.6.5",
63
- "@dxos/keys": "0.6.5",
64
- "@dxos/keyring": "0.6.5",
65
- "@dxos/kv-store": "0.6.5",
66
- "@dxos/lock-file": "0.6.5",
67
- "@dxos/messaging": "0.6.5",
68
- "@dxos/node-std": "0.6.5",
69
- "@dxos/log": "0.6.5",
70
- "@dxos/network-manager": "0.6.5",
71
- "@dxos/random-access-storage": "0.6.5",
72
- "@dxos/protocols": "0.6.5",
73
- "@dxos/rpc": "0.6.5",
74
- "@dxos/teleport": "0.6.5",
75
- "@dxos/teleport-extension-object-sync": "0.6.5",
76
- "@dxos/timeframe": "0.6.5",
77
- "@dxos/teleport-extension-gossip": "0.6.5",
78
- "@dxos/tracing": "0.6.5",
79
- "@dxos/util": "0.6.5",
80
- "@dxos/websocket-rpc": "0.6.5"
48
+ "@dxos/async": "0.6.6-main.e1a6e1f",
49
+ "@dxos/automerge": "0.6.6-main.e1a6e1f",
50
+ "@dxos/context": "0.6.6-main.e1a6e1f",
51
+ "@dxos/client-protocol": "0.6.6-main.e1a6e1f",
52
+ "@dxos/crypto": "0.6.6-main.e1a6e1f",
53
+ "@dxos/config": "0.6.6-main.e1a6e1f",
54
+ "@dxos/credentials": "0.6.6-main.e1a6e1f",
55
+ "@dxos/debug": "0.6.6-main.e1a6e1f",
56
+ "@dxos/echo-db": "0.6.6-main.e1a6e1f",
57
+ "@dxos/echo-pipeline": "0.6.6-main.e1a6e1f",
58
+ "@dxos/echo-protocol": "0.6.6-main.e1a6e1f",
59
+ "@dxos/edge-client": "0.6.6-main.e1a6e1f",
60
+ "@dxos/echo-schema": "0.6.6-main.e1a6e1f",
61
+ "@dxos/feed-store": "0.6.6-main.e1a6e1f",
62
+ "@dxos/invariant": "0.6.6-main.e1a6e1f",
63
+ "@dxos/indexing": "0.6.6-main.e1a6e1f",
64
+ "@dxos/keyring": "0.6.6-main.e1a6e1f",
65
+ "@dxos/lock-file": "0.6.6-main.e1a6e1f",
66
+ "@dxos/keys": "0.6.6-main.e1a6e1f",
67
+ "@dxos/kv-store": "0.6.6-main.e1a6e1f",
68
+ "@dxos/log": "0.6.6-main.e1a6e1f",
69
+ "@dxos/messaging": "0.6.6-main.e1a6e1f",
70
+ "@dxos/network-manager": "0.6.6-main.e1a6e1f",
71
+ "@dxos/node-std": "0.6.6-main.e1a6e1f",
72
+ "@dxos/protocols": "0.6.6-main.e1a6e1f",
73
+ "@dxos/random-access-storage": "0.6.6-main.e1a6e1f",
74
+ "@dxos/rpc": "0.6.6-main.e1a6e1f",
75
+ "@dxos/teleport": "0.6.6-main.e1a6e1f",
76
+ "@dxos/teleport-extension-gossip": "0.6.6-main.e1a6e1f",
77
+ "@dxos/timeframe": "0.6.6-main.e1a6e1f",
78
+ "@dxos/codec-protobuf": "0.6.6-main.e1a6e1f",
79
+ "@dxos/teleport-extension-object-sync": "0.6.6-main.e1a6e1f",
80
+ "@dxos/tracing": "0.6.6-main.e1a6e1f",
81
+ "@dxos/util": "0.6.6-main.e1a6e1f",
82
+ "@dxos/websocket-rpc": "0.6.6-main.e1a6e1f"
81
83
  },
82
84
  "devDependencies": {
83
85
  "@types/platform": "^1.3.4",
84
86
  "@types/readable-stream": "^2.3.9",
85
- "@dxos/signal": "0.6.5"
87
+ "@dxos/signal": "0.6.6-main.e1a6e1f"
86
88
  },
87
89
  "publishConfig": {
88
90
  "access": "public"
@@ -251,6 +251,7 @@ describe('InvitationHandler', () => {
251
251
  const peer = testBuilder.createPeer();
252
252
  await peer.createIdentity();
253
253
  await openAndClose(peer.echoHost, peer.dataSpaceManager);
254
+ await peer.echoHost.addReplicator(peer.meshEchoReplicator);
254
255
  if (spaceKey == null) {
255
256
  const space = await peer.dataSpaceManager.createSpace();
256
257
  spaceKey = space.key;
@@ -353,6 +353,18 @@ export class InvitationsHandler {
353
353
  await ctx.dispose();
354
354
  } else {
355
355
  invariant(invitation.swarmKey);
356
+
357
+ const timeoutInactive = () => {
358
+ if (guardedState.mutex.isLocked()) {
359
+ scheduleTask(ctx, timeoutInactive, timeout);
360
+ } else {
361
+ guardedState.set(null, Invitation.State.TIMEOUT);
362
+ }
363
+ };
364
+
365
+ // Timeout if no connection is established.
366
+ scheduleTask(ctx, timeoutInactive, timeout);
367
+
356
368
  await this._joinSwarm(ctx, invitation, InvitationOptions.Role.GUEST, createExtension);
357
369
  guardedState.set(null, Invitation.State.CONNECTING);
358
370
  }
@@ -12,7 +12,7 @@ import { afterTest, describe, test } from '@dxos/test';
12
12
 
13
13
  import { type ServiceContext } from '../services';
14
14
  import { createIdentity, createPeers } from '../testing';
15
- import { performInvitation } from '../testing/invitation-utils';
15
+ import { acceptInvitation, createInvitation, performInvitation } from '../testing/invitation-utils';
16
16
 
17
17
  const closeAfterTest = async (peer: ServiceContext) => {
18
18
  afterTest(() => peer.close());
@@ -151,6 +151,28 @@ describe('services/space-invitations-protocol', () => {
151
151
  ).to.equal(2); // own halo + newly joined space.
152
152
  });
153
153
 
154
+ test('timeout', async () => {
155
+ const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
156
+ const space = await host.dataSpaceManager!.createSpace();
157
+ const hostInvitation = await createInvitation(host, {
158
+ kind: Invitation.Kind.SPACE,
159
+ spaceKey: space.key,
160
+ timeout: 100,
161
+ });
162
+ const invitation = hostInvitation.get();
163
+ await host.close();
164
+
165
+ const guestTimeout = new Trigger();
166
+ const guestInvitation = await acceptInvitation(guest, invitation);
167
+ guestInvitation.subscribe((invitation) => {
168
+ if (invitation.state === Invitation.State.TIMEOUT) {
169
+ guestTimeout.wake();
170
+ }
171
+ });
172
+
173
+ await guestTimeout.wait();
174
+ });
175
+
154
176
  test('cancels invitation', async () => {
155
177
  const [host, guest] = await asyncChain<ServiceContext>([createIdentity, closeAfterTest])(createPeers(2));
156
178
 
@@ -6,8 +6,9 @@ import { Trigger } from '@dxos/async';
6
6
  import { Context, Resource } from '@dxos/context';
7
7
  import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
8
8
  import { failUndefined } from '@dxos/debug';
9
- import { EchoHost } from '@dxos/echo-db';
10
- import { MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
9
+ import { EchoEdgeReplicator, EchoHost } from '@dxos/echo-db';
10
+ import { MeshEchoReplicator, MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
11
+ import type { EdgeConnection } from '@dxos/edge-client';
11
12
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
12
13
  import { invariant } from '@dxos/invariant';
13
14
  import { Keyring } from '@dxos/keyring';
@@ -42,7 +43,10 @@ import {
42
43
  import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
43
44
 
44
45
  export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams &
45
- DataSpaceManagerRuntimeParams & { invitationConnectionDefaultParams?: Partial<TeleportParams> };
46
+ DataSpaceManagerRuntimeParams & {
47
+ invitationConnectionDefaultParams?: Partial<TeleportParams>;
48
+ disableP2pReplication?: boolean;
49
+ };
46
50
  /**
47
51
  * Shared backend for all client services.
48
52
  */
@@ -65,6 +69,8 @@ export class ServiceContext extends Resource {
65
69
  public readonly invitations: InvitationsHandler;
66
70
  public readonly invitationsManager: InvitationsManager;
67
71
  public readonly echoHost: EchoHost;
72
+ private readonly _meshReplicator?: MeshEchoReplicator = undefined;
73
+ private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
68
74
 
69
75
  // Initialized after identity is initialized.
70
76
  public dataSpaceManager?: DataSpaceManager;
@@ -83,6 +89,7 @@ export class ServiceContext extends Resource {
83
89
  public readonly level: LevelDB,
84
90
  public readonly networkManager: SwarmNetworkManager,
85
91
  public readonly signalManager: SignalManager,
92
+ private readonly _edgeConnection: EdgeConnection | undefined,
86
93
  public readonly _runtimeParams?: ServiceContextRuntimeParams,
87
94
  ) {
88
95
  super();
@@ -110,6 +117,7 @@ export class ServiceContext extends Resource {
110
117
  blobStore: this.blobStore,
111
118
  metadataStore: this.metadataStore,
112
119
  snapshotStore: this.snapshotStore,
120
+ disableP2pReplication: this._runtimeParams?.disableP2pReplication,
113
121
  });
114
122
 
115
123
  this.identityManager = new IdentityManager(
@@ -140,6 +148,15 @@ export class ServiceContext extends Resource {
140
148
  this._acceptIdentity.bind(this),
141
149
  ),
142
150
  );
151
+
152
+ if (!this._runtimeParams?.disableP2pReplication) {
153
+ this._meshReplicator = new MeshEchoReplicator();
154
+ }
155
+ if (this._edgeConnection) {
156
+ this._echoEdgeReplicator = new EchoEdgeReplicator({
157
+ edgeConnection: this._edgeConnection,
158
+ });
159
+ }
143
160
  }
144
161
 
145
162
  @Trace.span()
@@ -150,8 +167,17 @@ export class ServiceContext extends Resource {
150
167
  log.trace('dxos.sdk.service-context.open', trace.begin({ id: this._instanceId }));
151
168
  await this.signalManager.open();
152
169
  await this.networkManager.open();
170
+ await this._edgeConnection?.open();
153
171
 
154
172
  await this.echoHost.open(ctx);
173
+
174
+ if (this._meshReplicator) {
175
+ await this.echoHost.addReplicator(this._meshReplicator);
176
+ }
177
+ if (this._echoEdgeReplicator) {
178
+ await this.echoHost.addReplicator(this._echoEdgeReplicator);
179
+ }
180
+
155
181
  await this.metadataStore.load();
156
182
  await this.spaceManager.open();
157
183
  await this.identityManager.open(ctx);
@@ -176,9 +202,12 @@ export class ServiceContext extends Resource {
176
202
  await this.spaceManager.close();
177
203
  await this.feedStore.close();
178
204
  await this.metadataStore.close();
205
+
179
206
  await this.echoHost.close(ctx);
180
207
  await this.networkManager.close();
181
208
  await this.signalManager.close();
209
+ await this._edgeConnection?.close();
210
+
182
211
  log('closed');
183
212
  }
184
213
 
@@ -233,16 +262,19 @@ export class ServiceContext extends Resource {
233
262
  },
234
263
  };
235
264
 
236
- this.dataSpaceManager = new DataSpaceManager(
237
- this.spaceManager,
238
- this.metadataStore,
239
- this.keyring,
265
+ this.dataSpaceManager = new DataSpaceManager({
266
+ spaceManager: this.spaceManager,
267
+ metadataStore: this.metadataStore,
268
+ keyring: this.keyring,
240
269
  signingContext,
241
- this.feedStore,
242
- this.echoHost,
243
- this.invitationsManager,
244
- this._runtimeParams as DataSpaceManagerRuntimeParams,
245
- );
270
+ feedStore: this.feedStore,
271
+ echoHost: this.echoHost,
272
+ invitationsManager: this.invitationsManager,
273
+ edgeConnection: this._edgeConnection,
274
+ echoEdgeReplicator: this._echoEdgeReplicator,
275
+ meshReplicator: this._meshReplicator,
276
+ runtimeParams: this._runtimeParams as DataSpaceManagerRuntimeParams,
277
+ });
246
278
  await this.dataSpaceManager.open();
247
279
 
248
280
  this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
@@ -6,12 +6,18 @@ import { Event, synchronized } from '@dxos/async';
6
6
  import { clientServiceBundle, type ClientServices } from '@dxos/client-protocol';
7
7
  import { type Config } from '@dxos/config';
8
8
  import { Context } from '@dxos/context';
9
+ import { EdgeClient, type EdgeConnection } from '@dxos/edge-client';
9
10
  import { invariant } from '@dxos/invariant';
10
11
  import { PublicKey } from '@dxos/keys';
11
12
  import { type LevelDB } from '@dxos/kv-store';
12
13
  import { log } from '@dxos/log';
13
14
  import { WebsocketSignalManager, type SignalManager } from '@dxos/messaging';
14
- import { SwarmNetworkManager, createSimplePeerTransportFactory, type TransportFactory } from '@dxos/network-manager';
15
+ import {
16
+ SwarmNetworkManager,
17
+ createIceProvider,
18
+ createSimplePeerTransportFactory,
19
+ type TransportFactory,
20
+ } from '@dxos/network-manager';
15
21
  import { trace } from '@dxos/protocols';
16
22
  import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
17
23
  import { type Storage } from '@dxos/random-access-storage';
@@ -82,6 +88,7 @@ export class ClientServicesHost {
82
88
  private _level?: LevelDB;
83
89
  private _callbacks?: ClientServicesHostCallbacks;
84
90
  private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
91
+ private _edgeConnection?: EdgeConnection = undefined;
85
92
 
86
93
  private _serviceContext!: ServiceContext;
87
94
  private readonly _runtimeParams: ServiceContextRuntimeParams;
@@ -109,6 +116,10 @@ export class ClientServicesHost {
109
116
  this._callbacks = callbacks;
110
117
  this._runtimeParams = runtimeParams ?? {};
111
118
 
119
+ if (this._runtimeParams.disableP2pReplication === undefined) {
120
+ this._runtimeParams.disableP2pReplication = config?.get('runtime.client.disableP2pReplication', false);
121
+ }
122
+
112
123
  if (config) {
113
124
  this.initialize({ config, transportFactory, signalManager });
114
125
  }
@@ -200,9 +211,11 @@ export class ClientServicesHost {
200
211
  }
201
212
  const {
202
213
  connectionLog = true,
203
- transportFactory = createSimplePeerTransportFactory({
204
- iceServers: this._config?.get('runtime.services.ice'),
205
- }),
214
+ transportFactory = createSimplePeerTransportFactory(
215
+ { iceServers: this._config?.get('runtime.services.ice') },
216
+ this._config?.get('runtime.services.iceProviders') &&
217
+ createIceProvider(this._config!.get('runtime.services.iceProviders')!),
218
+ ),
206
219
  signalManager = new WebsocketSignalManager(this._config?.get('runtime.services.signaling') ?? []),
207
220
  } = options;
208
221
  this._signalManager = signalManager;
@@ -214,6 +227,14 @@ export class ClientServicesHost {
214
227
  signalManager,
215
228
  });
216
229
 
230
+ const edgeEndpoint = config?.get('runtime.services.edge.url');
231
+ if (edgeEndpoint) {
232
+ // TODO(dmaretskyi): Use actual identity instead of random keys.
233
+ this._edgeConnection = new EdgeClient(PublicKey.random(), PublicKey.random(), {
234
+ socketEndpoint: edgeEndpoint,
235
+ });
236
+ }
237
+
217
238
  log('initialized');
218
239
  }
219
240
 
@@ -249,6 +270,7 @@ export class ClientServicesHost {
249
270
  this._level,
250
271
  this._networkManager,
251
272
  this._signalManager,
273
+ this._edgeConnection,
252
274
  this._runtimeParams,
253
275
  );
254
276
 
@@ -43,6 +43,7 @@ describe('DataSpaceManager', () => {
43
43
  await peer2.createIdentity();
44
44
 
45
45
  await openAndClose(peer1.echoHost, peer1.dataSpaceManager, peer2.echoHost, peer2.dataSpaceManager);
46
+ await connectReplicators([peer1, peer2]);
46
47
 
47
48
  const space1 = await peer1.dataSpaceManager.createSpace();
48
49
  await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
@@ -112,6 +113,7 @@ describe('DataSpaceManager', () => {
112
113
  await peer2.dataSpaceManager.open();
113
114
 
114
115
  await openAndClose(peer1.echoHost, peer1.dataSpaceManager, peer2.echoHost, peer2.dataSpaceManager);
116
+ await connectReplicators([peer1, peer2]);
115
117
 
116
118
  const space1 = await peer1.dataSpaceManager.createSpace();
117
119
  await space1.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.endTimeframe);
@@ -206,6 +208,10 @@ describe('DataSpaceManager', () => {
206
208
  });
207
209
  });
208
210
 
211
+ const connectReplicators = (peers: TestPeer[]) => {
212
+ return Promise.all(peers.map((peer) => peer.echoHost.addReplicator(peer.meshEchoReplicator)));
213
+ };
214
+
209
215
  const reloadDataSpaces = async (peer: TestPeer) => {
210
216
  await peer.dataSpaceManager.close();
211
217
  await peer.dataSpaceManager.open();