@dxos/client-services 0.1.34 → 0.1.36-next.ef27157

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 (87) hide show
  1. package/dist/lib/browser/{chunk-H5IXSSI7.mjs → chunk-OINEQJWM.mjs} +783 -924
  2. package/dist/lib/browser/chunk-OINEQJWM.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +9 -11
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +212 -74
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/index.cjs +897 -1039
  8. package/dist/lib/node/index.cjs.map +4 -4
  9. package/dist/lib/node/meta.json +1 -1
  10. package/dist/lib/node/packlets/testing/index.cjs +1057 -1061
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/packlets/identity/identity.d.ts +3 -3
  13. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  14. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +18 -0
  15. package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -0
  16. package/dist/types/src/packlets/invitations/device-invitation-protocol.test.d.ts +2 -0
  17. package/dist/types/src/packlets/invitations/device-invitation-protocol.test.d.ts.map +1 -0
  18. package/dist/types/src/packlets/invitations/index.d.ts +4 -4
  19. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  20. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +12 -0
  21. package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -0
  22. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +38 -0
  23. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -0
  24. package/dist/types/src/packlets/invitations/invitations-service.d.ts +13 -15
  25. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  26. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +22 -0
  27. package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -0
  28. package/dist/types/src/packlets/invitations/space-invitation-protocol.test.d.ts +2 -0
  29. package/dist/types/src/packlets/invitations/space-invitation-protocol.test.d.ts.map +1 -0
  30. package/dist/types/src/packlets/services/service-context.d.ts +6 -4
  31. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  32. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  33. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  34. package/dist/types/src/packlets/testing/invitation-utils.d.ts +31 -2
  35. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  36. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  37. package/dist/types/src/packlets/tests/invitations.test.d.ts +2 -0
  38. package/dist/types/src/packlets/tests/invitations.test.d.ts.map +1 -0
  39. package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -0
  40. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  41. package/package.json +30 -30
  42. package/src/packlets/identity/identity.ts +3 -3
  43. package/src/packlets/invitations/{device-invitations-handler.test.ts → device-invitation-protocol.test.ts} +3 -3
  44. package/src/packlets/invitations/device-invitation-protocol.ts +83 -0
  45. package/src/packlets/invitations/index.ts +4 -4
  46. package/src/packlets/invitations/invitation-protocol.ts +21 -0
  47. package/src/packlets/invitations/invitations-handler.ts +462 -0
  48. package/src/packlets/invitations/invitations-service.ts +127 -104
  49. package/src/packlets/invitations/space-invitation-protocol.test.ts +221 -0
  50. package/src/packlets/invitations/space-invitation-protocol.ts +117 -0
  51. package/src/packlets/services/service-context.test.ts +11 -4
  52. package/src/packlets/services/service-context.ts +34 -17
  53. package/src/packlets/services/service-host.ts +4 -12
  54. package/src/packlets/services/service-registry.test.ts +23 -25
  55. package/src/packlets/spaces/spaces-service.ts +7 -2
  56. package/src/packlets/testing/invitation-utils.ts +219 -31
  57. package/src/packlets/testing/test-builder.ts +30 -19
  58. package/src/packlets/tests/client-services.test.ts +33 -76
  59. package/src/packlets/tests/halo-profile.test.ts +2 -28
  60. package/src/packlets/tests/invitations.test.ts +389 -0
  61. package/src/packlets/tests/spaces-invitations.test.ts +12 -30
  62. package/src/packlets/tests/spaces.test.ts +6 -28
  63. package/src/packlets/vault/worker-runtime.ts +4 -0
  64. package/dist/lib/browser/chunk-H5IXSSI7.mjs.map +0 -7
  65. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts +0 -30
  66. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +0 -1
  67. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts +0 -2
  68. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts.map +0 -1
  69. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts +0 -13
  70. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +0 -1
  71. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts +0 -2
  72. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts.map +0 -1
  73. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +0 -26
  74. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +0 -1
  75. package/dist/types/src/packlets/invitations/space-invitations-handler.test.d.ts +0 -2
  76. package/dist/types/src/packlets/invitations/space-invitations-handler.test.d.ts.map +0 -1
  77. package/dist/types/src/packlets/invitations/space-invitations-service.d.ts +0 -16
  78. package/dist/types/src/packlets/invitations/space-invitations-service.d.ts.map +0 -1
  79. package/dist/types/src/packlets/invitations/space-invitations-service.test.d.ts +0 -2
  80. package/dist/types/src/packlets/invitations/space-invitations-service.test.d.ts.map +0 -1
  81. package/src/packlets/invitations/device-invitations-handler.ts +0 -370
  82. package/src/packlets/invitations/device-invitations-service.test.ts +0 -96
  83. package/src/packlets/invitations/device-invitations-service.ts +0 -24
  84. package/src/packlets/invitations/space-invitations-handler.test.ts +0 -246
  85. package/src/packlets/invitations/space-invitations-handler.ts +0 -463
  86. package/src/packlets/invitations/space-invitations-service.test.ts +0 -129
  87. package/src/packlets/invitations/space-invitations-service.ts +0 -35
