@dxos/client-services 0.4.10-main.fe71b4c → 0.4.10-next.169e4e3

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 (63) hide show
  1. package/dist/lib/browser/{chunk-7S34JE6M.mjs → chunk-KCCL73B5.mjs} +625 -508
  2. package/dist/lib/browser/chunk-KCCL73B5.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3 -1
  4. package/dist/lib/browser/index.mjs.map +1 -1
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/packlets/testing/index.mjs +125 -112
  7. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  8. package/dist/lib/node/{chunk-DQMGKBOV.cjs → chunk-2EUUFY7P.cjs} +694 -578
  9. package/dist/lib/node/chunk-2EUUFY7P.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +44 -42
  11. package/dist/lib/node/index.cjs.map +1 -1
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/packlets/testing/index.cjs +125 -115
  14. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  15. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  16. package/dist/types/src/packlets/indexing/util.d.ts +0 -5
  17. package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
  18. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +3 -1
  19. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  20. package/dist/types/src/packlets/invitations/index.d.ts +1 -0
  21. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  22. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +6 -1
  23. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  24. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +4 -2
  25. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  26. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +44 -0
  27. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -0
  28. package/dist/types/src/packlets/invitations/invitations-service.d.ts +7 -23
  29. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  30. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -1
  31. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  32. package/dist/types/src/packlets/services/service-context.d.ts +2 -0
  33. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  34. package/dist/types/src/packlets/services/service-host.d.ts +1 -0
  35. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  36. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +5 -1
  37. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  38. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  39. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  40. package/dist/types/src/packlets/testing/test-builder.d.ts +3 -0
  41. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  42. package/dist/types/src/version.d.ts +1 -1
  43. package/package.json +34 -34
  44. package/src/packlets/identity/identity-manager.ts +1 -0
  45. package/src/packlets/identity/identity.test.ts +3 -0
  46. package/src/packlets/indexing/util.ts +7 -64
  47. package/src/packlets/invitations/device-invitation-protocol.ts +6 -1
  48. package/src/packlets/invitations/index.ts +1 -0
  49. package/src/packlets/invitations/invitation-protocol.ts +7 -1
  50. package/src/packlets/invitations/invitations-handler.ts +11 -73
  51. package/src/packlets/invitations/invitations-manager.ts +271 -0
  52. package/src/packlets/invitations/invitations-service.ts +23 -168
  53. package/src/packlets/invitations/space-invitation-protocol.ts +45 -3
  54. package/src/packlets/services/automerge-host.test.ts +1 -1
  55. package/src/packlets/services/service-context.ts +14 -2
  56. package/src/packlets/services/service-host.ts +11 -15
  57. package/src/packlets/spaces/data-space-manager.ts +48 -2
  58. package/src/packlets/spaces/data-space.ts +1 -1
  59. package/src/packlets/testing/invitation-utils.ts +100 -97
  60. package/src/packlets/testing/test-builder.ts +19 -1
  61. package/src/version.ts +1 -1
  62. package/dist/lib/browser/chunk-7S34JE6M.mjs.map +0 -7
  63. package/dist/lib/node/chunk-DQMGKBOV.cjs.map +0 -7
@@ -2,7 +2,11 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { createAdmissionCredentials, getCredentialAssertion } from '@dxos/credentials';
5
+ import {
6
+ createAdmissionCredentials,
7
+ createDelegatedSpaceInvitationCredential,
8
+ getCredentialAssertion,
9
+ } from '@dxos/credentials';
6
10
  import { writeMessages } from '@dxos/feed-store';
7
11
  import { invariant } from '@dxos/invariant';
8
12
  import { type Keyring } from '@dxos/keyring';
@@ -11,7 +15,7 @@ import { log } from '@dxos/log';
11
15
  import { AlreadyJoinedError } from '@dxos/protocols';
