@dxos/client-services 0.4.10-main.e6ba7bc → 0.4.10-main.e96274c

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 (50) hide show
  1. package/dist/lib/browser/{chunk-NE6FWMYP.mjs → chunk-UVEPMM4Z.mjs} +287 -355
  2. package/dist/lib/browser/chunk-UVEPMM4Z.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 +112 -125
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/{chunk-3EKN7HG6.cjs → chunk-GZWBW7OC.cjs} +377 -445
  8. package/dist/lib/node/chunk-GZWBW7OC.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +43 -43
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/packlets/testing/index.cjs +115 -125
  12. package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
  13. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  14. package/dist/types/src/packlets/indexing/util.d.ts +5 -0
  15. package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
  16. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +1 -3
  17. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
  18. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +1 -6
  19. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
  20. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +2 -4
  21. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  22. package/dist/types/src/packlets/invitations/invitations-manager.d.ts +7 -9
  23. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  24. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  25. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +1 -2
  26. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
  27. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  28. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +1 -5
  29. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  30. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  31. package/dist/types/src/packlets/testing/test-builder.d.ts +0 -3
  32. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  33. package/dist/types/src/version.d.ts +1 -1
  34. package/package.json +34 -34
  35. package/src/packlets/identity/identity-manager.ts +0 -1
  36. package/src/packlets/identity/identity.test.ts +0 -3
  37. package/src/packlets/indexing/util.ts +65 -1
  38. package/src/packlets/invitations/device-invitation-protocol.ts +1 -6
  39. package/src/packlets/invitations/invitation-protocol.ts +1 -7
  40. package/src/packlets/invitations/invitations-handler.ts +71 -10
  41. package/src/packlets/invitations/invitations-manager.ts +40 -114
  42. package/src/packlets/invitations/invitations-service.ts +2 -4
  43. package/src/packlets/invitations/space-invitation-protocol.ts +3 -45
  44. package/src/packlets/services/service-context.ts +2 -3
  45. package/src/packlets/spaces/data-space-manager.ts +2 -48
  46. package/src/packlets/testing/invitation-utils.ts +97 -100
  47. package/src/packlets/testing/test-builder.ts +1 -19
  48. package/src/version.ts +1 -1
  49. package/dist/lib/browser/chunk-NE6FWMYP.mjs.map +0 -7
  50. package/dist/lib/node/chunk-3EKN7HG6.cjs.map +0 -7
@@ -2,27 +2,20 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Event, PushStream } from '@dxos/async';
6
- import {
7
- type AuthenticatingInvitation,
8
- AUTHENTICATION_CODE_LENGTH,
9
- CancellableInvitation,
10
- INVITATION_TIMEOUT,
11
- } from '@dxos/client-protocol';
12
- import { Context } from '@dxos/context';
13
- import { generatePasscode } from '@dxos/credentials';
5
+ import { Event } from '@dxos/async';
6
+ import type { AuthenticatingInvitation, CancellableInvitation } from '@dxos/client-protocol';
7
+ import { type Context } from '@dxos/context';
14
8
  import { hasInvitationExpired, type MetadataStore } from '@dxos/echo-pipeline';
15
9
  import { invariant } from '@dxos/invariant';
16
- import { PublicKey } from '@dxos/keys';
17
10
  import { log } from '@dxos/log';
18
11
  import {
19
12
  type AcceptInvitationRequest,
13
+ type Invitation,
20
14
  type AuthenticationRequest,
21
- Invitation,
22
15
  } from '@dxos/protocols/proto/dxos/client/services';
23
16
 
24
17
  import type { InvitationProtocol } from './invitation-protocol';
25
- import { createAdmissionKeypair, type InvitationsHandler } from './invitations-handler';
18
+ import type { InvitationsHandler } from './invitations-handler';
26
19
 
