@dxos/client-services 0.4.7-main.731b147 → 0.4.7-main.772b4a3

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 (47) hide show
  1. package/dist/lib/browser/{chunk-XPIRHRIB.mjs → chunk-KGSDIFCK.mjs} +227 -146
  2. package/dist/lib/browser/chunk-KGSDIFCK.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +4 -2
  4. package/dist/lib/browser/index.mjs.map +2 -2
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +4 -2
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-BIYZDTFF.cjs → chunk-3ZHY4PXC.cjs} +216 -135
  9. package/dist/lib/node/chunk-3ZHY4PXC.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +40 -38
  11. package/dist/lib/node/index.cjs.map +2 -2
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/packlets/testing/index.cjs +11 -9
  14. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  15. package/dist/types/src/packlets/devices/devices-service.d.ts +1 -1
  16. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  17. package/dist/types/src/packlets/identity/identity-manager.d.ts +8 -2
  18. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  19. package/dist/types/src/packlets/identity/identity.d.ts +5 -1
  20. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  21. package/dist/types/src/packlets/logging/logging-service.d.ts +1 -0
  22. package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
  23. package/dist/types/src/packlets/services/service-context.d.ts +7 -3
  24. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  25. package/dist/types/src/packlets/services/service-host.d.ts +4 -2
  26. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  27. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +7 -1
  28. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  29. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  30. package/dist/types/src/packlets/vault/shared-worker-connection.d.ts.map +1 -1
  31. package/dist/types/src/version.d.ts +1 -1
  32. package/package.json +35 -35
  33. package/src/packlets/devices/devices-service.test.ts +8 -4
  34. package/src/packlets/devices/devices-service.ts +47 -11
  35. package/src/packlets/identity/identity-manager.ts +48 -6
  36. package/src/packlets/identity/identity.ts +9 -1
  37. package/src/packlets/logging/logging-service.ts +9 -2
  38. package/src/packlets/services/automerge-host.test.ts +1 -1
  39. package/src/packlets/services/service-context.ts +24 -4
  40. package/src/packlets/services/service-host.ts +8 -3
  41. package/src/packlets/spaces/data-space-manager.ts +18 -3
  42. package/src/packlets/spaces/spaces-service.ts +1 -3
  43. package/src/packlets/testing/test-builder.ts +1 -1
  44. package/src/packlets/vault/shared-worker-connection.ts +2 -0
  45. package/src/version.ts +1 -1
  46. package/dist/lib/browser/chunk-XPIRHRIB.mjs.map +0 -7
  47. package/dist/lib/node/chunk-BIYZDTFF.cjs.map +0 -7
@@ -4,8 +4,9 @@
4
4
 
5
5
  import { EventSubscriptions } from '@dxos/async';
6
6
  import { Stream } from '@dxos/codec-protobuf';
