@dxos/client-services 0.5.9-main.bdf733d → 0.5.9-main.bf0ae3e

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 (45) hide show
  1. package/dist/lib/browser/{chunk-KNGR7BYM.mjs → chunk-4IR3JP4U.mjs} +767 -605
  2. package/dist/lib/browser/chunk-4IR3JP4U.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +1 -1
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +11 -11
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/{chunk-WWHTBQNR.cjs → chunk-ZBIDLLZ4.cjs} +982 -824
  8. package/dist/lib/node/chunk-ZBIDLLZ4.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +42 -42
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/packlets/testing/index.cjs +17 -17
  12. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  13. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +19 -0
  14. package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +1 -0
  15. package/dist/types/src/packlets/identity/identity-service.d.ts +14 -7
  16. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
  17. package/dist/types/src/packlets/identity/identity.d.ts +4 -1
  18. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  19. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  20. package/dist/types/src/packlets/services/service-host.d.ts +1 -1
  21. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  22. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +5 -3
  23. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  24. package/dist/types/src/packlets/spaces/data-space.d.ts +1 -0
  25. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  26. package/dist/types/src/packlets/spaces/spaces-service.d.ts +1 -1
  27. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  28. package/dist/types/src/packlets/testing/test-builder.d.ts +8 -6
  29. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  30. package/dist/types/src/version.d.ts +1 -1
  31. package/package.json +36 -36
  32. package/src/packlets/identity/default-space-state-machine.ts +44 -0
  33. package/src/packlets/identity/identity-service.test.ts +35 -5
  34. package/src/packlets/identity/identity-service.ts +50 -8
  35. package/src/packlets/identity/identity.ts +25 -2
  36. package/src/packlets/services/service-context.ts +1 -4
  37. package/src/packlets/services/service-host.ts +13 -40
  38. package/src/packlets/spaces/data-space-manager.test.ts +46 -1
  39. package/src/packlets/spaces/data-space-manager.ts +54 -25
  40. package/src/packlets/spaces/data-space.ts +24 -5
  41. package/src/packlets/spaces/spaces-service.ts +2 -2
  42. package/src/packlets/testing/test-builder.ts +12 -10
  43. package/src/version.ts +1 -1
  44. package/dist/lib/browser/chunk-KNGR7BYM.mjs.map +0 -7
  45. package/dist/lib/node/chunk-WWHTBQNR.cjs.map +0 -7
@@ -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
  }
@@ -76,6 +76,7 @@ export type DataSpaceParams = {
76
76
 
77
77
  export type CreateEpochOptions = {
78
78
  migration?: CreateEpochRequest.Migration;
79
+ newAutomergeRoot?: string;
79
80
  };
80
81
 
81
82
  @trackLeaks('open', 'close')
@@ -192,10 +193,13 @@ export class DataSpace {
192
193
 
193
194
  @synchronized
194
195
  async open() {
195
- await this._open();
196
+ if (this._state === SpaceState.CLOSED) {
197
+ await this._open();
198
+ }
196
199
  }
197
200
 
198
201
  private async _open() {
202
+ await this._presence.open();
199
203
  await this._gossip.open();
200
204
  await this._notarizationPlugin.open();
201
205
  await this._inner.spaceState.addCredentialProcessor(this._notarizationPlugin);
@@ -227,7 +231,7 @@ export class DataSpace {
227
231
  await this._inner.spaceState.removeCredentialProcessor(this._notarizationPlugin);
228
232
  await this._notarizationPlugin.close();
229
233
 
230
- await this._presence.destroy();
234
+ await this._presence.close();
231
235
  await this._gossip.close();
232
236
  }
233
237
 
@@ -452,6 +456,7 @@ export class DataSpace {
452
456
  const rootHandle = this._echoHost.automergeRepo.find(currentRootUrl as any);
453
457
  await cancelWithContext(this._ctx, asyncTimeout(rootHandle.whenReady(), 10_000));
454
458
  const newRoot = this._echoHost.automergeRepo.create(rootHandle.docSync());
459
+ await this._echoHost.automergeRepo.flush([newRoot.documentId]);
455
460
  invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
456
461
  // TODO(dmaretskyi): Unify epoch construction.
457
462
  epoch = {
@@ -507,6 +512,18 @@ export class DataSpace {
507
512
  };
508
513
  }
509
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;
510
527
  }
511
528
 
512
529
  if (!epoch) {
@@ -526,11 +543,12 @@ export class DataSpace {
526
543
  });
527
544
 
528
545
  await this.inner.controlPipeline.state.waitUntilTimeframe(new Timeframe([[receipt.feedKey, receipt.seq]]));
546
+ await this._echoHost.updateIndexes();
529
547
  }
530
548
 
531
549
  @synchronized
532
550
  async activate() {
533
- if (this._state !== SpaceState.INACTIVE) {
551
+ if (![SpaceState.CLOSED, SpaceState.INACTIVE].includes(this._state)) {
534
552
  return;
535
553
  }
536
554
 
@@ -544,10 +562,11 @@ export class DataSpace {
544
562
  if (this._state === SpaceState.INACTIVE) {
545
563
  return;
546
564
  }
547
-
548
565
  // Unregister from data service.
549
566
  await this._metadataStore.setSpaceState(this.key, SpaceState.INACTIVE);
550
- await this._close();
567
+ if (this._state !== SpaceState.CLOSED) {
568
+ await this._close();
569
+ }
551
570
  this._state = SpaceState.INACTIVE;
552
571
  log('new state', { state: SpaceState[this._state] });
553
572
  this.stateUpdate.emit();
@@ -208,10 +208,10 @@ 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 {
@@ -19,8 +19,8 @@ import { createStorage, StorageType, type Storage } from '@dxos/random-access-st
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,9 +37,11 @@ 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
47
  const networkManager = new SwarmNetworkManager({
@@ -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 = {
@@ -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() {
@@ -156,7 +160,7 @@ export class TestPeer {
156
160
 
157
161
  get networkManager() {
158
162
  return (this._props.networkManager ??= new SwarmNetworkManager({
159
- signalManager: new MemorySignalManager(this.signalContext),
163
+ signalManager: new MemorySignalManager(this._signalContext),
160
164
  transportFactory: MemoryTransportFactory,
161
165
  }));
162
166
  }
@@ -176,10 +180,7 @@ export class TestPeer {
176
180
  }
177
181
 
178
182
  get echoHost() {
179
- return (this._props.echoHost ??= new EchoHost({
180
- kv: this.level,
181
- storage: this.storage,
182
- }));
183
+ return (this._props.echoHost ??= new EchoHost({ kv: this.level }));
183
184
  }
184
185
 
185
186
  get dataSpaceManager(): DataSpaceManager {
@@ -191,6 +192,7 @@ export class TestPeer {
191
192
  this.feedStore,
192
193
  this.echoHost,
193
194
  this.invitationsManager,
195
+ this._opts.dataSpaceParams,
194
196
  ));
195
197
  }
196
198
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.5.9-main.bdf733d";
1
+ export const DXOS_VERSION = "0.5.9-main.bf0ae3e";