@dxos/client-services 0.6.13 → 0.6.14-main.69511f5

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 (138) hide show
  1. package/dist/lib/browser/{chunk-CRXXOI45.mjs → chunk-PK5RMXEO.mjs} +6462 -5230
  2. package/dist/lib/browser/chunk-PK5RMXEO.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +7 -3
  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 +12 -8
  7. package/dist/lib/browser/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-PZ3JJJ3K.cjs → chunk-XDE6WELX.cjs} +6287 -5057
  9. package/dist/lib/node/chunk-XDE6WELX.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +50 -46
  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 +18 -13
  14. package/dist/lib/node/testing/index.cjs.map +3 -3
  15. package/dist/lib/node-esm/chunk-S5DTGWTU.mjs +8956 -0
  16. package/dist/lib/node-esm/chunk-S5DTGWTU.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +420 -0
  18. package/dist/lib/node-esm/index.mjs.map +7 -0
  19. package/dist/lib/node-esm/meta.json +1 -0
  20. package/dist/lib/node-esm/testing/index.mjs +424 -0
  21. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  22. package/dist/types/src/index.d.ts +1 -0
  23. package/dist/types/src/index.d.ts.map +1 -1
  24. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +35 -0
  25. package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -0
  26. package/dist/types/src/packlets/agents/edge-agent-service.d.ts +10 -0
  27. package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -0
  28. package/dist/types/src/packlets/agents/index.d.ts +3 -0
  29. package/dist/types/src/packlets/agents/index.d.ts.map +1 -0
  30. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  31. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  32. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts +2 -0
  33. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts.map +1 -0
  34. package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
  35. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  36. package/dist/types/src/packlets/identity/identity-manager.d.ts +28 -9
  37. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  38. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +18 -0
  39. package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -0
  40. package/dist/types/src/packlets/identity/identity-service.d.ts +7 -2
  41. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  42. package/dist/types/src/packlets/identity/identity.d.ts +12 -3
  43. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  44. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  45. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +30 -0
  46. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -0
  47. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts +2 -1
  48. package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
  49. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts +2 -1
  50. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  51. package/dist/types/src/packlets/invitations/invitation-state.d.ts +19 -0
  52. package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -0
  53. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +8 -8
  54. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  55. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  56. package/dist/types/src/packlets/services/service-context.d.ts +14 -9
  57. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  58. package/dist/types/src/packlets/services/service-host.d.ts +2 -0
  59. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  60. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +7 -3
  61. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  62. package/dist/types/src/packlets/spaces/data-space.d.ts +5 -3
  63. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  64. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +3 -0
  65. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  66. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts +2 -0
  67. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts.map +1 -0
  68. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +1 -1
  69. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
  70. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +35 -6
  71. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  72. package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
  73. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  74. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  75. package/dist/types/src/packlets/testing/test-builder.d.ts +1 -2
  76. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  77. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  78. package/dist/types/src/testing/setup.d.ts +3 -0
  79. package/dist/types/src/testing/setup.d.ts.map +1 -0
  80. package/dist/types/src/version.d.ts +1 -1
  81. package/dist/types/src/version.d.ts.map +1 -1
  82. package/package.json +44 -45
  83. package/src/index.ts +1 -0
  84. package/src/packlets/agents/edge-agent-manager.ts +163 -0
  85. package/src/packlets/agents/edge-agent-service.ts +42 -0
  86. package/src/packlets/agents/index.ts +6 -0
  87. package/src/packlets/devices/devices-service.test.ts +4 -5
  88. package/src/packlets/diagnostics/diagnostics-broadcast.ts +1 -0
  89. package/src/packlets/identity/{authenticator.test.ts → authenticator.node.test.ts} +2 -3
  90. package/src/packlets/identity/authenticator.ts +5 -2
  91. package/src/packlets/identity/contacts-service.ts +1 -1
  92. package/src/packlets/identity/identity-manager.test.ts +31 -16
  93. package/src/packlets/identity/identity-manager.ts +76 -32
  94. package/src/packlets/identity/identity-recovery-manager.ts +95 -0
  95. package/src/packlets/identity/identity-service.test.ts +5 -8
  96. package/src/packlets/identity/identity-service.ts +11 -5
  97. package/src/packlets/identity/identity.test.ts +130 -239
  98. package/src/packlets/identity/identity.ts +60 -17
  99. package/src/packlets/invitations/device-invitation-protocol.test.ts +7 -4
  100. package/src/packlets/invitations/device-invitation-protocol.ts +8 -2
  101. package/src/packlets/invitations/edge-invitation-handler.ts +185 -0
  102. package/src/packlets/invitations/invitation-guest-extenstion.ts +8 -4
  103. package/src/packlets/invitations/invitation-host-extension.ts +8 -7
  104. package/src/packlets/invitations/invitation-state.ts +112 -0
  105. package/src/packlets/invitations/invitations-handler.test.ts +16 -9
  106. package/src/packlets/invitations/invitations-handler.ts +57 -98
  107. package/src/packlets/invitations/space-invitation-protocol.test.ts +4 -3
  108. package/src/packlets/invitations/space-invitation-protocol.ts +5 -0
  109. package/src/packlets/logging/logging.test.ts +1 -2
  110. package/src/packlets/network/network-service.test.ts +2 -3
  111. package/src/packlets/services/service-context.test.ts +3 -1
  112. package/src/packlets/services/service-context.ts +113 -35
  113. package/src/packlets/services/service-host.test.ts +8 -12
  114. package/src/packlets/services/service-host.ts +25 -7
  115. package/src/packlets/services/service-registry.test.ts +1 -2
  116. package/src/packlets/spaces/data-space-manager.test.ts +2 -2
  117. package/src/packlets/spaces/data-space-manager.ts +44 -7
  118. package/src/packlets/spaces/data-space.ts +37 -6
  119. package/src/packlets/spaces/edge-feed-replicator.test.ts +252 -0
  120. package/src/packlets/spaces/edge-feed-replicator.ts +80 -22
  121. package/src/packlets/spaces/epoch-migrations.ts +2 -2
  122. package/src/packlets/spaces/notarization-plugin.test.ts +10 -7
  123. package/src/packlets/spaces/notarization-plugin.ts +196 -29
  124. package/src/packlets/spaces/spaces-service.test.ts +5 -9
  125. package/src/packlets/spaces/spaces-service.ts +6 -1
  126. package/src/packlets/storage/storage.ts +0 -1
  127. package/src/packlets/system/system-service.test.ts +1 -2
  128. package/src/packlets/testing/test-builder.ts +7 -4
  129. package/src/packlets/worker/worker-runtime.ts +2 -2
  130. package/src/testing/setup.ts +11 -0
  131. package/src/version.ts +1 -5
  132. package/dist/lib/browser/chunk-CRXXOI45.mjs.map +0 -7
  133. package/dist/lib/node/chunk-PZ3JJJ3K.cjs.map +0 -7
  134. package/dist/types/src/packlets/identity/authenticator.test.d.ts +0 -2
  135. package/dist/types/src/packlets/identity/authenticator.test.d.ts.map +0 -1
  136. package/dist/types/src/packlets/services/automerge-host.test.d.ts +0 -2
  137. package/dist/types/src/packlets/services/automerge-host.test.d.ts.map +0 -1
  138. package/src/packlets/services/automerge-host.test.ts +0 -60