7
+ import { invariant } from '@dxos/invariant';
7
8
  import {
8
- type Device,
9
+ Device,
9
10
  DeviceKind,
10
11
  type DevicesService,
11
12
  type QueryDevicesResponse,
@@ -28,27 +29,62 @@ export class DevicesServiceImpl implements DevicesService {
28
29
  if (!deviceKeys) {
29
30
  next({ devices: [] });
30
31
  } else {
32
+ invariant(this._identityManager.identity?.presence, 'presence not present');
33
+ const peers = this._identityManager.identity.presence.getPeersOnline();
31
34
  next({
32
- devices: Array.from(deviceKeys.entries()).map(([key, profile]) => ({
33
- deviceKey: key,
34
- kind: this._identityManager.identity?.deviceKey.equals(key) ? DeviceKind.CURRENT : DeviceKind.TRUSTED,
35
- profile,
36
- })),
35
+ devices: Array.from(deviceKeys.entries()).map(([key, profile]) => {
36
+ const isMe = this._identityManager.identity?.deviceKey.equals(key);
37
+ const peerState = peers.find((peer) => peer.identityKey.equals(key));
38
+
39
+ return {
40
+ deviceKey: key,
41
+ kind: this._identityManager.identity?.deviceKey.equals(key) ? DeviceKind.CURRENT : DeviceKind.TRUSTED,
42
+ profile,
43
+ presence: isMe
44
+ ? Device.PresenceState.ONLINE
45
+ : peerState
46
+ ? Device.PresenceState.ONLINE
47
+ : Device.PresenceState.OFFLINE,
48
+ };
49
+ }),
50
+ });
51
+ }
52
+ };
53
+
54
+ let identitySubscribed = false;
55
+ let presenceSubscribed = false;
56
+ const subscribeIdentity = () => {
57
+ if (!identitySubscribed) {
58
+ this._identityManager.identity?.stateUpdate.on(() => {
59
+ update();
37
60
  });
61
+ identitySubscribed = true;
62
+ }
63
+ };
64
+
65
+ const subscribePresence = () => {
66
+ if (!presenceSubscribed) {
67
+ this._identityManager.identity?.presence?.updated.on(() => {
68
+ update();
69
+ });
70
+ presenceSubscribed = true;
38
71
  }
39
72
  };
40
73
 
41
74
  const subscriptions = new EventSubscriptions();
75
+
76
+ if (this._identityManager.identity) {
77
+ subscribeIdentity();
78
+ subscribePresence();
79
+ }
80
+
42
81
  subscriptions.add(
43
82
  this._identityManager.stateUpdate.on(() => {
44
83
  update();
45
84
 
46
85
  if (this._identityManager.identity) {
47
- subscriptions.add(
48
- this._identityManager.identity.stateUpdate.on(() => {
49
- update();
50
- }),
51
- );
86
+ subscribeIdentity();
87
+ subscribePresence();
52
88
  }
53
89
  }),
54
90
  );
@@ -13,7 +13,7 @@ import { type Keyring } from '@dxos/keyring';
13
13
  import { PublicKey } from '@dxos/keys';
14
14
  import { log } from '@dxos/log';
15
15
  import { trace } from '@dxos/protocols';
16
- import { type Device, DeviceKind } from '@dxos/protocols/proto/dxos/client/services';
16
+ import { Device, DeviceKind } from '@dxos/protocols/proto/dxos/client/services';
17
17
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
18
18
  import { type IdentityRecord, type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
19
19
  import {
@@ -22,6 +22,7 @@ import {
22
22
  DeviceType,
23
23
  type ProfileDocument,
24
24
  } from '@dxos/protocols/proto/dxos/halo/credentials';
25
+ import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
25
26
  import { Timeframe } from '@dxos/timeframe';
26
27
  import { trace as Trace } from '@dxos/tracing';
27
28
  import { isNode, deferFunction } from '@dxos/util';
@@ -29,10 +30,14 @@ import { isNode, deferFunction } from '@dxos/util';
29
30
  import { createAuthProvider } from './authenticator';
30
31
  import { Identity } from './identity';
31
32
 
33
+ const DEVICE_PRESENCE_ANNOUNCE_INTERVAL = 10_000;
34
+ const DEVICE_PRESENCE_OFFLINE_TIMEOUT = 20_000;
35
+
32
36
  interface ConstructSpaceParams {
33
37
  spaceRecord: SpaceMetadata;
34
38
  swarmIdentity: SwarmIdentity;
35
39
  identityKey: PublicKey;
40
+ gossip: Gossip;
36
41
  }
37
42
 
38
43
  export type JoinIdentityParams = {
@@ -58,12 +63,19 @@ export type CreateIdentityOptions = {
58
63
  deviceProfile?: DeviceProfileDocument;
59
64
  };
60
65
 
66
+ export type IdentityManagerRuntimeParams = {
67
+ devicePresenceAnnounceInterval?: number;
68
+ devicePresenceOfflineTimeout?: number;
69
+ };
70
+
61
71
  // TODO(dmaretskyi): Rename: represents the peer's state machine.
62
72
  @Trace.resource()
63
73
  export class IdentityManager {
64
74
  readonly stateUpdate = new Event();
65
75
 
66
76
  private _identity?: Identity;
77
+ private readonly _devicePresenceAnnounceInterval: number;
78
+ private readonly _devicePresenceOfflineTimeout: number;
67
79
 
68
80
  // TODO(burdon): IdentityManagerParams.
69
81
  // TODO(dmaretskyi): Perhaps this should take/generate the peerKey outside of an initialized identity.
@@ -72,7 +84,15 @@ export class IdentityManager {
72
84
  private readonly _keyring: Keyring,
73
85
  private readonly _feedStore: FeedStore<FeedMessage>,
74
86
  private readonly _spaceManager: SpaceManager,
75
- ) {}
87
+ params?: IdentityManagerRuntimeParams,
88
+ ) {
89
+ const {
90
+ devicePresenceAnnounceInterval = DEVICE_PRESENCE_ANNOUNCE_INTERVAL,
91
+ devicePresenceOfflineTimeout = DEVICE_PRESENCE_OFFLINE_TIMEOUT,
92
+ } = params ?? {};
93
+ this._devicePresenceAnnounceInterval = devicePresenceAnnounceInterval;
94
+ this._devicePresenceOfflineTimeout = devicePresenceOfflineTimeout;
95
+ }
76
96
 
77
97
  get identity() {
78
98
  return this._identity;
@@ -284,13 +304,28 @@ export class IdentityManager {
284
304
  const receipt = await this._identity.controlPipeline.writer.write({ credential: { credential } });
285
305
  await this._identity.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
286
306
  this.stateUpdate.emit();
287
- return { deviceKey: this._identity.deviceKey, kind: DeviceKind.CURRENT, profile };
307
+ return {
308
+ deviceKey: this._identity.deviceKey,
309
+ kind: DeviceKind.CURRENT,
310
+ presence: Device.PresenceState.ONLINE,
311
+ profile,
312
+ };
288
313
  }
289
314
 
290
315
  private async _constructIdentity(identityRecord: IdentityRecord) {
291
316
  invariant(!this._identity);
292
317
  log('constructing identity', { identityRecord });
293
318
 
319
+ const gossip = new Gossip({
320
+ localPeerId: identityRecord.deviceKey,
321
+ });
322
+ const presence = new Presence({
323
+ announceInterval: this._devicePresenceAnnounceInterval,
324
+ offlineTimeout: this._devicePresenceOfflineTimeout,
325
+ identityKey: identityRecord.deviceKey,
326
+ gossip,
327
+ });
328
+
294
329
  // Must be created before the space so the feeds are writable.
295
330
  invariant(identityRecord.haloSpace.controlFeedKey);
296
331
  const controlFeed = await this._feedStore.openFeed(identityRecord.haloSpace.controlFeedKey, {
@@ -309,13 +344,15 @@ export class IdentityManager {
309
344
  credentialProvider: createAuthProvider(createCredentialSignerWithKey(this._keyring, identityRecord.deviceKey)),
310
345
  credentialAuthenticator: deferFunction(() => identity.authVerifier.verifier),
311
346
  },
347
+ gossip,
312
348
  identityKey: identityRecord.identityKey,
313
349
  });
314
350
  await space.setControlFeed(controlFeed);
315
- space.setDataFeed(dataFeed);
351
+ void space.setDataFeed(dataFeed); // TODO(dmaretskyi): Should this be awaited?
316
352
 
317
353
  const identity: Identity = new Identity({
318
354
  space,
355
+ presence,
319
356
  signer: this._keyring,
320
357
  identityKey: identityRecord.identityKey,
321
358
  deviceKey: identityRecord.deviceKey,
@@ -331,14 +368,19 @@ export class IdentityManager {
331
368
  return identity;
332
369
  }
333
370
 
334
- private async _constructSpace({ spaceRecord, swarmIdentity, identityKey }: ConstructSpaceParams) {
371
+ private async _constructSpace({ spaceRecord, swarmIdentity, identityKey, gossip }: ConstructSpaceParams) {
335
372
  return this._spaceManager.constructSpace({
336
373
  metadata: {
337
374
  key: spaceRecord.key,
338
375
  genesisFeedKey: spaceRecord.genesisFeedKey,
339
376
  },
340
377
  swarmIdentity,
341
- onAuthorizedConnection: () => {},
378
+ onAuthorizedConnection: (session) => {
379
+ session.addExtension(
380
+ 'dxos.mesh.teleport.gossip',
381
+ gossip.createExtension({ remotePeerId: session.remotePeerId }),
382
+ );
383
+ },
342
384
  onAuthFailure: () => {
343
385
  log.warn('auth failure');
344
386
  },
@@ -25,6 +25,7 @@ import {
25
25
  type ProfileDocument,
26
26
  } from '@dxos/protocols/proto/dxos/halo/credentials';
27
27
  import { type DeviceAdmissionRequest } from '@dxos/protocols/proto/dxos/halo/invitations';
28
+ import { type Presence } from '@dxos/teleport-extension-gossip';
28
29
  import { trace } from '@dxos/tracing';
29
30
  import { type ComplexMap, ComplexSet } from '@dxos/util';
30
31
 
@@ -35,6 +36,7 @@ export type IdentityParams = {
35
36
  deviceKey: PublicKey;
36
37
  signer: Signer;
37
38
  space: Space;
39
+ presence?: Presence;
38
40
  };
39
41
 
40
42
  /**
@@ -44,6 +46,7 @@ export type IdentityParams = {
44
46
  export class Identity {
45
47
  public readonly space: Space;
46
48
  private readonly _signer: Signer;
49
+ private readonly _presence?: Presence;
47
50
  private readonly _deviceStateMachine: DeviceStateMachine;
48
51
  private readonly _profileStateMachine: ProfileStateMachine;
49
52
  public readonly authVerifier: TrustedKeySetAuthVerifier;
@@ -53,9 +56,10 @@ export class Identity {
53
56
 
54
57
  public readonly stateUpdate = new Event();
55
58
 
56
- constructor({ space, signer, identityKey, deviceKey }: IdentityParams) {
59
+ constructor({ space, signer, identityKey, deviceKey, presence }: IdentityParams) {
57
60
  this.space = space;
58
61
  this._signer = signer;
62
+ this._presence = presence;
59
63
 
60
64
  this.identityKey = identityKey;
61
65
  this.deviceKey = deviceKey;
@@ -128,6 +132,10 @@ export class Identity {
128
132
  return this._deviceStateMachine.deviceCredentialChain;
129
133
  }
130
134
 
135
+ get presence() {
136
+ return this._presence;
137
+ }
138
+
131
139
  /**
132
140
  * Issues credentials as identity.
133
141
  * Requires identity to be ready.
@@ -4,6 +4,7 @@
4
4
 
5
5
  import { Event } from '@dxos/async';
6
6
  import { Stream } from '@dxos/codec-protobuf';
7
+ import { PublicKey } from '@dxos/keys';
7
8
  import {
8
9
  type LogLevel,
9
10
  type LogProcessor,
@@ -21,14 +22,15 @@ import {
21
22
  type QueryMetricsRequest,
22
23
  type QueryMetricsResponse,
23
24
  } from '@dxos/protocols/proto/dxos/client/services';
24
- import { jsonify, numericalValues, tracer } from '@dxos/util';
25
+ import { getDebugName, jsonify, numericalValues, tracer } from '@dxos/util';
25
26
 
26
27
  /**
27
28
  * Logging service used to spy on logs of the host.
28
29
  */
29
30
  export class LoggingServiceImpl implements LoggingService {
30
31
  private readonly _logs = new Event<NaturalLogEntry>();
31
- private readonly _started = new Date();
32
+ private readonly _started = Date.now();
33
+ private readonly _sessionId = PublicKey.random().toHex();
32
34
 
33
35
  async open() {
34
36
  log.runtimeConfig.processors.push(this._logProcessor);
@@ -116,6 +118,11 @@ export class LoggingServiceImpl implements LoggingService {
116
118
  // TODO(dmaretskyi): Fix proto.
117
119
  file: entry.meta?.F ?? '',
118
120
  line: entry.meta?.L ?? 0,
121
+ scope: {
122
+ hostSessionId: this._sessionId,
123
+ uptimeSeconds: (Date.now() - this._started) / 1000,
124
+ name: getDebugName(entry.meta?.S),
125
+ },
119
126
  },
120
127
  };
121
128
 
@@ -21,7 +21,7 @@ describe('AutomergeHost', () => {
21
21
 
22
22
  const storageDirectory = createStorage({ type: StorageType.RAM }).createDirectory();
23
23
 
24
- const host = new AutomergeHost(storageDirectory);
24
+ const host = new AutomergeHost({ directory: storageDirectory });
25
25
  afterTest(() => host.close());
26
26
  const dataService = new DataServiceImpl(
27
27
  {} as DataServiceSubscriptions, // is not used in this test, just required argument
@@ -14,6 +14,7 @@ import {
14
14
  SnapshotStore,
15
15
  AutomergeHost,
16
16
  } from '@dxos/echo-pipeline';
17
+ import { IndexMetadataStore } from '@dxos/echo-schema';
17
18
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
18
19
  import { invariant } from '@dxos/invariant';
19
20
  import { Keyring } from '@dxos/keyring';
@@ -31,15 +32,21 @@ import { BlobStore } from '@dxos/teleport-extension-object-sync';
31
32
  import { trace as Trace } from '@dxos/tracing';
32
33
  import { safeInstanceof } from '@dxos/util';
33
34
 
34
- import { type CreateIdentityOptions, IdentityManager, type JoinIdentityParams } from '../identity';
35
+ import {
36
+ type CreateIdentityOptions,
37
+ IdentityManager,
38
+ type IdentityManagerRuntimeParams,
39
+ type JoinIdentityParams,
40
+ } from '../identity';
35
41
  import {
36
42
  DeviceInvitationProtocol,
37
43
  InvitationsHandler,
38
44
  type InvitationProtocol,
39
45
  SpaceInvitationProtocol,
40
46
  } from '../invitations';
41
- import { DataSpaceManager, type SigningContext } from '../spaces';
47
+ import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
42
48
 
49
+ export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams;
43
50
  /**
44
51
  * Shared backend for all client services.
45
52
  */
@@ -62,6 +69,7 @@ export class ServiceContext {
62
69
  public readonly identityManager: IdentityManager;
63
70
  public readonly invitations: InvitationsHandler;
64
71
  public readonly automergeHost: AutomergeHost;
72
+ public readonly indexMetadata: IndexMetadataStore;
65
73
 
66
74
  // Initialized after identity is initialized.
67
75
  public dataSpaceManager?: DataSpaceManager;
@@ -80,9 +88,11 @@ export class ServiceContext {
80
88
  public readonly networkManager: NetworkManager,
81
89
  public readonly signalManager: SignalManager,
82
90
  public readonly modelFactory: ModelFactory,
91
+ public readonly _runtimeParams?: IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams,
83
92
  ) {
84
93
  // TODO(burdon): Move strings to constants.
85
94
  this.metadataStore = new MetadataStore(storage.createDirectory('metadata'));
95
+ this.indexMetadata = new IndexMetadataStore({ directory: storage.createDirectory('index-metadata') });
86
96
  this.snapshotStore = new SnapshotStore(storage.createDirectory('snapshots'));
87
97
  this.blobStore = new BlobStore(storage.createDirectory('blobs'));
88
98
 
@@ -107,9 +117,18 @@ export class ServiceContext {
107
117
  snapshotStore: this.snapshotStore,
108
118
  });
109
119
 
110
- this.identityManager = new IdentityManager(this.metadataStore, this.keyring, this.feedStore, this.spaceManager);
120
+ this.identityManager = new IdentityManager(
121
+ this.metadataStore,
122
+ this.keyring,
123
+ this.feedStore,
124
+ this.spaceManager,
125
+ this._runtimeParams as IdentityManagerRuntimeParams,
126
+ );
111
127
 
112
- this.automergeHost = new AutomergeHost(storage.createDirectory('automerge'));
128
+ this.automergeHost = new AutomergeHost({
129
+ directory: storage.createDirectory('automerge'),
130
+ metadata: this.indexMetadata,
131
+ });
113
132
 
114
133
  this.invitations = new InvitationsHandler(this.networkManager);
115
134
 
@@ -221,6 +240,7 @@ export class ServiceContext {
221
240
  signingContext,
222
241
  this.feedStore,
223
242
  this.automergeHost,
243
+ this._runtimeParams as DataSpaceManagerRuntimeParams,
224
244
  );
225
245
  await this.dataSpaceManager.open();
226
246
 
@@ -8,7 +8,7 @@ import { type Config } from '@dxos/config';
8
8
  import { Context } from '@dxos/context';
9
9
  import { DocumentModel } from '@dxos/document-model';
10
10
  import { DataServiceImpl } from '@dxos/echo-pipeline';
11
- import { type TypedObject, base, getRawDoc, type SpaceDoc } from '@dxos/echo-schema';
11
+ import { type TypedObject, getRawDoc, type SpaceDoc, getAutomergeObjectCore } from '@dxos/echo-schema';
12
12
  import { invariant } from '@dxos/invariant';
13
13
  import { PublicKey } from '@dxos/keys';
14
14
  import { log } from '@dxos/log';
@@ -24,7 +24,7 @@ import { assignDeep } from '@dxos/util';
24
24
  import { WebsocketRpcClient } from '@dxos/websocket-rpc';
25
25
 
26
26
  import { createDiagnostics } from './diagnostics';
27
- import { ServiceContext } from './service-context';
27
+ import { ServiceContext, type ServiceContextRuntimeParams } from './service-context';
28
28
  import { ServiceRegistry } from './service-registry';
29
29
  import { DevicesServiceImpl } from '../devices';
30
30
  import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
@@ -54,6 +54,7 @@ export type ClientServicesHostParams = {
54
54
  storage?: Storage;
55
55
  lockKey?: string;
56
56
  callbacks?: ClientServicesHostCallbacks;
57
+ runtimeParams?: ServiceContextRuntimeParams;
57
58
  };
58
59
 
59
60
  export type ClientServicesHostCallbacks = {
@@ -88,6 +89,7 @@ export class ClientServicesHost {
88
89
  private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
89
90
 
90
91
  private _serviceContext!: ServiceContext;
92
+ private readonly _runtimeParams?: ServiceContextRuntimeParams;
91
93
 
92
94
  @Trace.info()
93
95
  private _opening = false;
@@ -104,10 +106,12 @@ export class ClientServicesHost {
104
106
  // TODO(wittjosiah): Turn this on by default.
105
107
  lockKey,
106
108
  callbacks,
109
+ runtimeParams,
107
110
  }: ClientServicesHostParams = {}) {
108
111
  this._storage = storage;
109
112
  this._modelFactory = modelFactory;
110
113
  this._callbacks = callbacks;
114
+ this._runtimeParams = runtimeParams;
111
115
 
112
116
  if (config) {
113
117
  this.initialize({ config, transportFactory, signalManager });
@@ -239,6 +243,7 @@ export class ClientServicesHost {
239
243
  this._networkManager,
240
244
  this._signalManager,
241
245
  this._modelFactory,
246
+ this._runtimeParams,
242
247
  );
243
248
 
244
249
  this._serviceRegistry.setServices({
@@ -352,7 +357,7 @@ export class ClientServicesHost {
352
357
  await document.whenReady();
353
358
 
354
359
  document.change((doc: SpaceDoc) => {
355
- assignDeep(doc, ['objects', obj[base]._id], getRawDoc(obj).handle.docSync());
360
+ assignDeep(doc, ['objects', getAutomergeObjectCore(obj).id], getRawDoc(obj).handle.docSync());
356
361
  });
357
362
 
358
363
  return identity;
@@ -59,6 +59,11 @@ export type AcceptSpaceOptions = {
59
59
  dataTimeframe?: Timeframe;
60
60
  };
61
61
 
62
+ export type DataSpaceManagerRuntimeParams = {
63
+ spaceMemberPresenceAnnounceInterval?: number;
64
+ spaceMemberPresenceOfflineTimeout?: number;
65
+ };
66
+
62
67
  @trackLeaks('open', 'close')
63
68
  export class DataSpaceManager {
64
69
  private readonly _ctx = new Context();
@@ -69,6 +74,8 @@ export class DataSpaceManager {
69
74
 
70
75
  private _isOpen = false;
71
76
  private readonly _instanceId = PublicKey.random().toHex();
77
+ private readonly _spaceMemberPresenceAnnounceInterval: number;
78
+ private readonly _spaceMemberPresenceOfflineTimeout: number;
72
79
 
73
80
  constructor(
74
81
  private readonly _spaceManager: SpaceManager,
@@ -78,7 +85,15 @@ export class DataSpaceManager {
78
85
  private readonly _signingContext: SigningContext,
79
86
  private readonly _feedStore: FeedStore<FeedMessage>,
80
87
  private readonly _automergeHost: AutomergeHost,
81
- ) {}
88
+ params?: DataSpaceManagerRuntimeParams,
89
+ ) {
90
+ const {
91
+ spaceMemberPresenceAnnounceInterval = PRESENCE_ANNOUNCE_INTERVAL,
92
+ spaceMemberPresenceOfflineTimeout = PRESENCE_OFFLINE_TIMEOUT,
93
+ } = params ?? {};
94
+ this._spaceMemberPresenceAnnounceInterval = spaceMemberPresenceAnnounceInterval;
95
+ this._spaceMemberPresenceOfflineTimeout = spaceMemberPresenceOfflineTimeout;
96
+ }
82
97
 
83
98
  // TODO(burdon): Remove.
84
99
  get spaces() {
@@ -204,8 +219,8 @@ export class DataSpaceManager {
204
219
  localPeerId: this._signingContext.deviceKey,
205
220
  });
206
221
  const presence = new Presence({
207
- announceInterval: PRESENCE_ANNOUNCE_INTERVAL,
208
- offlineTimeout: PRESENCE_OFFLINE_TIMEOUT, // TODO(burdon): Config.
222
+ announceInterval: this._spaceMemberPresenceAnnounceInterval,
223
+ offlineTimeout: this._spaceMemberPresenceOfflineTimeout,
209
224
  identityKey: this._signingContext.identityKey,
210
225
  gossip,
211
226
  });
@@ -215,9 +215,7 @@ export class SpacesServiceImpl implements SpacesService {
215
215
  return {
216
216
  identity: {
217
217
  identityKey: member.key,
218
- profile: {
219
- displayName: member.profile?.displayName,
220
- },
218
+ profile: member.profile ?? {},
221
219
  },
222
220
  presence: member.removed
223
221
  ? SpaceMember.PresenceState.REMOVED
@@ -179,7 +179,7 @@ export class TestPeer {
179
179
  }
180
180
 
181
181
  get automergeHost() {
182
- return (this._props.automergeHost ??= new AutomergeHost(this.storage.createDirectory('automerge')));
182
+ return (this._props.automergeHost ??= new AutomergeHost({ directory: this.storage.createDirectory('automerge') }));
183
183
  }
184
184
 
185
185
  get dataSpaceManager() {
@@ -76,6 +76,8 @@ export class SharedWorkerConnection {
76
76
  BridgeService: this._transportService,
77
77
  },
78
78
  port: this._systemPort,
79
+ // TODO(wittjosiah): Make longer and factor out to constant.
80
+ // TODO(wittjosiah): If this is too long then it breaks the reset flows in Composer.
79
81
  timeout: 200,
80
82
  });
81
83
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.4.7-main.731b147";
1
+ export const DXOS_VERSION = "0.4.7-main.772b4a3";