@@ -2,7 +2,10 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
+ import assert from 'node:assert';
6
+
5
7
  import { Trigger } from '@dxos/async';
8
+ import { Invitation } from '@dxos/client';
6
9
  import { CredentialConsumer, getCredentialAssertion } from '@dxos/credentials';
7
10
  import { failUndefined } from '@dxos/debug';
8
11
  import {
@@ -25,7 +28,12 @@ import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
25
28
  import { Storage } from '@dxos/random-access-storage';
26
29
 
27
30
  import { CreateIdentityOptions, IdentityManager, JoinIdentityParams } from '../identity';
28
- import { DeviceInvitationsHandler, SpaceInvitationsHandler } from '../invitations';
31
+ import {
32
+ DeviceInvitationProtocol,
33
+ InvitationsHandler,
34
+ InvitationProtocol,
35
+ SpaceInvitationProtocol
36
+ } from '../invitations';
29
37
  import { DataSpaceManager } from '../spaces';
30
38
 
31
39
  /**
@@ -41,13 +49,17 @@ export class ServiceContext {
41
49
  public readonly keyring: Keyring;
42
50
  public readonly spaceManager: SpaceManager;
43
51
  public readonly identityManager: IdentityManager;
44
- public readonly deviceInvitations: DeviceInvitationsHandler;
45
-
46
- private _deviceSpaceSync?: CredentialConsumer<any>;
52
+ public readonly invitations: InvitationsHandler;
47
53
 
48
54
  // Initialized after identity is initialized.
49
55
  public dataSpaceManager?: DataSpaceManager;
50
- public spaceInvitations?: SpaceInvitationsHandler;
56
+
57
+ private readonly _handlerFactories = new Map<
58
+ Invitation.Kind,
59
+ (invitation: Partial<Invitation>) => InvitationProtocol
60
+ >();
61
+
62
+ private _deviceSpaceSync?: CredentialConsumer<any>;
51
63
 
52
64
  private readonly _instanceId = PublicKey.random().toHex();
53
65
 
@@ -84,14 +96,15 @@ export class ServiceContext {
84
96
  this.spaceManager
85
97
  );
86
98
 
99
+ this.invitations = new InvitationsHandler(this.networkManager);
100
+
87
101
  // TODO(burdon): _initialize called in multiple places.
88
102
  // TODO(burdon): Call _initialize on success.
89
- this.deviceInvitations = new DeviceInvitationsHandler({
90
- networkManager: this.networkManager,
91
- getIdentity: () => this.identityManager.identity ?? failUndefined(),
92
- acceptIdentity: this._acceptIdentity.bind(this),
93
- keyring: this.keyring
94
- });
103
+ this._handlerFactories.set(Invitation.Kind.DEVICE, () => new DeviceInvitationProtocol(
104
+ this.keyring,
105
+ () => this.identityManager.identity ?? failUndefined(),
106
+ this._acceptIdentity.bind(this)
107
+ ));
95
108
  }
96
109
 
97
110
  async open() {
@@ -135,6 +148,12 @@ export class ServiceContext {
135
148
  return identity;
136
149
  }
137
150
 
151
+ getInvitationHandler(invitation: Partial<Invitation> & Pick<Invitation, 'kind'>): InvitationProtocol {
152
+ const factory = this._handlerFactories.get(invitation.kind);
153
+ assert(factory, `Unknown invitation kind: ${invitation.kind}`);
154
+ return factory(invitation);
155
+ }
156
+
138
157
  private async _acceptIdentity(params: JoinIdentityParams) {
139
158
  const identity = await this.identityManager.acceptIdentity(params);
140
159
 
@@ -168,12 +187,10 @@ export class ServiceContext {
168
187
  );
169
188
  await this.dataSpaceManager.open();
170
189
 
171
- this.spaceInvitations = new SpaceInvitationsHandler(
172
- this.networkManager,
173
- this.dataSpaceManager,
174
- signingContext,
175
- this.keyring
176
- );
190
+ this._handlerFactories.set(Invitation.Kind.SPACE, (invitation) => {
191
+ assert(this.dataSpaceManager, 'dataSpaceManager not initialized yet');
192
+ return new SpaceInvitationProtocol(this.dataSpaceManager, signingContext, this.keyring, invitation.spaceKey);
193
+ });
177
194
  this.initialized.wake();
178
195
 
179
196
  this._deviceSpaceSync = identity.space.spaceState.registerProcessor({
@@ -7,7 +7,6 @@ import assert from 'node:assert';
7
7
  import { Event } from '@dxos/async';
8
8
  import { clientServiceBundle, ClientServices, createDefaultModelFactory, PublicKey } from '@dxos/client';
9
9
  import { Config } from '@dxos/config';
10
- import { raise } from '@dxos/debug';
11
10
  import { DataServiceImpl } from '@dxos/echo-pipeline';
12
11
  import { log } from '@dxos/log';
13
12
  import { ModelFactory } from '@dxos/model-factory';
@@ -20,7 +19,7 @@ import { TracingServiceImpl } from '../deprecated';
20
19
  import { DevicesServiceImpl } from '../devices';
21
20
  import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
22
21
  import { IdentityServiceImpl } from '../identity';
23
- import { DeviceInvitationsServiceImpl, SpaceInvitationsServiceImpl } from '../invitations';
22
+ import { InvitationsServiceImpl } from '../invitations';
24
23
  import { NetworkServiceImpl } from '../network';
25
24
  import { SpacesServiceImpl } from '../spaces';
26
25
  import { createStorageObjects } from '../storage';
@@ -185,18 +184,11 @@ export class ClientServicesHost {
185
184
 
186
185
  IdentityService: new IdentityServiceImpl(this._serviceContext),
187
186
 
188
- DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
189
-
190
- DeviceInvitationsService: new DeviceInvitationsServiceImpl(
191
- this._serviceContext.identityManager,
192
- this._serviceContext.deviceInvitations
187
+ InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitations, (invitation) =>
188
+ this._serviceContext.getInvitationHandler(invitation)
193
189
  ),
194
190
 
195
- SpaceInvitationsService: new SpaceInvitationsServiceImpl(
196
- this._serviceContext.identityManager,
197
- () => this._serviceContext.spaceInvitations ?? raise(new Error('SpaceInvitations not initialized')),
198
- () => this._serviceContext.dataSpaceManager ?? raise(new Error('SpaceManager not initialized'))
199
- ),
191
+ DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
200
192
 
201
193
  SpacesService: new SpacesServiceImpl(
202
194
  this._serviceContext.identityManager,
@@ -5,25 +5,25 @@
5
5
  import assert from 'node:assert';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
- import { ClientServices, SpaceInvitationsProxy } from '@dxos/client';
8
+ import { ClientServices, InvitationsProxy } from '@dxos/client';
9
9
  import { log } from '@dxos/log';
10
10
  import { schema } from '@dxos/protocols';
11
- import { Invitation, SpaceInvitationsService } from '@dxos/protocols/proto/dxos/client/services';
11
+ import { Invitation, InvitationsService } from '@dxos/protocols/proto/dxos/client/services';
12
12
  import { createLinkedPorts, createProtoRpcPeer, createServiceBundle } from '@dxos/rpc';
13
13
  import { describe, test } from '@dxos/test';
14
14
 
15
- import { SpaceInvitationsServiceImpl } from '../invitations';
15
+ import { InvitationsServiceImpl } from '../invitations';
16
16
  import { createServiceContext } from '../testing';
17
17
  import { ServiceRegistry } from './service-registry';
18
18
 
19
19
  // TODO(burdon): Create TestService (that doesn't require peers).
20
20
 
21
21
  type TestServices = {
22
- SpaceInvitationsService: SpaceInvitationsService;
22
+ InvitationsService: InvitationsService;
23
23
  };
24
24
 
25
25
  const serviceBundle = createServiceBundle<TestServices>({
26
- SpaceInvitationsService: schema.getService('dxos.client.services.SpaceInvitationsService')
26
+ InvitationsService: schema.getService('dxos.client.services.InvitationsService')
27
27
  });
28
28
 
29
29
  describe('service registry', () => {
@@ -33,14 +33,11 @@ describe('service registry', () => {
33
33
  await serviceContext.createIdentity();
34
34
 
35
35
  assert(serviceContext.dataSpaceManager);
36
- assert(serviceContext.spaceInvitations);
37
36
  const space = await serviceContext.dataSpaceManager.createSpace();
38
37
 
39
38
  const serviceRegistry = new ServiceRegistry(serviceBundle, {
40
- SpaceInvitationsService: new SpaceInvitationsServiceImpl(
41
- serviceContext.identityManager,
42
- () => serviceContext.spaceInvitations!,
43
- () => serviceContext.dataSpaceManager!
39
+ InvitationsService: new InvitationsServiceImpl(serviceContext.invitations, (invitation) =>
40
+ serviceContext.getInvitationHandler(invitation)
44
41
  )
45
42
  });
46
43
 
@@ -66,21 +63,22 @@ describe('service registry', () => {
66
63
  const done = new Trigger(); // createRpcServer
67
64
 
68
65
  {
69
- const spaceInvitationsProxy = new SpaceInvitationsProxy(proxy.rpc.SpaceInvitationsService);
70
- const observer = spaceInvitationsProxy.createInvitation(space.key);
71
- observer.subscribe({
72
- onConnecting: (invitation: Invitation) => {
73
- log('connecting', invitation);
74
- void observer.cancel();
75
- },
76
- onCancelled: () => {
77
- done.wake();
78
- },
79
- onSuccess: (_invitation: Invitation) => {
80
- throw new Error('Not not implemented.');
81
- },
82
- onError: () => {
83
- throw new Error('Not not implemented.');
66
+ const spaceInvitationsProxy = new InvitationsProxy(proxy.rpc.InvitationsService, () => ({
67
+ kind: Invitation.Kind.SPACE,
68
+ spaceKey: space.key
69
+ }));
70
+ const observer = spaceInvitationsProxy.createInvitation();
71
+ observer.subscribe((invitation: Invitation) => {
72
+ switch (invitation.state) {
73
+ case Invitation.State.CONNECTING: {
74
+ log('connecting', invitation);
75
+ void observer.cancel();
76
+ break;
77
+ }
78
+
79
+ case Invitation.State.CANCELLED: {
80
+ done.wake();
81
+ }
84
82
  }
85
83
  });
86
84
  }
@@ -149,10 +149,15 @@ export class SpacesServiceImpl implements SpacesService {
149
149
  spaceKey: space.key,
150
150
  state: space.state,
151
151
  pipeline: {
152
- targetControlTimeframe: space.inner.controlPipeline.state.targetTimeframe,
152
+ controlFeeds: space.inner.controlPipeline.state.feeds.map((feed) => feed.key),
153
153
  currentControlTimeframe: space.inner.controlPipeline.state.timeframe,
154
+ targetControlTimeframe: space.inner.controlPipeline.state.targetTimeframe,
155
+ totalControlTimeframe: space.inner.controlPipeline.state.endTimeframe,
156
+
157
+ dataFeeds: space.dataPipeline.pipelineState?.feeds.map((feed) => feed.key) ?? [],
154
158
  currentDataTimeframe: space.dataPipeline.pipelineState?.timeframe,
155
- targetDataTimeframe: space.dataPipeline.pipelineState?.targetTimeframe
159
+ targetDataTimeframe: space.dataPipeline.pipelineState?.targetTimeframe,
160
+ totalDataTimeframe: space.dataPipeline.pipelineState?.endTimeframe
156
161
  },
157
162
  members: Array.from(space.inner.spaceState.members.values()).map((member) => ({
158
163
  identity: {
@@ -5,39 +5,227 @@
5
5
  import assert from 'node:assert';
6
6
 
7
7
  import { Trigger } from '@dxos/async';
8
- import { InvitationsHandler } from '@dxos/client';
9
- import { raise } from '@dxos/debug';
8
+ import {
9
+ AuthenticatingInvitationObservable,
10
+ CancellableInvitationObservable,
11
+ Client,
12
+ EchoProxy,
13
+ HaloProxy,
14
+ InvitationsProxy,
15
+ SpaceProxy
16
+ } from '@dxos/client';
10
17
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
11
18
 
12
- export const performInvitation = async <T>(host: InvitationsHandler<T>, guest: InvitationsHandler<T>, context: T) => {
13
- const done1 = new Trigger<Invitation>(); // peer 1 connected.
14
- const done2 = new Trigger<Invitation>(); // peer 2 connected.
15
- const observable1 = await host.createInvitation(context, { type: Invitation.Type.INTERACTIVE_TESTING });
16
- observable1.subscribe({
17
- onConnecting: async (invitation1: Invitation) => {
18
- const observable2 = await guest.acceptInvitation(invitation1, { type: Invitation.Type.INTERACTIVE_TESTING });
19
- observable2.subscribe({
20
- onConnecting: async (invitation2: Invitation) => {
21
- assert(invitation1.swarmKey!.equals(invitation2.swarmKey!));
22
- },
23
- onConnected: async (invitation2: Invitation) => {},
24
- onSuccess: (invitation) => {
25
- done2.wake(invitation);
26
- },
27
- onCancelled: () => raise(new Error()),
28
- onTimeout: (err: Error) => raise(err),
29
- onError: (err: Error) => raise(err)
30
- });
31
- },
32
- onConnected: async (invitation1: Invitation) => {},
33
- onCancelled: () => raise(new Error('cancelled')),
34
- onSuccess: (invitation) => {
35
- done1.wake(invitation);
19
+ import { ServiceContext } from '../services';
20
+
21
+ /**
22
+ * Strip secrets from invitation before giving it to the peer.
23
+ */
24
+ export const sanitizeInvitation = (invitation: Invitation): Invitation => {
25
+ return {
26
+ invitationId: invitation.invitationId,
27
+ type: invitation.type,
28
+ kind: invitation.kind,
29
+ authMethod: invitation.authMethod,
30
+ swarmKey: invitation.swarmKey,
31
+ state: invitation.state,
32
+ timeout: invitation.timeout
33
+ };
34
+ };
35
+
36
+ export type PerformInvitationCallbacks<T> = {
37
+ onConnecting?: (value: T) => boolean | void;
38
+ onConnected?: (value: T) => boolean | void;
39
+ onReady?: (value: T) => boolean | void;
40
+ onAuthenticating?: (value: T) => boolean | void;
41
+ onSuccess?: (value: T) => boolean | void;
42
+ onCancelled?: (value: T) => boolean | void;
43
+ onTimeout?: (value: T) => boolean | void;
44
+ onError?: (value: T) => boolean | void;
45
+ };
46
+
47
+ export type PerformInvitationParams = {
48
+ host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy;
49
+ guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client;
50
+ options?: Partial<Invitation>;
51
+ hooks?: {
52
+ host?: PerformInvitationCallbacks<CancellableInvitationObservable>;
53
+ guest?: PerformInvitationCallbacks<AuthenticatingInvitationObservable>;
54
+ };
55
+ };
56
+
57
+ export type Result = { invitation?: Invitation; error?: Error };
58
+
59
+ export const performInvitation = ({
60
+ host,
61
+ guest,
62
+ options,
63
+ hooks
64
+ }: PerformInvitationParams): [Promise<Result>, Promise<Result>] => {
65
+ const hostComplete = new Trigger<Result>();
66
+ const guestComplete = new Trigger<Result>();
67
+ const authCode = new Trigger<string>();
68
+
69
+ const hostObservable = createInvitation(host, options);
70
+ hostObservable.subscribe(
71
+ async (hostInvitation: Invitation) => {
72
+ switch (hostInvitation.state) {
73
+ case Invitation.State.CONNECTING: {
74
+ if (hooks?.host?.onConnecting?.(hostObservable)) {
75
+ break;
76
+ }
77
+ const guestObservable = acceptInvitation(guest, hostInvitation);
78
+ guestObservable.subscribe(
79
+ async (guestInvitation: Invitation) => {
80
+ switch (guestInvitation.state) {
81
+ case Invitation.State.CONNECTING: {
82
+ if (hooks?.guest?.onConnecting?.(guestObservable)) {
83
+ break;
84
+ }
85
+ assert(hostInvitation.swarmKey!.equals(guestInvitation.swarmKey!));
86
+ break;
87
+ }
88
+
89
+ case Invitation.State.CONNECTED: {
90
+ hooks?.guest?.onConnected?.(guestObservable);
91
+ break;
92
+ }
93
+
94
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
95
+ if (hooks?.guest?.onReady?.(guestObservable)) {
96
+ break;
97
+ }
98
+ await guestObservable.authenticate(await authCode.wait());
99
+ break;
100
+ }
101
+
102
+ case Invitation.State.AUTHENTICATING: {
103
+ hooks?.guest?.onAuthenticating?.(guestObservable);
104
+ break;
105
+ }
106
+
107
+ case Invitation.State.SUCCESS: {
108
+ if (hooks?.guest?.onSuccess?.(guestObservable)) {
109
+ break;
110
+ }
111
+ guestComplete.wake({ invitation: guestInvitation });
112
+ break;
113
+ }
114
+
115
+ case Invitation.State.CANCELLED: {
116
+ if (hooks?.guest?.onCancelled?.(guestObservable)) {
117
+ break;
118
+ }
119
+ guestComplete.wake({ invitation: guestInvitation });
120
+ break;
121
+ }
122
+
123
+ case Invitation.State.TIMEOUT: {
124
+ if (hooks?.guest?.onTimeout?.(guestObservable)) {
125
+ return;
126
+ }
127
+ guestComplete.wake({ invitation: guestInvitation });
128
+ }
129
+ }
130
+ },
131
+ (error: Error) => {
132
+ if (hooks?.guest?.onError?.(guestObservable)) {
133
+ return;
134
+ }
135
+ guestComplete.wake({ error });
136
+ }
137
+ );
138
+ break;
139
+ }
140
+
141
+ case Invitation.State.CONNECTED: {
142
+ hooks?.host?.onConnected?.(hostObservable);
143
+ break;
144
+ }
145
+
146
+ case Invitation.State.READY_FOR_AUTHENTICATION: {
147
+ if (hooks?.host?.onReady?.(hostObservable)) {
148
+ break;
149
+ }
150
+ if (hostInvitation.authCode) {
151
+ authCode.wake(hostInvitation.authCode);
152
+ }
153
+ break;
154
+ }
155
+
156
+ case Invitation.State.AUTHENTICATING: {
157
+ hooks?.host?.onAuthenticating?.(hostObservable);
158
+ break;
159
+ }
160
+
161
+ case Invitation.State.SUCCESS: {
162
+ if (hooks?.host?.onSuccess?.(hostObservable)) {
163
+ break;
164
+ }
165
+ hostComplete.wake({ invitation: hostInvitation });
166
+ break;
167
+ }
168
+
169
+ case Invitation.State.CANCELLED: {
170
+ if (hooks?.host?.onCancelled?.(hostObservable)) {
171
+ break;
172
+ }
173
+ hostComplete.wake({ invitation: hostInvitation });
174
+ break;
175
+ }
176
+
177
+ case Invitation.State.TIMEOUT: {
178
+ if (hooks?.host?.onTimeout?.(hostObservable)) {
179
+ break;
180
+ }
181
+ hostComplete.wake({ invitation: hostInvitation });
182
+ break;
183
+ }
184
+ }
36
185
  },
37
- onTimeout: (err: Error) => raise(err),
38
- onError: (err: Error) => raise(err)
39
- });
186
+ (error: Error) => {
187
+ if (hooks?.host?.onError?.(hostObservable)) {
188
+ return;
189
+ }
190
+ hostComplete.wake({ error });
191
+ }
192
+ );
193
+
194
+ return [hostComplete.wait(), guestComplete.wait()];
195
+ };
196
+
197
+ const createInvitation = (
198
+ host: ServiceContext | InvitationsProxy | HaloProxy | SpaceProxy,
199
+ options?: Partial<Invitation>
200
+ ): CancellableInvitationObservable => {
201
+ options ??= {
202
+ authMethod: Invitation.AuthMethod.NONE,
203
+ ...(options ?? {})
204
+ };
205
+
206
+ if (host instanceof InvitationsProxy || host instanceof HaloProxy || host instanceof SpaceProxy) {
207
+ return host.createInvitation(options);
208
+ }
209
+
210
+ const hostHandler = host.getInvitationHandler({ kind: Invitation.Kind.SPACE, ...options });
211
+ return host.invitations.createInvitation(hostHandler, options);
212
+ };
213
+
214
+ const acceptInvitation = (
215
+ guest: ServiceContext | InvitationsProxy | HaloProxy | EchoProxy | Client,
216
+ invitation: Invitation
217
+ ): AuthenticatingInvitationObservable => {
218
+ invitation = sanitizeInvitation(invitation);
219
+
220
+ if (
221
+ guest instanceof InvitationsProxy ||
222
+ guest instanceof HaloProxy ||
223
+ guest instanceof EchoProxy ||
224
+ guest instanceof Client
225
+ ) {
226
+ return guest.acceptInvitation(invitation);
227
+ }
40
228
 
41
- await done1.wait();
42
- await done2.wait();
229
+ const guestHandler = guest.getInvitationHandler({ kind: invitation.kind });
230
+ return guest.invitations.acceptInvitation(guestHandler, invitation);
43
231
  };
