@dxos/client-services 0.5.8 → 0.5.9-main.0a0e87d

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 (84) hide show
  1. package/dist/lib/browser/{chunk-JECXTGZA.mjs → chunk-CMZ6YZOX.mjs} +1485 -1315
  2. package/dist/lib/browser/chunk-CMZ6YZOX.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +55 -363
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +13 -12
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-OR7LRWDY.cjs → chunk-CA7UVCON.cjs} +1613 -1447
  9. package/dist/lib/node/chunk-CA7UVCON.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +93 -396
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/packlets/testing/index.cjs +18 -17
  14. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  15. package/dist/types/src/index.d.ts +3 -3
  16. package/dist/types/src/index.d.ts.map +1 -1
  17. package/dist/types/src/packlets/devtools/network.d.ts +4 -4
  18. package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
  19. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +19 -0
  20. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -0
  21. package/dist/types/src/packlets/identity/identity-service.d.ts +14 -7
  22. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  23. package/dist/types/src/packlets/identity/identity.d.ts +4 -1
  24. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  25. package/dist/types/src/packlets/network/network-service.d.ts +2 -2
  26. package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
  27. package/dist/types/src/packlets/services/service-context.d.ts +4 -5
  28. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  29. package/dist/types/src/packlets/services/service-host.d.ts +1 -1
  30. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  31. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +5 -3
  32. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  33. package/dist/types/src/packlets/spaces/data-space.d.ts +2 -0
  34. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  35. package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
  36. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  37. package/dist/types/src/packlets/testing/test-builder.d.ts +11 -9
  38. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  39. package/dist/types/src/packlets/worker/index.d.ts +3 -0
  40. package/dist/types/src/packlets/worker/index.d.ts.map +1 -0
  41. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -0
  42. package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -0
  43. package/dist/types/src/version.d.ts +1 -1
  44. package/dist/types/src/version.d.ts.map +1 -1
  45. package/package.json +36 -36
  46. package/src/index.ts +3 -3
  47. package/src/packlets/devtools/network.ts +4 -4
  48. package/src/packlets/identity/default-space-state-machine.ts +44 -0
  49. package/src/packlets/identity/identity-manager.test.ts +2 -2
  50. package/src/packlets/identity/identity-service.test.ts +35 -5
  51. package/src/packlets/identity/identity-service.ts +50 -8
  52. package/src/packlets/identity/identity.test.ts +8 -4
  53. package/src/packlets/identity/identity.ts +25 -2
  54. package/src/packlets/invitations/invitations-handler.ts +2 -2
  55. package/src/packlets/network/network-service.ts +2 -2
  56. package/src/packlets/services/service-context.ts +3 -3
  57. package/src/packlets/services/service-host.ts +16 -44
  58. package/src/packlets/spaces/data-space-manager.test.ts +46 -1
  59. package/src/packlets/spaces/data-space-manager.ts +54 -25
  60. package/src/packlets/spaces/data-space.ts +35 -6
  61. package/src/packlets/spaces/spaces-service.ts +3 -2
  62. package/src/packlets/testing/test-builder.ts +15 -10
  63. package/src/packlets/worker/index.ts +6 -0
  64. package/src/version.ts +1 -5
  65. package/dist/lib/browser/chunk-JECXTGZA.mjs.map +0 -7
  66. package/dist/lib/node/chunk-OR7LRWDY.cjs.map +0 -7
  67. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +0 -37
  68. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +0 -1
  69. package/dist/types/src/packlets/vault/index.d.ts +0 -6
  70. package/dist/types/src/packlets/vault/index.d.ts.map +0 -1
  71. package/dist/types/src/packlets/vault/shared-worker-connection.d.ts +0 -36
  72. package/dist/types/src/packlets/vault/shared-worker-connection.d.ts.map +0 -1
  73. package/dist/types/src/packlets/vault/shell-runtime.d.ts +0 -33
  74. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +0 -1
  75. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +0 -1
  76. package/dist/types/src/packlets/vault/worker-session.d.ts.map +0 -1
  77. package/src/packlets/vault/iframe-host-runtime.ts +0 -130
  78. package/src/packlets/vault/index.ts +0 -9
  79. package/src/packlets/vault/shared-worker-connection.ts +0 -115
  80. package/src/packlets/vault/shell-runtime.ts +0 -111
  81. /package/dist/types/src/packlets/{vault → worker}/worker-runtime.d.ts +0 -0
  82. /package/dist/types/src/packlets/{vault → worker}/worker-session.d.ts +0 -0
  83. /package/src/packlets/{vault → worker}/worker-runtime.ts +0 -0
  84. /package/src/packlets/{vault → worker}/worker-session.ts +0 -0