12
16
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
13
17
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
14
- import { type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
18
+ import { SpaceMember, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
15
19
  import {
16
20
  type AdmissionRequest,
17
21
  type AdmissionResponse,
@@ -43,7 +47,11 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
43
47
  };
44
48
  }
45
49
 
46
- async admit(request: AdmissionRequest, guestProfile?: ProfileDocument | undefined): Promise<AdmissionResponse> {
50
+ async admit(
51
+ invitation: Invitation,
52
+ request: AdmissionRequest,
53
+ guestProfile?: ProfileDocument | undefined,
54
+ ): Promise<AdmissionResponse> {
47
55
  invariant(this._spaceKey);
48
56
  const space = await this._spaceManager.spaces.get(this._spaceKey);
49
57
  invariant(space);
@@ -59,6 +67,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
59
67
  space.key,
60
68
  space.inner.genesisFeedKey,
61
69
  guestProfile,
70
+ invitation.delegationCredentialId,
62
71
  );
63
72
 
64
73
  // TODO(dmaretskyi): Refactor.
@@ -76,6 +85,39 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
76
85
  };
77
86
  }
78
87
 
88
+ async delegate(invitation: Invitation): Promise<PublicKey> {
89
+ invariant(this._spaceKey);
90
+ const space = await this._spaceManager.spaces.get(this._spaceKey);
91
+ invariant(space);
92
+ if (invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY) {
93
+ invariant(invitation.guestKeypair?.publicKey);
94
+ }
95
+
96
+ log('writing delegate space invitation', { host: this._signingContext.deviceKey, id: invitation.invitationId });
97
+ const credential = await createDelegatedSpaceInvitationCredential(
98
+ this._signingContext.credentialSigner,
99
+ space.key,
100
+ {
101
+ invitationId: invitation.invitationId,
102
+ authMethod: invitation.authMethod,
103
+ swarmKey: invitation.swarmKey,
104
+ role: SpaceMember.Role.ADMIN,
105
+ expiresOn: invitation.lifetime
106
+ ? new Date((invitation.created?.getTime() ?? Date.now()) + invitation.lifetime)
107
+ : undefined,
108
+ multiUse: invitation.multiUse ?? false,
109
+ guestKey:
110
+ invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY
111
+ ? invitation.guestKeypair!.publicKey
112
+ : undefined,
113
+ },
114
+ );
115
+
116
+ invariant(credential.credential);
117
+ await writeMessages(space.inner.controlPipeline.writer, [credential]);
118
+ return credential.credential.credential.id!;
119
+ }
120
+
79
121
  checkInvitation(invitation: Partial<Invitation>) {
80
122
  if (invitation.spaceKey && this._spaceManager.spaces.has(invitation.spaceKey)) {
81
123
  return new AlreadyJoinedError('Already joined space.');
@@ -5,9 +5,9 @@
5
5
  import { expect } from 'chai';
6
6
 
7
7
  import { asyncTimeout, sleep } from '@dxos/async';
8
+ import { AutomergeContext } from '@dxos/echo-db';
8
9
  import { AutomergeHost, DataServiceImpl } from '@dxos/echo-pipeline';
9
10
  import { createTestLevel } from '@dxos/echo-pipeline/testing';
10
- import { AutomergeContext } from '@dxos/echo-schema';
11
11
  import { afterTest, describe, test } from '@dxos/test';
12
12
 
13
13
  describe('AutomergeHost', () => {
@@ -32,13 +32,14 @@ import {
32
32
  type IdentityManagerRuntimeParams,
33
33
  type JoinIdentityParams,
34
34
  } from '../identity';
35
- import { createDocumentsIterator, createSelectedDocumentsIterator } from '../indexing';
35
+ import { createSelectedDocumentsIterator } from '../indexing';
36
36
  import {
37
37
  DeviceInvitationProtocol,
38
38
  InvitationsHandler,
39
39
  SpaceInvitationProtocol,
40
40
  type InvitationProtocol,
41
41
  } from '../invitations';
42
+ import { InvitationsManager } from '../invitations/invitations-manager';
42
43
  import { DataSpaceManager, type DataSpaceManagerRuntimeParams, type SigningContext } from '../spaces';
43
44
 
44
45
  export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams;
@@ -62,6 +63,7 @@ export class ServiceContext extends Resource {
62
63
  public readonly spaceManager: SpaceManager;
63
64
  public readonly identityManager: IdentityManager;
64
65
  public readonly invitations: InvitationsHandler;
66
+ public readonly invitationsManager: InvitationsManager;
65
67
  public readonly automergeHost: AutomergeHost;
66
68
  public readonly indexMetadata: IndexMetadataStore;
67
69
  public readonly indexer: Indexer;
@@ -129,13 +131,18 @@ export class ServiceContext extends Resource {
129
131
  });
130
132
 
131
133
  this.indexer = new Indexer({
134
+ db: this.level,
132
135
  indexStore: new IndexStore({ db: level.sublevel('index-storage') }),
133
136
  metadataStore: this.indexMetadata,
134
137
  loadDocuments: createSelectedDocumentsIterator(this.automergeHost),
135
- getAllDocuments: createDocumentsIterator(this.automergeHost),
136
138
  });
137
139
 
138
140
  this.invitations = new InvitationsHandler(this.networkManager);
141
+ this.invitationsManager = new InvitationsManager(
142
+ this.invitations,
143
+ (invitation) => this.getInvitationHandler(invitation),
144
+ this.metadataStore,
145
+ );
139
146
 
140
147
  // TODO(burdon): _initialize called in multiple places.
141
148
  // TODO(burdon): Call _initialize on success.
@@ -166,6 +173,10 @@ export class ServiceContext extends Resource {
166
173
  if (this.identityManager.identity) {
167
174
  await this._initialize(ctx);
168
175
  }
176
+
177
+ const loadedInvitations = await this.invitationsManager.loadPersistentInvitations();
178
+ log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
179
+
169
180
  log.trace('dxos.sdk.service-context.open', trace.end({ id: this._instanceId }));
170
181
  log('opened');
171
182
  }
@@ -245,6 +256,7 @@ export class ServiceContext extends Resource {
245
256
  signingContext,
246
257
  this.feedStore,
247
258
  this.automergeHost,
259
+ this.invitationsManager,
248
260
  this._runtimeParams as DataSpaceManagerRuntimeParams,
249
261
  );
250
262
  await this.dataSpaceManager.open();
@@ -16,7 +16,7 @@ import {
16
16
  type LevelDB,
17
17
  } from '@dxos/echo-pipeline';
18
18
  import { getTypeReference } from '@dxos/echo-schema';
19
- import { IndexServiceImpl } from '@dxos/indexing';
19
+ import { QueryServiceImpl } from '@dxos/indexing';
20
20
  import { invariant } from '@dxos/invariant';
21
21
  import { PublicKey } from '@dxos/keys';
22
22
  import { log } from '@dxos/log';
@@ -83,6 +83,7 @@ export class ClientServicesHost {
83
83
  private readonly _systemService: SystemServiceImpl;
84
84
  private readonly _loggingService: LoggingServiceImpl;
85
85
  private readonly _tracingService = TRACE_PROCESSOR.createTraceSender();
86
+ private _queryService!: QueryServiceImpl;
86
87
 
87
88
  private _config?: Config;
88
89
  private readonly _statusUpdate = new Event<void>();
@@ -262,6 +263,12 @@ export class ClientServicesHost {
262
263
  this._runtimeParams,
263
264
  );
264
265
 
266
+ this._queryService = new QueryServiceImpl({
267
+ indexer: this._serviceContext.indexer,
268
+ automergeHost: this._serviceContext.automergeHost,
269
+ });
270
+ await this._queryService.open(ctx);
271
+
265
272
  this._serviceRegistry.setServices({
266
273
  SystemService: this._systemService,
267
274
 
@@ -272,11 +279,7 @@ export class ClientServicesHost {
272
279
  (profile) => this._serviceContext.broadcastProfileUpdate(profile),
273
280
  ),
274
281
 
275
- InvitationsService: new InvitationsServiceImpl(
276
- this._serviceContext.invitations,
277
- (invitation) => this._serviceContext.getInvitationHandler(invitation),
278
- this._serviceContext.metadataStore,
279
- ),
282
+ InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitationsManager),
280
283
 
281
284
  DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
282
285
 
@@ -291,10 +294,7 @@ export class ClientServicesHost {
291
294
 
292
295
  DataService: new DataServiceImpl(this._serviceContext.automergeHost),
293
296
 
294
- IndexService: new IndexServiceImpl({
295
- indexer: this._serviceContext.indexer,
296
- automergeHost: this._serviceContext.automergeHost,
297
- }),
297
+ QueryService: this._queryService,
298
298
 
299
299
  NetworkService: new NetworkServiceImpl(this._serviceContext.networkManager, this._serviceContext.signalManager),
300
300
 
@@ -310,11 +310,6 @@ export class ClientServicesHost {
310
310
  });
311
311
 
312
312
  await this._serviceContext.open(ctx);
313
- // TODO(nf): move to InvitationManager in ServiceContext?
314
- invariant(this.serviceRegistry.services.InvitationsService);
315
- const loadedInvitations = await this.serviceRegistry.services.InvitationsService.loadPersistentInvitations();
316
-
317
- log('loaded persistent invitations', { count: loadedInvitations.invitations?.length });
318
313
 
319
314
  const devtoolsProxy = this._config?.get('runtime.client.devtoolsProxy');
320
315
  if (devtoolsProxy) {
@@ -349,6 +344,7 @@ export class ClientServicesHost {
349
344
  await this._devtoolsProxy?.close();
350
345
  this._serviceRegistry.setServices({ SystemService: this._systemService });
351
346
  await this._loggingService.close();
347
+ await this._queryService.close();
352
348
  await this._serviceContext.close();
353
349
  await this._level?.close();
354
350
  this._open = false;
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { Event, synchronized, trackLeaks } from '@dxos/async';
6
6
  import { Context, cancelWithContext } from '@dxos/context';
7
- import { getCredentialAssertion, type CredentialSigner } from '@dxos/credentials';
7
+ import { getCredentialAssertion, type CredentialSigner, type DelegateInvitationCredential } from '@dxos/credentials';
8
8
  import { type AutomergeHost, type MetadataStore, type Space, type SpaceManager } from '@dxos/echo-pipeline';
9
9
  import { type FeedStore } from '@dxos/feed-store';
10
10
  import { invariant } from '@dxos/invariant';
@@ -12,10 +12,11 @@ import { type Keyring } from '@dxos/keyring';
12
12
  import { PublicKey } from '@dxos/keys';
13
13
  import { log } from '@dxos/log';
14
14
  import { trace } from '@dxos/protocols';
15
- import { SpaceState } from '@dxos/protocols/proto/dxos/client/services';
15
+ import { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
16
16
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
17
17
  import { type SpaceMetadata } from '@dxos/protocols/proto/dxos/echo/metadata';
18
18
  import { type Credential, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
19
+ import { type DelegateSpaceInvitation } from '@dxos/protocols/proto/dxos/halo/invitations';
19
20
  import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
20
21
  import { type Timeframe } from '@dxos/timeframe';
21
22
  import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
@@ -23,6 +24,7 @@ import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
23
24
  import { DataSpace } from './data-space';
24
25
  import { spaceGenesis } from './genesis';
25
26
  import { createAuthProvider } from '../identity';
27
+ import { type InvitationsManager } from '../invitations';
26
28
 
27
29
  const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
28
30
  const PRESENCE_OFFLINE_TIMEOUT = 20_000;
@@ -78,6 +80,7 @@ export class DataSpaceManager {
78
80
  private readonly _signingContext: SigningContext,
79
81
  private readonly _feedStore: FeedStore<FeedMessage>,
80
82
  private readonly _automergeHost: AutomergeHost,
83
+ private readonly _invitationsManager: InvitationsManager,
81
84
  params?: DataSpaceManagerRuntimeParams,
82
85
  ) {
83
86
  const {
@@ -247,6 +250,9 @@ export class DataSpaceManager {
247
250
  log.warn('auth failure');
248
251
  },
249
252
  memberKey: this._signingContext.identityKey,
253
+ onDelegatedInvitationStatusChange: (invitation, isActive) => {
254
+ return this._handleInvitationStatusChange(dataSpace, invitation, isActive);
255
+ },
250
256
  });
251
257
  controlFeed && (await space.setControlFeed(controlFeed));
252
258
  dataFeed && (await space.setDataFeed(dataFeed));
@@ -267,6 +273,7 @@ export class DataSpaceManager {
267
273
  afterReady: async () => {
268
274
  log('after space ready', { space: space.key, open: this._isOpen });
269
275
  if (this._isOpen) {
276
+ await this._createDelegatedInvitations(dataSpace, [...space.spaceState.invitations.entries()]);
270
277
  this.updated.emit();
271
278
  }
272
279
  },
@@ -289,4 +296,43 @@ export class DataSpaceManager {
289
296
  this._spaces.set(metadata.key, dataSpace);
290
297
  return dataSpace;
291
298
  }
299
+
300
+ private async _handleInvitationStatusChange(
301
+ dataSpace: DataSpace | undefined,
302
+ delegatedInvitation: DelegateInvitationCredential,
303
+ isActive: boolean,
304
+ ): Promise<void> {
305
+ if (dataSpace?.state !== SpaceState.READY) {
306
+ return;
307
+ }
308
+ if (isActive) {
309
+ await this._createDelegatedInvitations(dataSpace, [
310
+ [delegatedInvitation.credentialId, delegatedInvitation.invitation],
311
+ ]);
312
+ } else {
313
+ await this._invitationsManager.cancelInvitation(delegatedInvitation.invitation);
314
+ }
315
+ }
316
+
317
+ private async _createDelegatedInvitations(
318
+ space: DataSpace,
319
+ invitations: Array<[PublicKey, DelegateSpaceInvitation]>,
320
+ ): Promise<void> {
321
+ const tasks = invitations.map(([credentialId, invitation]) => {
322
+ return this._invitationsManager.createInvitation({
323
+ type: Invitation.Type.DELEGATED,
324
+ kind: Invitation.Kind.SPACE,
325
+ spaceKey: space.key,
326
+ authMethod: invitation.authMethod,
327
+ invitationId: invitation.invitationId,
328
+ swarmKey: invitation.swarmKey,
329
+ guestKeypair: invitation.guestKey ? { publicKey: invitation.guestKey } : undefined,
330
+ lifetime: invitation.expiresOn ? invitation.expiresOn.getTime() - Date.now() : undefined,
331
+ multiUse: invitation.multiUse,
332
+ delegationCredentialId: credentialId,
333
+ persistent: false,
334
+ });
335
+ });
336
+ await Promise.all(tasks);
337
+ }
292
338
  }
@@ -6,7 +6,6 @@ import { Event, asyncTimeout, scheduleTask, sleep, synchronized, trackLeaks } fr
6
6
  import { AUTH_TIMEOUT } from '@dxos/client-protocol';
7
7
  import { cancelWithContext, Context, ContextDisposedError } from '@dxos/context';
8
8
  import { timed, warnAfterTimeout } from '@dxos/debug';
9
- import { TYPE_PROPERTIES } from '@dxos/echo-db';
10
9
  import {
11
10
  type MetadataStore,
12
11
  type Space,
@@ -15,6 +14,7 @@ import {
15
14
  type SpaceDoc,
16
15
  } from '@dxos/echo-pipeline';
17
16
  import { AutomergeDocumentLoaderImpl } from '@dxos/echo-pipeline';
17
+ import { TYPE_PROPERTIES } from '@dxos/echo-schema';
18
18
  import { type FeedStore } from '@dxos/feed-store';
19
19
  import { failedInvariant, invariant } from '@dxos/invariant';
20
20
  import { type Keyring } from '@dxos/keyring';
@@ -60,146 +60,149 @@ export const performInvitation = ({
60
60
  const guestComplete = new Trigger<Result>();
61
61
  const authCode = new Trigger<string>();
62
62
 
63
- const hostObservable = createInvitation(host, options);
64
- hostObservable.subscribe(
65
- async (hostInvitation: Invitation) => {
66
- switch (hostInvitation.state) {
67
- case Invitation.State.CONNECTING: {
68
- if (hooks?.host?.onConnecting?.(hostObservable)) {
69
- break;
70
- }
71
- const guestObservable = acceptInvitation(guest, hostInvitation, guestDeviceProfile);
72
- guestObservable.subscribe(
73
- async (guestInvitation: Invitation) => {
74
- switch (guestInvitation.state) {
75
- case Invitation.State.CONNECTING: {
76
- if (hooks?.guest?.onConnecting?.(guestObservable)) {
63
+ void createInvitation(host, options).then((hostObservable) => {
64
+ hostObservable.subscribe(
65
+ async (hostInvitation: Invitation) => {
66
+ switch (hostInvitation.state) {
67
+ case Invitation.State.CONNECTING: {
68
+ if (hooks?.host?.onConnecting?.(hostObservable)) {
69
+ break;
70
+ }
71
+ const guestObservable = acceptInvitation(guest, hostInvitation, guestDeviceProfile);
72
+ guestObservable.subscribe(
73
+ async (guestInvitation: Invitation) => {
74
+ switch (guestInvitation.state) {
75
+ case Invitation.State.CONNECTING: {
76
+ if (hooks?.guest?.onConnecting?.(guestObservable)) {
77
+ break;
78
+ }
79
+ invariant(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
77
80
  break;
78
81
  }
79
- invariant(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
80
- break;
81
- }
82
82
 
83
- case Invitation.State.CONNECTED: {
84
- hooks?.guest?.onConnected?.(guestObservable);
85
- break;
86
- }
83
+ case Invitation.State.CONNECTED: {
84
+ hooks?.guest?.onConnected?.(guestObservable);
85
+ break;
86
+ }
87
87
 
88
- case Invitation.State.READY_FOR_AUTHENTICATION: {
89
- if (hooks?.guest?.onReady?.(guestObservable)) {
88
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
89
+ if (hooks?.guest?.onReady?.(guestObservable)) {
90
+ break;
91
+ }
92
+ await guestObservable.authenticate(await authCode.wait());
90
93
  break;
91
94
  }
92
- await guestObservable.authenticate(await authCode.wait());
93
- break;
94
- }
95
95
 
96
- case Invitation.State.AUTHENTICATING: {
97
- hooks?.guest?.onAuthenticating?.(guestObservable);
98
- break;
99
- }
96
+ case Invitation.State.AUTHENTICATING: {
97
+ hooks?.guest?.onAuthenticating?.(guestObservable);
98
+ break;
99
+ }
100
100
 
101
- case Invitation.State.SUCCESS: {
102
- if (hooks?.guest?.onSuccess?.(guestObservable)) {
101
+ case Invitation.State.SUCCESS: {
102
+ if (hooks?.guest?.onSuccess?.(guestObservable)) {
103
+ break;
104
+ }
105
+ guestComplete.wake({ invitation: guestInvitation });
103
106
  break;
104
107
  }
105
- guestComplete.wake({ invitation: guestInvitation });
106
- break;
107
- }
108
108
 
109
- case Invitation.State.CANCELLED: {
110
- if (hooks?.guest?.onCancelled?.(guestObservable)) {
109
+ case Invitation.State.CANCELLED: {
110
+ if (hooks?.guest?.onCancelled?.(guestObservable)) {
111
+ break;
112
+ }
113
+ guestComplete.wake({ invitation: guestInvitation });
111
114
  break;
112
115
  }
113
- guestComplete.wake({ invitation: guestInvitation });
114
- break;
115
- }
116
116
 
117
- case Invitation.State.TIMEOUT: {
118
- if (hooks?.guest?.onTimeout?.(guestObservable)) {
119
- return;
117
+ case Invitation.State.TIMEOUT: {
118
+ if (hooks?.guest?.onTimeout?.(guestObservable)) {
119
+ return;
120
+ }
121
+ guestComplete.wake({ invitation: guestInvitation });
120
122
  }
121
- guestComplete.wake({ invitation: guestInvitation });
122
123
  }
123
- }
124
- },
125
- (error: Error) => {
126
- if (hooks?.guest?.onError?.(guestObservable)) {
127
- return;
128
- }
129
- guestComplete.wake({ error });
130
- },
131
- );
132
- break;
133
- }
134
-
135
- case Invitation.State.CONNECTED: {
136
- hooks?.host?.onConnected?.(hostObservable);
137
- break;
138
- }
124
+ },
125
+ (error: Error) => {
126
+ if (hooks?.guest?.onError?.(guestObservable)) {
127
+ return;
128
+ }
129
+ guestComplete.wake({ error });
130
+ },
131
+ );
132
+ break;
133
+ }
139
134
 
140
- case Invitation.State.READY_FOR_AUTHENTICATION: {
141
- if (hooks?.host?.onReady?.(hostObservable)) {
135
+ case Invitation.State.CONNECTED: {
136
+ hooks?.host?.onConnected?.(hostObservable);
142
137
  break;
143
138
  }
144
- if (hostInvitation.authCode) {
145
- authCode.wake(hostInvitation.authCode);
139
+
140
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
141
+ if (hooks?.host?.onReady?.(hostObservable)) {
142
+ break;
143
+ }
144
+ if (hostInvitation.authCode) {
145
+ authCode.wake(hostInvitation.authCode);
146
+ }
147
+ break;
146
148
  }
147
- break;
148
- }
149
149
 
150
- case Invitation.State.AUTHENTICATING: {
151
- hooks?.host?.onAuthenticating?.(hostObservable);
152
- break;
153
- }
150
+ case Invitation.State.AUTHENTICATING: {
151
+ hooks?.host?.onAuthenticating?.(hostObservable);
152
+ break;
153
+ }
154
154
 
155
- case Invitation.State.SUCCESS: {
156
- if (hooks?.host?.onSuccess?.(hostObservable)) {
155
+ case Invitation.State.SUCCESS: {
156
+ if (hooks?.host?.onSuccess?.(hostObservable)) {
157
+ break;
158
+ }
159
+ hostComplete.wake({ invitation: hostInvitation });
157
160
  break;
158
161
  }
159
- hostComplete.wake({ invitation: hostInvitation });
160
- break;
161
- }
162
162
 
163
- case Invitation.State.CANCELLED: {
164
- if (hooks?.host?.onCancelled?.(hostObservable)) {
163
+ case Invitation.State.CANCELLED: {
164
+ if (hooks?.host?.onCancelled?.(hostObservable)) {
165
+ break;
166
+ }
167
+ hostComplete.wake({ invitation: hostInvitation });
165
168
  break;
166
169
  }
167
- hostComplete.wake({ invitation: hostInvitation });
168
- break;
169
- }
170
170
 
171
- case Invitation.State.TIMEOUT: {
172
- if (hooks?.host?.onTimeout?.(hostObservable)) {
171
+ case Invitation.State.TIMEOUT: {
172
+ if (hooks?.host?.onTimeout?.(hostObservable)) {
173
+ break;
174
+ }
175
+ hostComplete.wake({ invitation: hostInvitation });
173
176
  break;
174
177
  }
175
- hostComplete.wake({ invitation: hostInvitation });
176
- break;
177
178
  }
178
- }
179
- },
180
- (error: Error) => {
181
- if (hooks?.host?.onError?.(hostObservable)) {
182
- return;
183
- }
184
- hostComplete.wake({ error });
185
- },
186
- );
179
+ },
180
+ (error: Error) => {
181
+ if (hooks?.host?.onError?.(hostObservable)) {
182
+ return;
183
+ }
184
+ hostComplete.wake({ error });
185
+ },
186
+ );
187
+ });
187
188
 
188
189
  return [hostComplete.wait(), guestComplete.wait()];
189
190
  };
190
191
 
191
- const createInvitation = (
192
+ const createInvitation = async (
192
193
  host: ServiceContext | InvitationHost,
193
194
  options?: Partial<Invitation>,
194
- ): CancellableInvitation => {
195
+ ): Promise<CancellableInvitation> => {
195
196
  options ??= {
196
197
  authMethod: Invitation.AuthMethod.NONE,
197
198
  ...(options ?? {}),
198
199
  };
199
200
 
200
201
  if (host instanceof ServiceContext) {
201
- const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
202
- return host.invitations.createInvitation(hostHandler, options);
202
+ return host.invitationsManager.createInvitation({
203
+ kind: Invitation.Kind.SPACE,
204
+ ...options,
205
+ });
203
206
  }
204
207
 
205
208
  return host.share(options);
@@ -19,9 +19,11 @@ import { FeedFactory, FeedStore } from '@dxos/feed-store';
19
19
  import { Keyring } from '@dxos/keyring';
20
20
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
21
21
  import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
22
+ import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
22
23
  import { createStorage, StorageType, type Storage } from '@dxos/random-access-storage';
23
24
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
24
25
 
26
+ import { InvitationsHandler, InvitationsManager, SpaceInvitationProtocol } from '../invitations';
25
27
  import { ClientServicesHost, ServiceContext } from '../services';
26
28
  import { DataSpaceManager, type SigningContext } from '../spaces';
27
29
 
@@ -104,6 +106,7 @@ export type TestPeerProps = {
104
106
  signingContext?: SigningContext;
105
107
  blobStore?: BlobStore;
106
108
  automergeHost?: AutomergeHost;
109
+ invitationsManager?: InvitationsManager;
107
110
  };
108
111
 
109
112
  export class TestPeer {
@@ -181,7 +184,7 @@ export class TestPeer {
181
184
  }));
182
185
  }
183
186
 
184
- get dataSpaceManager() {
187
+ get dataSpaceManager(): DataSpaceManager {
185
188
  return (this._props.dataSpaceManager ??= new DataSpaceManager(
186
189
  this.spaceManager,
187
190
  this.metadataStore,
@@ -189,6 +192,21 @@ export class TestPeer {
189
192
  this.identity,
190
193
  this.feedStore,
191
194
  this.automergeHost,
195
+ this.invitationsManager,
196
+ ));
197
+ }
198
+
199
+ get invitationsManager() {
200
+ return (this._props.invitationsManager ??= new InvitationsManager(
201
+ new InvitationsHandler(this.networkManager),
202
+ (invitation) => {
203
+ if (invitation.kind === Invitation.Kind.SPACE) {
204
+ return new SpaceInvitationProtocol(this.dataSpaceManager, this.identity!, this.keyring, invitation.spaceKey!);
205
+ } else {
206
+ throw new Error('not implemented');
207
+ }
208
+ },
209
+ this.metadataStore,
192
210
  ));
193
211
  }
194
212
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.4.10-main.fe71b4c";
1
+ export const DXOS_VERSION = "0.4.10-next.169e4e3";