27
20
  /**
28
21
  * Entry point for creating and accepting invitations, keeps track of existing invitation set and
@@ -43,44 +36,36 @@ export class InvitationsManager {
43
36
 
44
37
  constructor(
45
38
  private readonly _invitationsHandler: InvitationsHandler,
46
- private readonly _getHandler: (invitation: Partial<Invitation> & Pick<Invitation, 'kind'>) => InvitationProtocol,
39
+ private readonly _getHandler: (invitation: Invitation) => InvitationProtocol,
47
40
  private readonly _metadataStore: MetadataStore,
48
41
  ) {}
49
42
 
50
- async createInvitation(options: Partial<Invitation> & Pick<Invitation, 'kind'>): Promise<CancellableInvitation> {
51
- if (options.invitationId) {
52
- const existingInvitation = this._createInvitations.get(options.invitationId);
53
- if (existingInvitation) {
54
- return existingInvitation;
55
- }
43
+ createInvitation(options: Invitation): CancellableInvitation {
44
+ const existingInvitation = this._createInvitations.get(options.invitationId);
45
+ if (existingInvitation) {
46
+ return existingInvitation;
56
47
  }
57
48
 
58
49
  const handler = this._getHandler(options);
59
- const invitation = this._createInvitation(handler, options);
60
- const { ctx, stream, observableInvitation } = this._createObservableInvitation(handler, invitation);
50
+ const invitation = this._invitationsHandler.createInvitation(handler, options);
51
+ this._createInvitations.set(invitation.get().invitationId, invitation);
52
+ this.invitationCreated.emit(invitation.get());
53
+
54
+ const saveInvitationTask = invitation.get().persistent
55
+ ? this._safePersistInBackground(invitation)
56
+ : Promise.resolve();
61
57
 
62
- this._createInvitations.set(invitation.invitationId, observableInvitation);
63
- this.invitationCreated.emit(invitation);
64
58
  // onComplete is called on cancel, expiration, or redemption of a single-use invitation
65
- this._onInvitationComplete(observableInvitation, async () => {
66
- this._createInvitations.delete(observableInvitation.get().invitationId);
67
- this.removedCreated.emit(observableInvitation.get());
68
- if (observableInvitation.get().persistent) {
69
- await this._safeDeleteInvitation(observableInvitation.get());
59
+ this._onInvitationComplete(invitation, async () => {
60
+ this._createInvitations.delete(invitation.get().invitationId);
61
+ this.removedCreated.emit(invitation.get());
62
+ if (invitation.get().persistent) {
63
+ await saveInvitationTask;
64
+ await this._safeDeleteInvitation(invitation.get());
70
65
  }
71
66
  });
72
67
 
73
- try {
74
- await this._persistIfRequired(handler, stream, invitation);
75
- } catch (err) {
76
- log.catch(err);
77
- await observableInvitation.cancel();
78
- return observableInvitation;
79
- }
80
-
81
- this._invitationsHandler.handleInvitationFlow(ctx, stream, handler, observableInvitation.get());
82
-
83
- return observableInvitation;
68
+ return invitation;
84
69
  }
85
70
 
86
71
  async loadPersistentInvitations(): Promise<{ invitations: Invitation[] }> {
@@ -93,13 +78,12 @@ export class InvitationsManager {
93
78
  // get saved persistent invitations, filter and remove from storage those that have expired.
94
79
  const freshInvitations = persistentInvitations.filter((invitation) => !hasInvitationExpired(invitation));
95
80
 
96
- const loadTasks = freshInvitations.map((persistentInvitation) => {
81
+ const cInvitations = freshInvitations.map((persistentInvitation) => {
97
82
  invariant(!this._createInvitations.get(persistentInvitation.invitationId), 'invitation already exists');
98
- return this.createInvitation({ ...persistentInvitation, persistent: false });
83
+ return this.createInvitation({ ...persistentInvitation, persistent: false }).get();
99
84
  });
100
- const cInvitations = await Promise.all(loadTasks);
101
85
 
102
- return { invitations: cInvitations.map((invitation) => invitation.get()) };
86
+ return { invitations: cInvitations };
103
87
  } catch (err) {
104
88
  log.catch(err);
105
89
  return { invitations: [] };
@@ -179,78 +163,20 @@ export class InvitationsManager {
179
163
  }
180
164
  }
181
165
 
182
- private _createInvitation(protocol: InvitationProtocol, options?: Partial<Invitation>): Invitation {
183
- const {
184
- invitationId = PublicKey.random().toHex(),
185
- type = Invitation.Type.INTERACTIVE,
186
- authMethod = Invitation.AuthMethod.SHARED_SECRET,
187
- state = Invitation.State.INIT,
188
- timeout = INVITATION_TIMEOUT,
189
- swarmKey = PublicKey.random(),
190
- persistent = options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
191
- created = new Date(),
192
- guestKeypair = undefined,
193
- lifetime = 86400, // 1 day,
194
- multiUse = false,
195
- } = options ?? {};
196
- const authCode =
197
- options?.authCode ??
198
- (authMethod === Invitation.AuthMethod.SHARED_SECRET ? generatePasscode(AUTHENTICATION_CODE_LENGTH) : undefined);
199
-
200
- return {
201
- invitationId,
202
- type,
203
- authMethod,
204
- state,
205
- swarmKey,
206
- authCode,
207
- timeout,
208
- persistent: persistent && type !== Invitation.Type.DELEGATED, // delegated invitations are persisted in control feed
209
- guestKeypair:
210
- guestKeypair ?? (authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? createAdmissionKeypair() : undefined),
211
- created,
212
- lifetime,
213
- multiUse,
214
- delegationCredentialId: options?.delegationCredentialId,
215
- ...protocol.getInvitationContext(),
216
- } satisfies Invitation;
217
- }
218
-
219
- private _createObservableInvitation(handler: InvitationProtocol, invitation: Invitation) {
220
- const stream = new PushStream<Invitation>();
221
- const ctx = new Context({
222
- onError: (err) => {
223
- stream.error(err);
224
- void ctx.dispose();
225
- },
226
- });
227
- ctx.onDispose(() => {
228
- log('complete', { ...handler.toJSON() });
229
- stream.complete();
230
- });
231
- const observableInvitation = new CancellableInvitation({
232
- initialInvitation: invitation,
233
- subscriber: stream.observable,
234
- onCancel: async () => {
235
- stream.next({ ...invitation, state: Invitation.State.CANCELLED });
236
- await ctx.dispose();
237
- },
166
+ private _safePersistInBackground(invitation: CancellableInvitation): Promise<void> {
167
+ return new Promise((resolve) => {
168
+ setTimeout(async () => {
169
+ try {
170
+ await this._metadataStore.addInvitation(invitation.get());
171
+ this.saved.emit(invitation.get());
172
+ } catch (err: any) {
173
+ log.catch(err);
174
+ await invitation.cancel();
175
+ } finally {
176
+ resolve();
177
+ }
178
+ });
238
179
  });
239
- return { ctx, stream, observableInvitation };
240
- }
241
-
242
- private async _persistIfRequired(
243
- handler: InvitationProtocol,
244
- changeStream: PushStream<Invitation>,
245
- invitation: Invitation,
246
- ): Promise<void> {
247
- if (invitation.type === Invitation.Type.DELEGATED && invitation.delegationCredentialId == null) {
248
- const delegationCredentialId = await handler.delegate(invitation);
249
- changeStream.next({ ...invitation, delegationCredentialId });
250
- } else if (invitation.persistent) {
251
- await this._metadataStore.addInvitation(invitation);
252
- this.saved.emit(invitation);
253
- }
254
180
  }
255
181
 
256
182
  private async _safeDeleteInvitation(invitation: Invitation): Promise<void> {
@@ -27,11 +27,9 @@ export class InvitationsServiceImpl implements InvitationsService {
27
27
  }
28
28
 
29
29
  createInvitation(options: Invitation): Stream<Invitation> {
30
+ const invitation = this._invitationsManager.createInvitation(options);
30
31
  return new Stream<Invitation>(({ next, close }) => {
31
- void this._invitationsManager
32
- .createInvitation(options)
33
- .then((invitation) => invitation.subscribe(next, close, close))
34
- .catch(close);
32
+ invitation.subscribe(next, close, close);
35
33
  });
36
34
  }
37
35
 
@@ -2,11 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import {
6
- createAdmissionCredentials,
7
- createDelegatedSpaceInvitationCredential,
8
- getCredentialAssertion,
9
- } from '@dxos/credentials';
5
+ import { createAdmissionCredentials, getCredentialAssertion } from '@dxos/credentials';
10
6
  import { writeMessages } from '@dxos/feed-store';
11
7
  import { invariant } from '@dxos/invariant';
12
8
  import { type Keyring } from '@dxos/keyring';
@@ -15,7 +11,7 @@ import { log } from '@dxos/log';
15
11
  import { AlreadyJoinedError } from '@dxos/protocols';
16
12
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
17
13
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
18
- import { SpaceMember, type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
14
+ import { type ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
19
15
  import {
20
16
  type AdmissionRequest,
21
17
  type AdmissionResponse,
@@ -47,11 +43,7 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
47
43
  };
48
44
  }
49
45
 
50
- async admit(
51
- invitation: Invitation,
52
- request: AdmissionRequest,
53
- guestProfile?: ProfileDocument | undefined,
54
- ): Promise<AdmissionResponse> {
46
+ async admit(request: AdmissionRequest, guestProfile?: ProfileDocument | undefined): Promise<AdmissionResponse> {
55
47
  invariant(this._spaceKey);
56
48
  const space = await this._spaceManager.spaces.get(this._spaceKey);
57
49
  invariant(space);
@@ -67,7 +59,6 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
67
59
  space.key,
68
60
  space.inner.genesisFeedKey,
69
61
  guestProfile,
70
- invitation.delegationCredentialId,
71
62
  );
72
63
 
73
64
  // TODO(dmaretskyi): Refactor.
@@ -85,39 +76,6 @@ export class SpaceInvitationProtocol implements InvitationProtocol {
85
76
  };
86
77
  }
87
78
 
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
-
121
79
  checkInvitation(invitation: Partial<Invitation>) {
122
80
  if (invitation.spaceKey && this._spaceManager.spaces.has(invitation.spaceKey)) {
123
81
  return new AlreadyJoinedError('Already joined space.');
@@ -32,7 +32,7 @@ import {
32
32
  type IdentityManagerRuntimeParams,
33
33
  type JoinIdentityParams,
34
34
  } from '../identity';
35
- import { createSelectedDocumentsIterator } from '../indexing';
35
+ import { createDocumentsIterator, createSelectedDocumentsIterator } from '../indexing';
36
36
  import {
37
37
  DeviceInvitationProtocol,
38
38
  InvitationsHandler,
@@ -131,10 +131,10 @@ export class ServiceContext extends Resource {
131
131
  });
132
132
 
133
133
  this.indexer = new Indexer({
134
- db: this.level,
135
134
  indexStore: new IndexStore({ db: level.sublevel('index-storage') }),
136
135
  metadataStore: this.indexMetadata,
137
136
  loadDocuments: createSelectedDocumentsIterator(this.automergeHost),
137
+ getAllDocuments: createDocumentsIterator(this.automergeHost),
138
138
  });
139
139
 
140
140
  this.invitations = new InvitationsHandler(this.networkManager);
@@ -256,7 +256,6 @@ export class ServiceContext extends Resource {
256
256
  signingContext,
257
257
  this.feedStore,
258
258
  this.automergeHost,
259
- this.invitationsManager,
260
259
  this._runtimeParams as DataSpaceManagerRuntimeParams,
261
260
  );
262
261
  await this.dataSpaceManager.open();
@@ -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, type DelegateInvitationCredential } from '@dxos/credentials';
7
+ import { getCredentialAssertion, type CredentialSigner } 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,11 +12,10 @@ 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 { Invitation, SpaceState } from '@dxos/protocols/proto/dxos/client/services';
15
+ import { 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';
20
19
  import { Gossip, Presence } from '@dxos/teleport-extension-gossip';
21
20
  import { type Timeframe } from '@dxos/timeframe';
22
21
  import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
@@ -24,7 +23,6 @@ import { ComplexMap, deferFunction, forEachAsync } from '@dxos/util';
24
23
  import { DataSpace } from './data-space';
25
24
  import { spaceGenesis } from './genesis';
26
25
  import { createAuthProvider } from '../identity';
27
- import { type InvitationsManager } from '../invitations';
28
26
 
29
27
  const PRESENCE_ANNOUNCE_INTERVAL = 10_000;
30
28
  const PRESENCE_OFFLINE_TIMEOUT = 20_000;
@@ -80,7 +78,6 @@ export class DataSpaceManager {
80
78
  private readonly _signingContext: SigningContext,
81
79
  private readonly _feedStore: FeedStore<FeedMessage>,
82
80
  private readonly _automergeHost: AutomergeHost,
83
- private readonly _invitationsManager: InvitationsManager,
84
81
  params?: DataSpaceManagerRuntimeParams,
85
82
  ) {
86
83
  const {
@@ -250,9 +247,6 @@ export class DataSpaceManager {
250
247
  log.warn('auth failure');
251
248
  },
252
249
  memberKey: this._signingContext.identityKey,
253
- onDelegatedInvitationStatusChange: (invitation, isActive) => {
254
- return this._handleInvitationStatusChange(dataSpace, invitation, isActive);
255
- },
256
250
  });
257
251
  controlFeed && (await space.setControlFeed(controlFeed));
258
252
  dataFeed && (await space.setDataFeed(dataFeed));
@@ -273,7 +267,6 @@ export class DataSpaceManager {
273
267
  afterReady: async () => {
274
268
  log('after space ready', { space: space.key, open: this._isOpen });
275
269
  if (this._isOpen) {
276
- await this._createDelegatedInvitations(dataSpace, [...space.spaceState.invitations.entries()]);
277
270
  this.updated.emit();
278
271
  }
279
272
  },
@@ -296,43 +289,4 @@ export class DataSpaceManager {
296
289
  this._spaces.set(metadata.key, dataSpace);
297
290
  return dataSpace;
298
291
  }
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
- }
338
292
  }
@@ -60,149 +60,146 @@ export const performInvitation = ({
60
60
  const guestComplete = new Trigger<Result>();
61
61
  const authCode = new Trigger<string>();
62
62
 
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!));
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)) {
80
77
  break;
81
78
  }
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)) {
90
- break;
91
- }
92
- await guestObservable.authenticate(await authCode.wait());
88
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
89
+ if (hooks?.guest?.onReady?.(guestObservable)) {
93
90
  break;
94
91
  }
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)) {
103
- break;
104
- }
105
- guestComplete.wake({ invitation: guestInvitation });
101
+ case Invitation.State.SUCCESS: {
102
+ if (hooks?.guest?.onSuccess?.(guestObservable)) {
106
103
  break;
107
104
  }
105
+ guestComplete.wake({ invitation: guestInvitation });
106
+ break;
107
+ }
108
108
 
109
- case Invitation.State.CANCELLED: {
110
- if (hooks?.guest?.onCancelled?.(guestObservable)) {
111
- break;
112
- }
113
- guestComplete.wake({ invitation: guestInvitation });
109
+ case Invitation.State.CANCELLED: {
110
+ if (hooks?.guest?.onCancelled?.(guestObservable)) {
114
111
  break;
115
112
  }
113
+ guestComplete.wake({ invitation: guestInvitation });
114
+ break;
115
+ }
116
116
 
117
- case Invitation.State.TIMEOUT: {
118
- if (hooks?.guest?.onTimeout?.(guestObservable)) {
119
- return;
120
- }
121
- guestComplete.wake({ invitation: guestInvitation });
117
+ case Invitation.State.TIMEOUT: {
118
+ if (hooks?.guest?.onTimeout?.(guestObservable)) {
119
+ return;
122
120
  }
121
+ guestComplete.wake({ invitation: guestInvitation });
123
122
  }
124
- },
125
- (error: Error) => {
126
- if (hooks?.guest?.onError?.(guestObservable)) {
127
- return;
128
- }
129
- guestComplete.wake({ error });
130
- },
131
- );
132
- break;
133
- }
123
+ }
124
+ },
125
+ (error: Error) => {
126
+ if (hooks?.guest?.onError?.(guestObservable)) {
127
+ return;
128
+ }
129
+ guestComplete.wake({ error });
130
+ },
131
+ );
132
+ break;
133
+ }
134
134
 
135
- case Invitation.State.CONNECTED: {
136
- hooks?.host?.onConnected?.(hostObservable);
137
- break;
138
- }
135
+ case Invitation.State.CONNECTED: {
136
+ hooks?.host?.onConnected?.(hostObservable);
137
+ break;
138
+ }
139
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
- }
140
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
141
+ if (hooks?.host?.onReady?.(hostObservable)) {
147
142
  break;
148
143
  }
149
-
150
- case Invitation.State.AUTHENTICATING: {
151
- hooks?.host?.onAuthenticating?.(hostObservable);
152
- break;
144
+ if (hostInvitation.authCode) {
145
+ authCode.wake(hostInvitation.authCode);
153
146
  }
147
+ break;
148
+ }
149
+
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)) {
157
- break;
158
- }
159
- hostComplete.wake({ invitation: hostInvitation });
155
+ case Invitation.State.SUCCESS: {
156
+ if (hooks?.host?.onSuccess?.(hostObservable)) {
160
157
  break;
161
158
  }
159
+ hostComplete.wake({ invitation: hostInvitation });
160
+ break;
161
+ }
162
162
 
163
- case Invitation.State.CANCELLED: {
164
- if (hooks?.host?.onCancelled?.(hostObservable)) {
165
- break;
166
- }
167
- hostComplete.wake({ invitation: hostInvitation });
163
+ case Invitation.State.CANCELLED: {
164
+ if (hooks?.host?.onCancelled?.(hostObservable)) {
168
165
  break;
169
166
  }
167
+ hostComplete.wake({ invitation: hostInvitation });
168
+ break;
169
+ }
170
170
 
171
- case Invitation.State.TIMEOUT: {
172
- if (hooks?.host?.onTimeout?.(hostObservable)) {
173
- break;
174
- }
175
- hostComplete.wake({ invitation: hostInvitation });
171
+ case Invitation.State.TIMEOUT: {
172
+ if (hooks?.host?.onTimeout?.(hostObservable)) {
176
173
  break;
177
174
  }
175
+ hostComplete.wake({ invitation: hostInvitation });
176
+ break;
178
177
  }
179
- },
180
- (error: Error) => {
181
- if (hooks?.host?.onError?.(hostObservable)) {
182
- return;
183
- }
184
- hostComplete.wake({ error });
185
- },
186
- );
187
- });
178
+ }
179
+ },
180
+ (error: Error) => {
181
+ if (hooks?.host?.onError?.(hostObservable)) {
182
+ return;
183
+ }
184
+ hostComplete.wake({ error });
185
+ },
186
+ );
188
187
 
189
188
  return [hostComplete.wait(), guestComplete.wait()];
190
189
  };
191
190
 
192
- const createInvitation = async (
191
+ const createInvitation = (
193
192
  host: ServiceContext | InvitationHost,
194
193
  options?: Partial<Invitation>,
195
- ): Promise<CancellableInvitation> => {
194
+ ): CancellableInvitation => {
196
195
  options ??= {
197
196
  authMethod: Invitation.AuthMethod.NONE,
198
197
  ...(options ?? {}),
199
198
  };
200
199
 
201
200
  if (host instanceof ServiceContext) {
202
- return host.invitationsManager.createInvitation({
203
- kind: Invitation.Kind.SPACE,
204
- ...options,
205
- });
201
+ const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
202
+ return host.invitations.createInvitation(hostHandler, options);
206
203
  }
207
204
 
208
205
  return host.share(options);