@@ -9,7 +9,7 @@ import { createKeyPair, sign } from '@dxos/crypto';
9
9
  import { invariant } from '@dxos/invariant';
10
10
  import { PublicKey } from '@dxos/keys';
11
11
  import { log } from '@dxos/log';
12
- import { createTeleportProtocolFactory, type NetworkManager, type SwarmConnection } from '@dxos/network-manager';
12
+ import { createTeleportProtocolFactory, type SwarmNetworkManager, type SwarmConnection } from '@dxos/network-manager';
13
13
  import { InvalidInvitationExtensionRoleError, trace } from '@dxos/protocols';
14
14
  import { type AdmissionKeypair, Invitation } from '@dxos/protocols/proto/dxos/client/services';
15
15
  import { type DeviceProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
@@ -61,7 +61,7 @@ export class InvitationsHandler {
61
61
  * @internal
62
62
  */
63
63
  constructor(
64
- private readonly _networkManager: NetworkManager,
64
+ private readonly _networkManager: SwarmNetworkManager,
65
65
  private readonly _defaultTeleportParams?: Partial<TeleportParams>,
66
66
  ) {}
67
67
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Stream } from '@dxos/codec-protobuf';
6
6
  import { type SignalManager } from '@dxos/messaging';
7
- import { type NetworkManager } from '@dxos/network-manager';
7
+ import { type SwarmNetworkManager } from '@dxos/network-manager';
8
8
  import {
9
9
  type NetworkService,
10
10
  type NetworkStatus,
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  export class NetworkServiceImpl implements NetworkService {
15
15
  constructor(
16
- private readonly networkManager: NetworkManager,
16
+ private readonly networkManager: SwarmNetworkManager,
17
17
  private readonly signalManager: SignalManager,
18
18
  ) {}
19
19
 
@@ -15,7 +15,7 @@ import { PublicKey } from '@dxos/keys';
15
15
  import { type LevelDB } from '@dxos/kv-store';
16
16
  import { log } from '@dxos/log';
17
17
  import { type SignalManager } from '@dxos/messaging';
18
- import { type NetworkManager } from '@dxos/network-manager';
18
+ import { type SwarmNetworkManager } from '@dxos/network-manager';
19
19
  import { InvalidStorageVersionError, STORAGE_VERSION, trace } from '@dxos/protocols';
20
20
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
21
21
  import type { FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
@@ -35,10 +35,10 @@ import {
35
35
  import {
36
36
  DeviceInvitationProtocol,
37
37
  InvitationsHandler,
38
+ InvitationsManager,
38
39
  SpaceInvitationProtocol,
39
40
  type InvitationProtocol,
40
41
  } from '../invitations';
41
- import { InvitationsManager } from '../invitations/invitations-manager';
42
42
  import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
43
43
 
44
44
  export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams &
@@ -81,7 +81,7 @@ export class ServiceContext extends Resource {
81
81
  constructor(
82
82
  public readonly storage: Storage,
83
83
  public readonly level: LevelDB,
84
- public readonly networkManager: NetworkManager,
84
+ public readonly networkManager: SwarmNetworkManager,
85
85
  public readonly signalManager: SignalManager,
86
86
  public readonly _runtimeParams?: ServiceContextRuntimeParams,
87
87
  ) {
@@ -3,22 +3,19 @@
3
3
  //
4
4
 
5
5
  import { Event, synchronized } from '@dxos/async';
6
- import { clientServiceBundle, defaultKey, type ClientServices, Properties } from '@dxos/client-protocol';
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 { type ObjectStructure, encodeReference, type SpaceDoc } from '@dxos/echo-protocol';
10
- import { getTypeReference } from '@dxos/echo-schema';
11
9
  import { invariant } from '@dxos/invariant';
12
10
  import { PublicKey } from '@dxos/keys';
13
11
  import { type LevelDB } from '@dxos/kv-store';
14
12
  import { log } from '@dxos/log';
15
13
  import { WebsocketSignalManager, type SignalManager } from '@dxos/messaging';
16
- import { NetworkManager, createSimplePeerTransportFactory, type TransportFactory } from '@dxos/network-manager';
14
+ import { SwarmNetworkManager, createSimplePeerTransportFactory, type TransportFactory } from '@dxos/network-manager';
17
15
  import { trace } from '@dxos/protocols';
18
16
  import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
19
17
  import { type Storage } from '@dxos/random-access-storage';
20
18
  import { TRACE_PROCESSOR, trace as Trace } from '@dxos/tracing';
21
- import { assignDeep } from '@dxos/util';
22
19
  import { WebsocketRpcClient } from '@dxos/websocket-rpc';
23
20
 
24
21
  import { ServiceContext, type ServiceContextRuntimeParams } from './service-context';
@@ -79,14 +76,14 @@ export class ClientServicesHost {
79
76
  private _config?: Config;
80
77
  private readonly _statusUpdate = new Event<void>();
81
78
  private _signalManager?: SignalManager;
82
- private _networkManager?: NetworkManager;
79
+ private _networkManager?: SwarmNetworkManager;
83
80
  private _storage?: Storage;
84
81
  private _level?: LevelDB;
85
82
  private _callbacks?: ClientServicesHostCallbacks;
86
83
  private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
87
84
 
88
85
  private _serviceContext!: ServiceContext;
89
- private readonly _runtimeParams?: ServiceContextRuntimeParams;
86
+ private readonly _runtimeParams: ServiceContextRuntimeParams;
90
87
  private diagnosticsBroadcastHandler: CollectDiagnosticsBroadcastHandler;
91
88
 
92
89
  @Trace.info()
@@ -109,7 +106,7 @@ export class ClientServicesHost {
109
106
  this._storage = storage;
110
107
  this._level = level;
111
108
  this._callbacks = callbacks;
112
- this._runtimeParams = runtimeParams;
109
+ this._runtimeParams = runtimeParams ?? {};
113
110
 
114
111
  if (config) {
115
112
  this.initialize({ config, transportFactory, signalManager });
@@ -210,7 +207,7 @@ export class ClientServicesHost {
210
207
  this._signalManager = signalManager;
211
208
 
212
209
  invariant(!this._networkManager, 'network manager already set');
213
- this._networkManager = new NetworkManager({
210
+ this._networkManager = new SwarmNetworkManager({
214
211
  log: connectionLog,
215
212
  transportFactory,
216
213
  signalManager,
@@ -254,15 +251,17 @@ export class ClientServicesHost {
254
251
  this._runtimeParams,
255
252
  );
256
253
 
254
+ const identityService = new IdentityServiceImpl(
255
+ this._serviceContext.identityManager,
256
+ this._serviceContext.keyring,
257
+ () => this._serviceContext.dataSpaceManager!,
258
+ (params) => this._createIdentity(params),
259
+ (profile) => this._serviceContext.broadcastProfileUpdate(profile),
260
+ );
261
+
257
262
  this._serviceRegistry.setServices({
258
263
  SystemService: this._systemService,
259
-
260
- IdentityService: new IdentityServiceImpl(
261
- (params) => this._createIdentity(params),
262
- this._serviceContext.identityManager,
263
- this._serviceContext.keyring,
264
- (profile) => this._serviceContext.broadcastProfileUpdate(profile),
265
- ),
264
+ IdentityService: identityService,
266
265
 
267
266
  InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitationsManager),
268
267
 
@@ -294,6 +293,7 @@ export class ClientServicesHost {
294
293
  });
295
294
 
296
295
  await this._serviceContext.open(ctx);
296
+ await identityService.open();
297
297
 
298
298
  const devtoolsProxy = this._config?.get('runtime.client.devtoolsProxy');
299
299
  if (devtoolsProxy) {
@@ -349,35 +349,7 @@ export class ClientServicesHost {
349
349
 
350
350
  private async _createIdentity(params: CreateIdentityOptions) {
351
351
  const identity = await this._serviceContext.createIdentity(params);
352
-
353
- // Setup default space.
354
352
  await this._serviceContext.initialized.wait();
355
- const space = await this._serviceContext.dataSpaceManager!.createSpace();
356
-
357
- const automergeIndex = space.automergeSpaceState.rootUrl;
358
- invariant(automergeIndex);
359
- const document = await this._serviceContext.echoHost.automergeRepo.find<SpaceDoc>(automergeIndex as any);
360
- await document.whenReady();
361
-
362
- // TODO(dmaretskyi): Better API for low-level data access.
363
- const properties: ObjectStructure = {
364
- system: {
365
- type: encodeReference(getTypeReference(Properties)!),
366
- },
367
- data: {
368
- [defaultKey]: identity.identityKey.toHex(),
369
- },
370
- meta: {
371
- keys: [],
372
- },
373
- };
374
- const propertiesId = PublicKey.random().toHex();
375
- document.change((doc: SpaceDoc) => {
376
- assignDeep(doc, ['objects', propertiesId], properties);
377
- });
378
-
379
- await this._serviceContext.echoHost.flush();
380
-
381
353
  return identity;
382
354
  }
383
355
  }
@@ -12,7 +12,7 @@ import { log } from '@dxos/log';
12
12
  import { SpaceState } from '@dxos/protocols/proto/dxos/client/services';
13
13
  import { describe, openAndClose, test } from '@dxos/test';
14
14
 
15
- import { TestBuilder } from '../testing';
15
+ import { TestBuilder, type TestPeer } from '../testing';
16
16
 
17
17
  describe('DataSpaceManager', () => {
18
18
  test('create space', async () => {
@@ -168,5 +168,50 @@ describe('DataSpaceManager', () => {
168
168
  500,
169
169
  );
170
170
  });
171
+
172
+ test('activate opens a lazily loaded space', async () => {
173
+ const builder = new TestBuilder();
174
+
175
+ const peer = builder.createPeer();
176
+ await peer.createIdentity();
177
+ await openAndClose(peer.echoHost, peer.dataSpaceManager);
178
+
179
+ await peer.dataSpaceManager.createSpace();
180
+ await reloadDataSpaces(peer);
181
+
182
+ const space = getFirstSpace(peer);
183
+ expect(space.state).to.equal(SpaceState.CLOSED);
184
+ await space.activate();
185
+ await asyncTimeout(
186
+ space.stateUpdate.waitForCondition(() => space.state === SpaceState.READY),
187
+ 500,
188
+ );
189
+ });
190
+
191
+ test('deactivate lazily loaded space ', async () => {
192
+ const builder = new TestBuilder();
193
+
194
+ const peer = builder.createPeer();
195
+ await peer.createIdentity();
196
+ await openAndClose(peer.echoHost, peer.dataSpaceManager);
197
+
198
+ await peer.dataSpaceManager.createSpace();
199
+ await reloadDataSpaces(peer);
200
+
201
+ await getFirstSpace(peer).deactivate();
202
+
203
+ await reloadDataSpaces(peer);
204
+
205
+ expect(getFirstSpace(peer).state).to.eq(SpaceState.INACTIVE);
206
+ });
171
207
  });
208
+
209
+ const reloadDataSpaces = async (peer: TestPeer) => {
210
+ await peer.dataSpaceManager.close();
211
+ await peer.dataSpaceManager.open();
212
+ };
213
+
214
+ const getFirstSpace = (peer: TestPeer) => {
215
+ return Array.from(peer.dataSpaceManager.spaces.values())[0];
216
+ };
172
217
  });
@@ -4,7 +4,8 @@
4
4
 
5
5
  import { Event, synchronized, trackLeaks } from '@dxos/async';
6
6
  import { type Doc } from '@dxos/automerge/automerge';
7
- import { type AutomergeUrl } from '@dxos/automerge/automerge-repo';
7
+ import { type DocHandle, type AutomergeUrl } from '@dxos/automerge/automerge-repo';
8
+ import { PropertiesType } from '@dxos/client-protocol';
8
9
  import { cancelWithContext, Context } from '@dxos/context';
9
10
  import {
10
11
  type CredentialSigner,
@@ -21,7 +22,8 @@ import {
21
22
  type SpaceProtocol,
22
23
  type SpaceProtocolSession,
23
24
  } from '@dxos/echo-pipeline';
24
- import { type SpaceDoc } from '@dxos/echo-protocol';
25
+ import { encodeReference, type ObjectStructure, type SpaceDoc } from '@dxos/echo-protocol';
26
+ import { getTypeReference } from '@dxos/echo-schema';
25
27
  import { type FeedStore } from '@dxos/feed-store';
26
28
  import { invariant } from '@dxos/invariant';
27
29
  import { type Keyring } from '@dxos/keyring';
@@ -37,7 +39,7 @@ import { type PeerState } from '@dxos/protocols/proto/dxos/mesh/presence';
37
39
  import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
38
40
  import { type Timeframe } from '@dxos/timeframe';
39
41
  import { trace } from '@dxos/tracing';
40
- import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
42
+ import { assignDeep, ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
41
43
 
42
44
  import { DataSpace, findPropertiesObject } from './data-space';
43
45
  import { spaceGenesis } from './genesis';
@@ -47,6 +49,9 @@ import { type InvitationsManager } from '../invitations';
47
49
  const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
48
50
  const PRESENCE_OFFLINE_TIMEOUT = 20_000;
49
51
 
52
+ // Space properties key for default metadata.
53
+ const DEFAULT_SPACE_KEY = '__DEFAULT__';
54
+
50
55
  export interface SigningContext {
51
56
  identityKey: PublicKey;
52
57
  deviceKey: PublicKey;
@@ -88,8 +93,6 @@ export class DataSpaceManager {
88
93
 
89
94
  private _isOpen = false;
90
95
  private readonly _instanceId = PublicKey.random().toHex();
91
- private readonly _spaceMemberPresenceAnnounceInterval: number;
92
- private readonly _spaceMemberPresenceOfflineTimeout: number;
93
96
 
94
97
  constructor(
95
98
  private readonly _spaceManager: SpaceManager,
@@ -99,15 +102,8 @@ export class DataSpaceManager {
99
102
  private readonly _feedStore: FeedStore<FeedMessage>,
100
103
  private readonly _echoHost: EchoHost,
101
104
  private readonly _invitationsManager: InvitationsManager,
102
- params?: DataSpaceManagerRuntimeParams,
105
+ private readonly _params?: DataSpaceManagerRuntimeParams,
103
106
  ) {
104
- const {
105
- spaceMemberPresenceAnnounceInterval = PRESENCE_ANNOUNCE_INTERVAL,
106
- spaceMemberPresenceOfflineTimeout = PRESENCE_OFFLINE_TIMEOUT,
107
- } = params ?? {};
108
- this._spaceMemberPresenceAnnounceInterval = spaceMemberPresenceAnnounceInterval;
109
- this._spaceMemberPresenceOfflineTimeout = spaceMemberPresenceOfflineTimeout;
110
-
111
107
  trace.diagnostic({
112
108
  id: 'spaces',
113
109
  name: 'Spaces',
@@ -157,12 +153,6 @@ export class DataSpaceManager {
157
153
  this._isOpen = true;
158
154
  this.updated.emit();
159
155
 
160
- for (const space of this._spaces.values()) {
161
- if (space.state !== SpaceState.INACTIVE) {
162
- space.initializeDataPipelineAsync();
163
- }
164
- }
165
-
166
156
  log.trace('dxos.echo.data-space-manager.open', Trace.end({ id: this._instanceId }));
167
157
  }
168
158
 
@@ -174,6 +164,7 @@ export class DataSpaceManager {
174
164
  for (const space of this._spaces.values()) {
175
165
  await space.close();
176
166
  }
167
+ this._spaces.clear();
177
168
  }
178
169
 
179
170
  /**
@@ -197,6 +188,7 @@ export class DataSpaceManager {
197
188
 
198
189
  const root = await this._echoHost.createSpaceRoot(spaceKey);
199
190
  const space = await this._constructSpace(metadata);
191
+ await space.open();
200
192
 
201
193
  const credentials = await spaceGenesis(this._keyring, this._signingContext, space.inner, root.url);
202
194
  await this._metadataStore.addSpace(metadata);
@@ -211,6 +203,46 @@ export class DataSpaceManager {
211
203
  return space;
212
204
  }
213
205
 
206
+ async isDefaultSpace(space: DataSpace): Promise<boolean> {
207
+ const rootDoc = await this._getSpaceRootDocument(space);
208
+ const [_, properties] = findPropertiesObject(rootDoc.docSync()) ?? [];
209
+ return properties?.data?.[DEFAULT_SPACE_KEY] === this._signingContext.identityKey.toHex();
210
+ }
211
+
212
+ async createDefaultSpace() {
213
+ const space = await this.createSpace();
214
+ const document = await this._getSpaceRootDocument(space);
215
+
216
+ // TODO(dmaretskyi): Better API for low-level data access.
217
+ const properties: ObjectStructure = {
218
+ system: {
219
+ type: encodeReference(getTypeReference(PropertiesType)!),
220
+ },
221
+ data: {
222
+ [DEFAULT_SPACE_KEY]: this._signingContext.identityKey.toHex(),
223
+ },
224
+ meta: {
225
+ keys: [],
226
+ },
227
+ };
228
+
229
+ const propertiesId = PublicKey.random().toHex();
230
+ document.change((doc: SpaceDoc) => {
231
+ assignDeep(doc, ['objects', propertiesId], properties);
232
+ });
233
+
234
+ await this._echoHost.flush();
235
+ return space;
236
+ }
237
+
238
+ private async _getSpaceRootDocument(space: DataSpace): Promise<DocHandle<SpaceDoc>> {
239
+ const automergeIndex = space.automergeSpaceState.rootUrl;
240
+ invariant(automergeIndex);
241
+ const document = this._echoHost.automergeRepo.find<SpaceDoc>(automergeIndex as any);
242
+ await document.whenReady();
243
+ return document;
244
+ }
245
+
214
246
  // TODO(burdon): Rename join space.
215
247
  @synchronized
216
248
  async acceptSpace(opts: AcceptSpaceOptions): Promise<DataSpace> {
@@ -226,6 +258,7 @@ export class DataSpaceManager {
226
258
  };
227
259
 
228
260
  const space = await this._constructSpace(metadata);
261
+ await space.open();
229
262
  await this._metadataStore.addSpace(metadata);
230
263
  space.initializeDataPipelineAsync();
231
264
 
@@ -254,8 +287,8 @@ export class DataSpaceManager {
254
287
  localPeerId: this._signingContext.deviceKey,
255
288
  });
256
289
  const presence = new Presence({
257
- announceInterval: this._spaceMemberPresenceAnnounceInterval,
258
- offlineTimeout: this._spaceMemberPresenceOfflineTimeout,
290
+ announceInterval: this._params?.spaceMemberPresenceAnnounceInterval ?? PRESENCE_ANNOUNCE_INTERVAL,
291
+ offlineTimeout: this._params?.spaceMemberPresenceOfflineTimeout ?? PRESENCE_OFFLINE_TIMEOUT,
259
292
  identityKey: this._signingContext.identityKey,
260
293
  gossip,
261
294
  });
@@ -336,10 +369,6 @@ export class DataSpaceManager {
336
369
  }
337
370
  });
338
371
 
339
- if (metadata.state !== SpaceState.INACTIVE) {
340
- await dataSpace.open();
341
- }
342
-
343
372
  if (metadata.controlTimeframe) {
344
373
  dataSpace.inner.controlPipeline.state.setTargetTimeframe(metadata.controlTimeframe);
345
374
  }
@@ -9,6 +9,7 @@ import { timed, warnAfterTimeout } from '@dxos/debug';
9
9
  import { type EchoHost } from '@dxos/echo-db';
10
10
  import {
11
11
  AutomergeDocumentLoaderImpl,
12
+ createIdFromSpaceKey,
12
13
  createMappedFeedWriter,
13
14
  type MetadataStore,
14
15
  type Space,
@@ -75,6 +76,7 @@ export type DataSpaceParams = {
75
76
 
76
77
  export type CreateEpochOptions = {
77
78
  migration?: CreateEpochRequest.Migration;
79
+ newAutomergeRoot?: string;
78
80
  };
79
81
 
80
82
  @trackLeaks('open', 'close')
@@ -141,6 +143,11 @@ export class DataSpace {
141
143
  log('new state', { state: SpaceState[this._state] });
142
144
  }
143
145
 
146
+ @trace.info()
147
+ get id() {
148
+ return this._inner.id;
149
+ }
150
+
144
151
  @trace.info()
145
152
  get key() {
146
153
  return this._inner.key;
@@ -186,10 +193,13 @@ export class DataSpace {
186
193
 
187
194
  @synchronized
188
195
  async open() {
189
- await this._open();
196
+ if (this._state === SpaceState.CLOSED) {
197
+ await this._open();
198
+ }
190
199
  }
191
200
 
192
201
  private async _open() {
202
+ await this._presence.open();
193
203
  await this._gossip.open();
194
204
  await this._notarizationPlugin.open();
195
205
  await this._inner.spaceState.addCredentialProcessor(this._notarizationPlugin);
@@ -221,7 +231,7 @@ export class DataSpace {
221
231
  await this._inner.spaceState.removeCredentialProcessor(this._notarizationPlugin);
222
232
  await this._notarizationPlugin.close();
223
233
 
224
- await this._presence.destroy();
234
+ await this._presence.close();
225
235
  await this._gossip.close();
226
236
  }
227
237
 
@@ -446,6 +456,7 @@ export class DataSpace {
446
456
  const rootHandle = this._echoHost.automergeRepo.find(currentRootUrl as any);
447
457
  await cancelWithContext(this._ctx, asyncTimeout(rootHandle.whenReady(), 10_000));
448
458
  const newRoot = this._echoHost.automergeRepo.create(rootHandle.docSync());
459
+ await this._echoHost.automergeRepo.flush([newRoot.documentId]);
449
460
  invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
450
461
  // TODO(dmaretskyi): Unify epoch construction.
451
462
  epoch = {
@@ -476,7 +487,11 @@ export class DataSpace {
476
487
  invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
477
488
 
478
489
  // Create new automerge documents for all objects.
479
- const docLoader = new AutomergeDocumentLoaderImpl(this.key, this._echoHost.automergeRepo);
490
+ const docLoader = new AutomergeDocumentLoaderImpl(
491
+ await createIdFromSpaceKey(this.key),
492
+ this._echoHost.automergeRepo,
493
+ this.key,
494
+ );
480
495
  await docLoader.loadSpaceRootDocHandle(this._ctx, { rootUrl: newRoot.url });
481
496
 
482
497
  otherObjects.forEach(([key, value]) => {
@@ -497,6 +512,18 @@ export class DataSpace {
497
512
  };
498
513
  }
499
514
  break;
515
+ case CreateEpochRequest.Migration.REPLACE_AUTOMERGE_ROOT:
516
+ {
517
+ invariant(options.newAutomergeRoot);
518
+ // TODO(dmaretskyi): Unify epoch construction.
519
+ epoch = {
520
+ previousId: this._automergeSpaceState.lastEpoch?.id,
521
+ number: (this._automergeSpaceState.lastEpoch?.subject.assertion.number ?? -1) + 1,
522
+ timeframe: this._automergeSpaceState.lastEpoch?.subject.assertion.timeframe ?? new Timeframe(),
523
+ automergeRoot: options.newAutomergeRoot,
524
+ };
525
+ }
526
+ break;
500
527
  }
501
528
 
502
529
  if (!epoch) {
@@ -516,11 +543,12 @@ export class DataSpace {
516
543
  });
517
544
 
518
545
  await this.inner.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
546
+ await this._echoHost.updateIndexes();
519
547
  }
520
548
 
521
549
  @synchronized
522
550
  async activate() {
523
- if (this._state !== SpaceState.INACTIVE) {
551
+ if (![SpaceState.CLOSED, SpaceState.INACTIVE].includes(this._state)) {
524
552
  return;
525
553
  }
526
554
 
@@ -534,10 +562,11 @@ export class DataSpace {
534
562
  if (this._state === SpaceState.INACTIVE) {
535
563
  return;
536
564
  }
537
-
538
565
  // Unregister from data service.
539
566
  await this._metadataStore.setSpaceState(this.key, SpaceState.INACTIVE);
540
- await this._close();
567
+ if (this._state !== SpaceState.CLOSED) {
568
+ await this._close();
569
+ }
541
570
  this._state = SpaceState.INACTIVE;
542
571
  log('new state', { state: SpaceState[this._state] });
543
572
  this.stateUpdate.emit();
@@ -208,14 +208,15 @@ export class SpacesServiceImpl implements SpacesService {
208
208
  }
209
209
  }
210
210
 
211
- async createEpoch({ spaceKey, migration }: CreateEpochRequest) {
211
+ async createEpoch({ spaceKey, migration, automergeRootUrl }: CreateEpochRequest) {
212
212
  const dataSpaceManager = await this._getDataSpaceManager();
213
213
  const space = dataSpaceManager.spaces.get(spaceKey) ?? raise(new SpaceNotFoundError(spaceKey));
214
- await space.createEpoch({ migration });
214
+ await space.createEpoch({ migration, newAutomergeRoot: automergeRootUrl });
215
215
  }
216
216
 
217
217
  private _serializeSpace(space: DataSpace): Space {
218
218
  return {
219
+ id: space.id,
219
220
  spaceKey: space.key,
220
221
  state: space.state,
221
222
  error: space.error ? encodeError(space.error) : undefined,
@@ -13,14 +13,14 @@ import { Keyring } from '@dxos/keyring';
13
13
  import { type LevelDB } from '@dxos/kv-store';
14
14
  import { createTestLevel } from '@dxos/kv-store/testing';
15
15
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
16
- import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
16
+ import { MemoryTransportFactory, SwarmNetworkManager } from '@dxos/network-manager';
17
17
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
18
18
  import { createStorage, StorageType, type Storage } from '@dxos/random-access-storage';
19
19
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
20
20
 
21
21
  import { InvitationsHandler, InvitationsManager, SpaceInvitationProtocol } from '../invitations';
22
- import { ClientServicesHost, ServiceContext } from '../services';
23
- import { DataSpaceManager, type SigningContext } from '../spaces';
22
+ import { ClientServicesHost, ServiceContext, type ServiceContextRuntimeParams } from '../services';
23
+ import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
24
24
 
25
25
  //
26
26
  // TODO(burdon): Replace with test builder.
@@ -37,12 +37,14 @@ export const createServiceHost = (config: Config, signalManagerContext: MemorySi
37
37
  export const createServiceContext = async ({
38
38
  signalContext = new MemorySignalManagerContext(),
39
39
  storage = createStorage({ type: StorageType.RAM }),
40
+ runtimeParams,
40
41
  }: {
41
42
  signalContext?: MemorySignalManagerContext;
42
43
  storage?: Storage;
44
+ runtimeParams?: ServiceContextRuntimeParams;
43
45
  } = {}) => {
44
46
  const signalManager = new MemorySignalManager(signalContext);
45
- const networkManager = new NetworkManager({
47
+ const networkManager = new SwarmNetworkManager({
46
48
  signalManager,
47
49
  transportFactory: MemoryTransportFactory,
48
50
  });
@@ -51,6 +53,7 @@ export const createServiceContext = async ({
51
53
 
52
54
  return new ServiceContext(storage, level, networkManager, signalManager, {
53
55
  invitationConnectionDefaultParams: { controlHeartbeatInterval: 200 },
56
+ ...runtimeParams,
54
57
  });
55
58
  };
56
59
 
@@ -88,6 +91,7 @@ export class TestBuilder {
88
91
 
89
92
  export type TestPeerOpts = {
90
93
  dataStore?: StorageType;
94
+ dataSpaceParams?: DataSpaceManagerRuntimeParams;
91
95
  };
92
96
 
93
97
  export type TestPeerProps = {
@@ -96,7 +100,7 @@ export type TestPeerProps = {
96
100
  feedStore?: FeedStore<any>;
97
101
  metadataStore?: MetadataStore;
98
102
  keyring?: Keyring;
99
- networkManager?: NetworkManager;
103
+ networkManager?: SwarmNetworkManager;
100
104
  spaceManager?: SpaceManager;
101
105
  dataSpaceManager?: DataSpaceManager;
102
106
  snapshotStore?: SnapshotStore;
@@ -110,8 +114,8 @@ export class TestPeer {
110
114
  private _props: TestPeerProps = {};
111
115
 
112
116
  constructor(
113
- private readonly signalContext: MemorySignalManagerContext,
114
- private readonly opts: TestPeerOpts = { dataStore: StorageType.RAM },
117
+ private readonly _signalContext: MemorySignalManagerContext,
118
+ private readonly _opts: TestPeerOpts = { dataStore: StorageType.RAM },
115
119
  ) {}
116
120
 
117
121
  get props() {
@@ -119,7 +123,7 @@ export class TestPeer {
119
123
  }
120
124
 
121
125
  get storage() {
122
- return (this._props.storage ??= createStorage({ type: this.opts.dataStore }));
126
+ return (this._props.storage ??= createStorage({ type: this._opts.dataStore }));
123
127
  }
124
128
 
125
129
  get keyring() {
@@ -155,8 +159,8 @@ export class TestPeer {
155
159
  }
156
160
 
157
161
  get networkManager() {
158
- return (this._props.networkManager ??= new NetworkManager({
159
- signalManager: new MemorySignalManager(this.signalContext),
162
+ return (this._props.networkManager ??= new SwarmNetworkManager({
163
+ signalManager: new MemorySignalManager(this._signalContext),
160
164
  transportFactory: MemoryTransportFactory,
161
165
  }));
162
166
  }
@@ -191,6 +195,7 @@ export class TestPeer {
191
195
  this.feedStore,
192
196
  this.echoHost,
193
197
  this.invitationsManager,
198
+ this._opts.dataSpaceParams,
194
199
  ));
195
200
  }
196
201
 
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ export * from './worker-runtime';
6
+ export * from './worker-session';
package/src/version.ts CHANGED
@@ -1,5 +1 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- export const DXOS_VERSION = '0.5.8'; // {x-release-please-version}
1
+ export const DXOS_VERSION = "0.5.9-main.0a0e87d";