@@ -150,27 +150,38 @@ export const joinCommonSpace = async ([initialPeer, ...peers]: Client[], spaceKe
150
150
  const hostDone = new Trigger<Invitation>();
151
151
  const guestDone = new Trigger<Invitation>();
152
152
 
153
- const hostObservabli = rootSpace.createInvitation({ type: Invitation.Type.INTERACTIVE_TESTING });
153
+ const hostObservable = rootSpace.createInvitation({ authMethod: Invitation.AuthMethod.NONE });
154
154
  log('invitation created');
155
- hostObservabli.subscribe({
156
- onConnecting: (invitation) => {
157
- const guestObservable = peer.acceptInvitation(invitation);
158
- log('invitation accepted');
159
-
160
- guestObservable.subscribe({
161
- onSuccess: (invitation: Invitation) => {
162
- guestDone.wake(invitation);
163
- log('invitation guestDone');
164
- },
165
- onError: (err: Error) => raise(err)
166
- });
155
+ hostObservable.subscribe(
156
+ (hostInvitation) => {
157
+ switch (hostInvitation.state) {
158
+ case Invitation.State.CONNECTING: {
159
+ const guestObservable = peer.acceptInvitation(hostInvitation);
160
+ log('invitation accepted');
161
+
162
+ guestObservable.subscribe(
163
+ (guestInvitation) => {
164
+ switch (guestInvitation.state) {
165
+ case Invitation.State.SUCCESS: {
166
+ guestDone.wake(guestInvitation);
167
+ log('invitation guestDone');
168
+ break;
169
+ }
170
+ }
171
+ },
172
+ (err) => raise(err)
173
+ );
174
+ break;
175
+ }
176
+
177
+ case Invitation.State.SUCCESS: {
178
+ hostDone.wake(hostInvitation);
179
+ log('invitation hostDone');
180
+ }
181
+ }
167
182
  },
168
- onSuccess: (invitation) => {
169
- hostDone.wake(invitation);
170
- log('invitation hostDone');
171
- },
172
- onError: (err) => raise(err)
173
- });
183
+ (err) => raise(err)
184
+ );
174
185
 
175
186
  await Promise.all([hostDone.wait(), guestDone.wait()]);
176
187
  })