@@ -2,9 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import chai, { expect } from 'chai';
6
- import chaiAsPromised from 'chai-as-promised';
7
5
  import { rmSync } from 'node:fs';
6
+ import { afterEach, onTestFinished, describe, expect, test } from 'vitest';
8
7
 
9
8
  import { asyncTimeout, latch, Trigger } from '@dxos/async';
10
9
  import { Config } from '@dxos/config';
@@ -14,13 +13,10 @@ import { type PublicKey } from '@dxos/keys';
14
13
  import { MemorySignalManagerContext } from '@dxos/messaging';
15
14
  import { type Identity } from '@dxos/protocols/proto/dxos/client/services';
16
15
  import { type Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
17
- import { afterTest, describe, test } from '@dxos/test';
18
16
  import { isNode } from '@dxos/util';
19
17
 
20
18
  import { createMockCredential, createServiceHost } from '../testing';
21
19
 
22
- chai.use(chaiAsPromised);
23
-
24
20
  describe('ClientServicesHost', () => {
25
21
  const dataRoot = '/tmp/dxos/client-services/service-host/storage';
26
22
 
@@ -38,7 +34,7 @@ describe('ClientServicesHost', () => {
38
34
  test('queryCredentials', async () => {
39
35
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
40
36
  await host.open(new Context());
41
- afterTest(() => host.close());
37
+ onTestFinished(() => host.close());
42
38
 
43
39
  await host.services.IdentityService!.createIdentity({});
44
40
  const { spaceKey } = await host.services.SpacesService!.createSpace();
@@ -49,7 +45,7 @@ describe('ClientServicesHost', () => {
49
45
  tick();
50
46
  // console.log(credential);
51
47
  });
52
- afterTest(() => stream.close());
48
+ onTestFinished(() => stream.close());
53
49
 
54
50
  await done();
55
51
  });
@@ -57,7 +53,7 @@ describe('ClientServicesHost', () => {
57
53
  test('write and query credentials', async () => {
58
54
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
59
55
  await host.open(new Context());
60
- afterTest(() => host.close());
56
+ onTestFinished(() => host.close());
61
57
 
62
58
  await host.services.IdentityService!.createIdentity({});
63
59
 
@@ -86,7 +82,7 @@ describe('ClientServicesHost', () => {
86
82
  queriedCredential.wake(credential);
87
83
  }
88
84
  });
89
- afterTest(() => credentials.close());
85
+ onTestFinished(() => credentials.close());
90
86
 
91
87
  await queriedCredential.wait();
92
88
  });
@@ -94,7 +90,7 @@ describe('ClientServicesHost', () => {
94
90
  test('sign presentation', async () => {
95
91
  const host = createServiceHost(new Config(), new MemorySignalManagerContext());
96
92
  await host.open(new Context());
97
- afterTest(() => host.close());
93
+ onTestFinished(() => host.close());
98
94
 
99
95
  await host.services.IdentityService!.createIdentity({});
100
96
 
@@ -147,9 +143,9 @@ describe('ClientServicesHost', () => {
147
143
  trigger.wake(identity.identity);
148
144
  }
149
145
  });
150
- await expect(asyncTimeout(trigger.wait(), 200)).to.be.rejectedWith();
146
+ await expect(asyncTimeout(trigger.wait(), 200)).rejects.toBeInstanceOf(Error);
151
147
  await stream?.close();
152
148
  await host.close();
153
149
  }
154
- }).onlyEnvironments('nodejs', 'chromium', 'firefox');
150
+ });
155
151
  });
@@ -6,7 +6,7 @@ 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
+ import { EdgeClient, EdgeHttpClient, createStubEdgeIdentity, type EdgeConnection } from '@dxos/edge-client';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { PublicKey } from '@dxos/keys';
12
12
  import { type LevelDB } from '@dxos/kv-store';
@@ -15,7 +15,7 @@ import { EdgeSignalManager, WebsocketSignalManager, type SignalManager } from '@
15
15
  import {
16
16
  SwarmNetworkManager,
17
17
  createIceProvider,
18
- createSimplePeerTransportFactory,
18
+ createRtcTransportFactory,
19
19
  type TransportFactory,
20
20
  } from '@dxos/network-manager';
21
21
  import { trace } from '@dxos/protocols';
@@ -26,12 +26,13 @@ import { WebsocketRpcClient } from '@dxos/websocket-rpc';
26
26
 
27
27
  import { ServiceContext, type ServiceContextRuntimeParams } from './service-context';
28
28
  import { ServiceRegistry } from './service-registry';
29
+ import { EdgeAgentServiceImpl } from '../agents';
29
30
  import { DevicesServiceImpl } from '../devices';
30
31
  import { DevtoolsHostEvents, DevtoolsServiceImpl } from '../devtools';
31
32
  import {
32
- type CollectDiagnosticsBroadcastHandler,
33
33
  createCollectDiagnosticsBroadcastHandler,
34
34
  createDiagnostics,
35
+ type CollectDiagnosticsBroadcastHandler,
35
36
  } from '../diagnostics';
36
37
  import { IdentityServiceImpl, type CreateIdentityOptions } from '../identity';
37
38
  import { ContactsServiceImpl } from '../identity/contacts-service';
@@ -89,6 +90,7 @@ export class ClientServicesHost {
89
90
  private _callbacks?: ClientServicesHostCallbacks;
90
91
  private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
91
92
  private _edgeConnection?: EdgeConnection = undefined;
93
+ private _edgeHttpClient?: EdgeHttpClient = undefined;
92
94
 
93
95
  private _serviceContext!: ServiceContext;
94
96
  private readonly _runtimeParams: ServiceContextRuntimeParams;
@@ -100,6 +102,9 @@ export class ClientServicesHost {
100
102
  @Trace.info()
101
103
  private _open = false;
102
104
 
105
+ @Trace.info()
106
+ private _resetting = false;
107
+
103
108
  constructor({
104
109
  config,
105
110
  transportFactory,
@@ -140,7 +145,7 @@ export class ClientServicesHost {
140
145
  this._systemService = new SystemServiceImpl({
141
146
  config: () => this._config,
142
147
  statusUpdate: this._statusUpdate,
143
- getCurrentStatus: () => (this.isOpen ? SystemStatus.ACTIVE : SystemStatus.INACTIVE),
148
+ getCurrentStatus: () => (this.isOpen && !this._resetting ? SystemStatus.ACTIVE : SystemStatus.INACTIVE),
144
149
  getDiagnostics: () => {
145
150
  return createDiagnostics(this._serviceRegistry.services, this._serviceContext, this._config!);
146
151
  },
@@ -212,13 +217,13 @@ export class ClientServicesHost {
212
217
 
213
218
  const edgeEndpoint = config?.get('runtime.services.edge.url');
214
219
  if (edgeEndpoint) {
215
- const randomKey = PublicKey.random().toHex();
216
- this._edgeConnection = new EdgeClient(randomKey, randomKey, { socketEndpoint: edgeEndpoint });
220
+ this._edgeConnection = new EdgeClient(createStubEdgeIdentity(), { socketEndpoint: edgeEndpoint });
221
+ this._edgeHttpClient = new EdgeHttpClient(edgeEndpoint);
217
222
  }
218
223
 
219
224
  const {
220
225
  connectionLog = true,
221
- transportFactory = createSimplePeerTransportFactory(
226
+ transportFactory = createRtcTransportFactory(
222
227
  { iceServers: this._config?.get('runtime.services.ice') },
223
228
  this._config?.get('runtime.services.iceProviders') &&
224
229
  createIceProvider(this._config!.get('runtime.services.iceProviders')!),
@@ -278,6 +283,7 @@ export class ClientServicesHost {
278
283
  this._networkManager,
279
284
  this._signalManager,
280
285
  this._edgeConnection,
286
+ this._edgeHttpClient,
281
287
  this._runtimeParams,
282
288
  this._config.get('runtime.client.edgeFeatures'),
283
289
  );
@@ -287,8 +293,14 @@ export class ClientServicesHost {
287
293
  return this._serviceContext.dataSpaceManager!;
288
294
  };
289
295
 
296
+ const agentManagerProvider = async () => {
297
+ await this._serviceContext.initialized.wait();
298
+ return this._serviceContext.edgeAgentManager!;
299
+ };
300
+
290
301
  const identityService = new IdentityServiceImpl(
291
302
  this._serviceContext.identityManager,
303
+ this._serviceContext.recoveryManager,
292
304
  this._serviceContext.keyring,
293
305
  () => this._serviceContext.dataSpaceManager!,
294
306
  (params) => this._createIdentity(params),
@@ -328,6 +340,8 @@ export class ClientServicesHost {
328
340
  config: this._config,
329
341
  context: this._serviceContext,
330
342
  }),
343
+
344
+ EdgeAgentService: new EdgeAgentServiceImpl(agentManagerProvider),
331
345
  });
332
346
 
333
347
  await this._serviceContext.open(ctx);
@@ -378,6 +392,10 @@ export class ClientServicesHost {
378
392
  log.trace('dxos.sdk.client-services-host.reset', trace.begin({ id: traceId }));
379
393
 
380
394
  log.info('resetting...');
395
+ // Emit this status update immediately so app returns to fallback.
396
+ // This state is never cleared because the app reloads.
397
+ this._resetting = true;
398
+ this._statusUpdate.emit();
381
399
  await this._serviceContext?.close();
382
400
  await this._storage!.reset();
383
401
  log.info('reset');
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { expect } from 'chai';
5
+ import { describe, expect, test } from 'vitest';
6
6
 
7
7
  import { Event } from '@dxos/async';
8
8
  import { type ClientServices } from '@dxos/client-protocol';
@@ -12,7 +12,6 @@ import { log } from '@dxos/log';
12
12
  import { schema } from '@dxos/protocols/proto';
13
13
  import { type SystemService, SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
14
14
  import { createLinkedPorts, createProtoRpcPeer, createServiceBundle } from '@dxos/rpc';
15
- import { describe, test } from '@dxos/test';
16
15
 
17
16
  import { ServiceRegistry } from './service-registry';
18
17
  import { SystemServiceImpl } from '../system';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { expect } from 'chai';
5
+ import { describe, expect, test } from 'vitest';
6
6
 
7
7
  import { asyncTimeout, latch } from '@dxos/async';
8
8
  import { createAdmissionCredentials } from '@dxos/credentials';
@@ -10,7 +10,7 @@ import { AuthStatus } from '@dxos/echo-pipeline';
10
10
  import { writeMessages } from '@dxos/feed-store';
11
11
  import { log } from '@dxos/log';
12
12
  import { SpaceState } from '@dxos/protocols/proto/dxos/client/services';
13
- import { describe, openAndClose, test } from '@dxos/test';
13
+ import { openAndClose } from '@dxos/test-utils';
14
14
 
15
15
  import { TestBuilder, type TestPeer } from '../testing';
16
16
 
@@ -14,8 +14,11 @@ import {
14
14
  type DelegateInvitationCredential,
15
15
  type MemberInfo,
16
16
  } from '@dxos/credentials';
17
- import { convertLegacyReferences, findInlineObjectOfType, type EchoEdgeReplicator, type EchoHost } from '@dxos/echo-db';
18
17
  import {
18
+ convertLegacyReferences,
19
+ findInlineObjectOfType,
20
+ type EchoEdgeReplicator,
21
+ type EchoHost,
19
22
  AuthStatus,
20
23
  CredentialServerExtension,
21
24
  type MeshEchoReplicator,
@@ -32,8 +35,8 @@ import {
32
35
  type ObjectStructure,
33
36
  type SpaceDoc,
34
37
  } from '@dxos/echo-protocol';
35
- import { TYPE_PROPERTIES, generateEchoId, getTypeReference } from '@dxos/echo-schema';
36
- import type { EdgeConnection } from '@dxos/edge-client';
38
+ import { TYPE_PROPERTIES, createObjectId, getTypeReference } from '@dxos/echo-schema';
39
+ import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
37
40
  import { writeMessages, type FeedStore } from '@dxos/feed-store';
38
41
  import { invariant } from '@dxos/invariant';
39
42
  import { type Keyring } from '@dxos/keyring';
@@ -43,7 +46,7 @@ import { AlreadyJoinedError, trace as Trace } from '@dxos/protocols';
43
46
  import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
44
47
  import { type Runtime } from '@dxos/protocols/proto/dxos/config';
45
48
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
46
- import { type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
49
+ import { type SpaceMetadata, EdgeReplicationSetting } from '@dxos/protocols/proto/dxos/echo/metadata';
47
50
  import { SpaceMember, type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
48
51
  import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
49
52
  import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
@@ -107,6 +110,7 @@ export type DataSpaceManagerParams = {
107
110
  echoHost: EchoHost;
108
111
  invitationsManager: InvitationsManager;
109
112
  edgeConnection?: EdgeConnection;
113
+ edgeHttpClient?: EdgeHttpClient;
110
114
  meshReplicator?: MeshEchoReplicator;
111
115
  echoEdgeReplicator?: EchoEdgeReplicator;
112
116
  runtimeParams?: DataSpaceManagerRuntimeParams;
@@ -116,6 +120,7 @@ export type DataSpaceManagerParams = {
116
120
  export type DataSpaceManagerRuntimeParams = {
117
121
  spaceMemberPresenceAnnounceInterval?: number;
118
122
  spaceMemberPresenceOfflineTimeout?: number;
123
+ activeEdgeNotarizationPollingInterval?: number;
119
124
  disableP2pReplication?: boolean;
120
125
  };
121
126
 
@@ -135,6 +140,7 @@ export class DataSpaceManager extends Resource {
135
140
  private readonly _echoHost: EchoHost;
136
141
  private readonly _invitationsManager: InvitationsManager;
137
142
  private readonly _edgeConnection?: EdgeConnection = undefined;
143
+ private readonly _edgeHttpClient?: EdgeHttpClient = undefined;
138
144
  private readonly _edgeFeatures?: Runtime.Client.EdgeFeatures = undefined;
139
145
  private readonly _meshReplicator?: MeshEchoReplicator = undefined;
140
146
  private readonly _echoEdgeReplicator?: EchoEdgeReplicator = undefined;
@@ -154,6 +160,7 @@ export class DataSpaceManager extends Resource {
154
160
  this._edgeConnection = params.edgeConnection;
155
161
  this._edgeFeatures = params.edgeFeatures;
156
162
  this._echoEdgeReplicator = params.echoEdgeReplicator;
163
+ this._edgeHttpClient = params.edgeHttpClient;
157
164
  this._runtimeParams = params.runtimeParams;
158
165
 
159
166
  trace.diagnostic({
@@ -290,7 +297,7 @@ export class DataSpaceManager extends Resource {
290
297
  },
291
298
  };
292
299
 
293
- const propertiesId = generateEchoId();
300
+ const propertiesId = createObjectId();
294
301
  document.change((doc: SpaceDoc) => {
295
302
  setDeep(doc, ['objects', propertiesId], properties);
296
303
  });
@@ -388,6 +395,26 @@ export class DataSpaceManager extends Resource {
388
395
  });
389
396
  }
390
397
 
398
+ async setSpaceEdgeReplicationSetting(spaceKey: PublicKey, setting: EdgeReplicationSetting) {
399
+ const space = this._spaces.get(spaceKey);
400
+ invariant(space, 'Space not found.');
401
+
402
+ await this._metadataStore.setSpaceEdgeReplicationSetting(spaceKey, setting);
403
+
404
+ if (space.isOpen) {
405
+ switch (setting) {
406
+ case EdgeReplicationSetting.DISABLED:
407
+ await this._echoEdgeReplicator?.disconnectFromSpace(space.id);
408
+ break;
409
+ case EdgeReplicationSetting.ENABLED:
410
+ await this._echoEdgeReplicator?.connectToSpace(space.id);
411
+ break;
412
+ }
413
+ }
414
+
415
+ space.stateUpdate.emit();
416
+ }
417
+
391
418
  private async _constructSpace(metadata: SpaceMetadata) {
392
419
  log('construct space', { metadata });
393
420
  const gossip = new Gossip({
@@ -479,13 +506,23 @@ export class DataSpaceManager extends Resource {
479
506
  },
480
507
  cache: metadata.cache,
481
508
  edgeConnection: this._edgeConnection,
509
+ edgeHttpClient: this._edgeHttpClient,
482
510
  edgeFeatures: this._edgeFeatures,
511
+ activeEdgeNotarizationPollingInterval: this._runtimeParams?.activeEdgeNotarizationPollingInterval,
483
512
  });
484
513
  dataSpace.postOpen.append(async () => {
485
- await this._echoEdgeReplicator?.connectToSpace(dataSpace.id);
514
+ const setting = dataSpace.getEdgeReplicationSetting();
515
+ if (setting === EdgeReplicationSetting.ENABLED) {
516
+ await this._echoEdgeReplicator?.connectToSpace(dataSpace.id);
517
+ } else if (this._echoEdgeReplicator) {
518
+ log('not connecting EchoEdgeReplicator because of EdgeReplicationSetting', { spaceId: dataSpace.id });
519
+ }
486
520
  });
487
521
  dataSpace.preClose.append(async () => {
488
- await this._echoEdgeReplicator?.disconnectFromSpace(dataSpace.id);
522
+ const setting = dataSpace.getEdgeReplicationSetting();
523
+ if (setting === EdgeReplicationSetting.ENABLED) {
524
+ await this._echoEdgeReplicator?.disconnectFromSpace(dataSpace.id);
525
+ }
489
526
  });
490
527
 
491
528
  presence.newPeer.on((peerState) => {
@@ -7,10 +7,15 @@ import { AUTH_TIMEOUT } from '@dxos/client-protocol';
7
7
  import { Context, ContextDisposedError, cancelWithContext } from '@dxos/context';
8
8
  import type { SpecificCredential } from '@dxos/credentials';
9
9
  import { timed, warnAfterTimeout } from '@dxos/debug';
10
- import { type EchoHost, type DatabaseRoot } from '@dxos/echo-db';
11
- import { createMappedFeedWriter, type MetadataStore, type Space } from '@dxos/echo-pipeline';
10
+ import {
11
+ type EchoHost,
12
+ type DatabaseRoot,
13
+ createMappedFeedWriter,
14
+ type MetadataStore,
15
+ type Space,
16
+ } from '@dxos/echo-pipeline';
12
17
  import { SpaceDocVersion } from '@dxos/echo-protocol';
13
- import type { EdgeConnection } from '@dxos/edge-client';
18
+ import type { EdgeConnection, EdgeHttpClient } from '@dxos/edge-client';
14
19
  import { type FeedStore, type FeedWrapper } from '@dxos/feed-store';
15
20
  import { failedInvariant } from '@dxos/invariant';
16
21
  import { type Keyring } from '@dxos/keyring';
@@ -75,7 +80,9 @@ export type DataSpaceParams = {
75
80
  callbacks?: DataSpaceCallbacks;
76
81
  cache?: SpaceCache;
77
82
  edgeConnection?: EdgeConnection;
83
+ edgeHttpClient?: EdgeHttpClient;
78
84
  edgeFeatures?: Runtime.Client.EdgeFeatures;
85
+ activeEdgeNotarizationPollingInterval?: number;
79
86
  };
80
87
 
81
88
  export type CreateEpochOptions = {
@@ -96,7 +103,7 @@ export class DataSpace {
96
103
  private readonly _feedStore: FeedStore<FeedMessage>;
97
104
  private readonly _metadataStore: MetadataStore;
98
105
  private readonly _signingContext: SigningContext;
99
- private readonly _notarizationPlugin = new NotarizationPlugin();
106
+ private readonly _notarizationPlugin: NotarizationPlugin;
100
107
  private readonly _callbacks: DataSpaceCallbacks;
101
108
  private readonly _cache?: SpaceCache = undefined;
102
109
  private readonly _echoHost: EchoHost;
@@ -136,6 +143,12 @@ export class DataSpace {
136
143
  this._signingContext = params.signingContext;
137
144
  this._callbacks = params.callbacks ?? {};
138
145
  this._echoHost = params.echoHost;
146
+ this._notarizationPlugin = new NotarizationPlugin({
147
+ spaceId: this._inner.id,
148
+ edgeClient: params.edgeHttpClient,
149
+ edgeFeatures: params.edgeFeatures,
150
+ activeEdgePollingInterval: params.activeEdgeNotarizationPollingInterval,
151
+ });
139
152
 
140
153
  this.authVerifier = new TrustedKeySetAuthVerifier({
141
154
  trustedKeysProvider: () =>
@@ -231,6 +244,7 @@ export class DataSpace {
231
244
  }
232
245
 
233
246
  await this._inner.open(new Context());
247
+ await this._inner.startProtocol();
234
248
 
235
249
  await this._edgeFeedReplicator?.open();
236
250
 
@@ -318,6 +332,7 @@ export class DataSpace {
318
332
  this._state = SpaceState.SPACE_INITIALIZING;
319
333
  log('new state', { state: SpaceState[this._state] });
320
334
 
335
+ log('initializing control pipeline');
321
336
  await this._initializeAndReadControlPipeline();
322
337
 
323
338
  // Allow other tasks to run before loading the data pipeline.
@@ -325,10 +340,13 @@ export class DataSpace {
325
340
 
326
341
  const ready = this.stateUpdate.waitForCondition(() => this._state === SpaceState.SPACE_READY);
327
342
 
343
+ log('initializing automerge root');
328
344
  this._automergeSpaceState.startProcessingRootDocs();
329
345
 
330
346
  // TODO(dmaretskyi): Change so `initializeDataPipeline` doesn't wait for the space to be READY, but rather any state with a valid root.
347
+ log('waiting for space to be ready');
331
348
  await ready;
349
+ log('space is ready');
332
350
  }
333
351
 
334
352
  private async _enterReadyState() {
@@ -345,6 +363,7 @@ export class DataSpace {
345
363
  private async _initializeAndReadControlPipeline() {
346
364
  await this._inner.controlPipeline.state.waitUntilReachedTargetTimeframe({
347
365
  ctx: this._ctx,
366
+ timeout: 10_000,
348
367
  breakOnStall: false,
349
368
  });
350
369
 
@@ -408,8 +427,16 @@ export class DataSpace {
408
427
  }
409
428
 
410
429
  if (credentials.length > 0) {
411
- // Never times out
412
- await this.notarizationPlugin.notarize({ ctx: this._ctx, credentials, timeout: 0 });
430
+ try {
431
+ log('will notarize credentials for feed admission', { count: credentials.length });
432
+ // Never times out
433
+ await this.notarizationPlugin.notarize({ ctx: this._ctx, credentials, timeout: 0 });
434
+
435
+ log('credentials notarized');
436
+ } catch (err) {
437
+ log.error('error notarizing credentials for feed admission', err);
438
+ throw err;
439
+ }
413
440
 
414
441
  // Set this after credentials are notarized so that on failure we will retry.
415
442
  await this._metadataStore.setWritableFeedKeys(this.key, this.inner.controlFeedKey!, this.inner.dataFeedKey!);
@@ -546,6 +573,10 @@ export class DataSpace {
546
573
  this.stateUpdate.emit();
547
574
  }
548
575
 
576
+ getEdgeReplicationSetting() {
577
+ return this._metadataStore.getSpaceEdgeReplicationSetting(this.key);
578
+ }
579
+
549
580
  private _onFeedAdded = async (feed: FeedWrapper<any>) => {
550
581
  await this._edgeFeedReplicator!.addFeed(feed);
551
582
  };