@dxos/client-services 0.6.14-main.8b352a0 → 0.6.14-staging.3e2eaca

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-Y5D7T3I7.mjs → chunk-GQWG2754.mjs} +169 -142
  2. package/dist/lib/browser/chunk-GQWG2754.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/testing/index.mjs +9 -2
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/node/{chunk-DARYUWYV.cjs → chunk-4SK56Z44.cjs} +177 -150
  8. package/dist/lib/node/chunk-4SK56Z44.cjs.map +7 -0
  9. package/dist/lib/node/index.cjs +47 -47
  10. package/dist/lib/node/meta.json +1 -1
  11. package/dist/lib/node/testing/index.cjs +16 -9
  12. package/dist/lib/node/testing/index.cjs.map +3 -3
  13. package/dist/lib/node-esm/{chunk-RVNJ6XZO.mjs → chunk-POX3HG6I.mjs} +169 -142
  14. package/dist/lib/node-esm/chunk-POX3HG6I.mjs.map +7 -0
  15. package/dist/lib/node-esm/index.mjs +1 -1
  16. package/dist/lib/node-esm/meta.json +1 -1
  17. package/dist/lib/node-esm/testing/index.mjs +9 -2
  18. package/dist/lib/node-esm/testing/index.mjs.map +3 -3
  19. package/dist/types/src/packlets/devices/devices-service.d.ts +3 -1
  20. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
  21. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +1 -0
  22. package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
  23. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  24. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  25. package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
  26. package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
  27. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +1 -0
  28. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  29. package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
  30. package/dist/types/src/version.d.ts +1 -1
  31. package/dist/types/src/version.d.ts.map +1 -1
  32. package/package.json +38 -38
  33. package/src/packlets/devices/devices-service.ts +18 -7
  34. package/src/packlets/identity/identity.test.ts +16 -5
  35. package/src/packlets/invitations/edge-invitation-handler.ts +6 -3
  36. package/src/packlets/invitations/invitation-guest-extenstion.ts +5 -5
  37. package/src/packlets/invitations/invitation-host-extension.ts +7 -10
  38. package/src/packlets/invitations/invitations-handler.test.ts +3 -6
  39. package/src/packlets/invitations/invitations-handler.ts +34 -28
  40. package/src/packlets/invitations/invitations-manager.ts +5 -3
  41. package/src/packlets/invitations/invitations-service.ts +5 -1
  42. package/src/packlets/services/service-context.ts +2 -2
  43. package/src/packlets/services/service-host.ts +1 -1
  44. package/src/packlets/spaces/edge-feed-replicator.test.ts +12 -7
  45. package/src/packlets/spaces/edge-feed-replicator.ts +9 -5
  46. package/src/packlets/testing/invitation-utils.ts +7 -0
  47. package/src/version.ts +1 -1
  48. package/dist/lib/browser/chunk-Y5D7T3I7.mjs.map +0 -7
  49. package/dist/lib/node/chunk-DARYUWYV.cjs.map +0 -7
  50. package/dist/lib/node-esm/chunk-RVNJ6XZO.mjs.map +0 -7
@@ -125,7 +125,7 @@ export class InvitationHostExtension
125
125
  };
126
126
  }
127
127
 
128
- log('guest introduced themselves', { guestProfile: profile });
128
+ log.verbose('guest introduced themselves', { guestProfile: profile });
129
129
  this.guestProfile = profile;
130
130
  this._callbacks.onStateUpdate(Invitation.State.READY_FOR_AUTHENTICATION);
131
131
  this._challenge =
@@ -143,7 +143,7 @@ export class InvitationHostExtension
143
143
  log.trace('dxos.sdk.invitation-handler.host.authenticate', trace.begin({ id: traceId }));
144
144
 
145
145
  const invitation = this._requireActiveInvitation();
146
- log('received authentication request', { authCode: code });
146
+ log.verbose('received authentication request', { authCode: code });
147
147
  let status = AuthenticationResponse.Status.OK;
148
148
 
149
149
  this._assertInvitationState([Invitation.State.AUTHENTICATING, Invitation.State.READY_FOR_AUTHENTICATION]);
@@ -236,18 +236,15 @@ export class InvitationHostExtension
236
236
  await super.onOpen(context);
237
237
 
238
238
  try {
239
- log('host acquire lock');
239
+ log.verbose('host acquire lock');
240
240
  this._invitationFlowLock = await tryAcquireBeforeContextDisposed(this._ctx, this._invitationFlowMutex);
241
- log('host lock acquired');
242
- const lastState = this._requireActiveInvitation().state;
241
+ log.verbose('host lock acquired');
243
242
  this._callbacks.onStateUpdate(Invitation.State.CONNECTING);
244
243
  await this.rpc.InvitationHostService.options({ role: InvitationOptions.Role.HOST });
245
- log('options sent');
244
+ log.verbose('options sent');
246
245
  await cancelWithContext(this._ctx, this._remoteOptionsTrigger.wait({ timeout: OPTIONS_TIMEOUT }));
247
- log('options received');
246
+ log.verbose('options received');
248
247
  if (this._remoteOptions?.role !== InvitationOptions.Role.GUEST) {
249
- // we connected with another host, restore previous real invitation flow status
250
- this._callbacks.onStateUpdate(lastState);
251
248
  throw new InvalidInvitationExtensionRoleError(undefined, {
252
249
  expected: InvitationOptions.Role.GUEST,
253
250
  remoteOptions: this._remoteOptions,
@@ -299,7 +296,7 @@ export class InvitationHostExtension
299
296
  if (this._invitationFlowLock != null) {
300
297
  this._invitationFlowLock?.release();
301
298
  this._invitationFlowLock = null;
302
- log('invitation flow lock released');
299
+ log.verbose('invitation flow lock released');
303
300
  }
304
301
  }
305
302
  }
@@ -71,7 +71,7 @@ describe('InvitationHandler', () => {
71
71
 
72
72
  await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
73
73
  await sleep(200);
74
- await host.sink.waitFor(Invitation.State.TIMEOUT);
74
+ await host.sink.waitFor(Invitation.State.CONNECTING);
75
75
  await guest.sink.waitFor(Invitation.State.TIMEOUT);
76
76
 
77
77
  await sleep(10);
@@ -91,7 +91,7 @@ describe('InvitationHandler', () => {
91
91
 
92
92
  await guest.sink.waitFor(Invitation.State.READY_FOR_AUTHENTICATION);
93
93
  await guest.peer.networkManager.close();
94
- await host.sink.waitFor(Invitation.State.ERROR);
94
+ await host.sink.waitFor(Invitation.State.CONNECTING);
95
95
 
96
96
  await sleep(10);
97
97
  expect(host.ctx.disposed).to.be.false;
@@ -134,7 +134,7 @@ describe('InvitationHandler', () => {
134
134
  const host = await createPeer();
135
135
  const invitation = await createInvitation(host, { multiUse: true });
136
136
  await hostInvitation(host, invitation);
137
- const anotherHost = await createNewHost(invitation);
137
+ await createNewHost(invitation);
138
138
 
139
139
  const guest = await createPeer(host.spaceKey);
140
140
  const codeInput = await failAuth(guest, invitation);
@@ -143,9 +143,6 @@ describe('InvitationHandler', () => {
143
143
  await sleep(10);
144
144
  }
145
145
  await guest.sink.waitFor(Invitation.State.SUCCESS);
146
-
147
- const hostFailed = [host, anotherHost].map((h) => h.sink.hasState(0, Invitation.State.ERROR));
148
- expect(hostFailed.sort()).to.deep.eq([false, true]);
149
146
  });
150
147
 
151
148
  test('single guest - many hosts', async () => {
@@ -86,7 +86,7 @@ export class InvitationsHandler {
86
86
  kind: invitation.kind,
87
87
  type: invitation.type,
88
88
  });
89
- metrics.increment('dxos.invitation.created');
89
+ metrics.increment('dxos.invitation.host');
90
90
  const guardedState = createGuardedInvitationState(ctx, invitation, stream);
91
91
  // Called for every connecting peer.
92
92
  const createExtension = (): InvitationHostExtension => {
@@ -96,7 +96,9 @@ export class InvitationsHandler {
96
96
  },
97
97
 
98
98
  onStateUpdate: (newState: Invitation.State): Invitation => {
99
- guardedState.set(extension, newState);
99
+ if (newState !== Invitation.State.ERROR && newState !== Invitation.State.TIMEOUT) {
100
+ guardedState.set(extension, newState);
101
+ }
100
102
  return guardedState.current;
101
103
  },
102
104
 
@@ -125,7 +127,7 @@ export class InvitationsHandler {
125
127
  let admitted = false;
126
128
  connectionCtx.onDispose(() => {
127
129
  if (!admitted) {
128
- guardedState.error(extension, new ContextDisposedError());
130
+ guardedState.set(extension, Invitation.State.CONNECTING);
129
131
  }
130
132
  });
131
133
 
@@ -133,9 +135,9 @@ export class InvitationsHandler {
133
135
  const traceId = PublicKey.random().toHex();
134
136
  try {
135
137
  log.trace('dxos.sdk.invitations-handler.host.onOpen', trace.begin({ id: traceId }));
136
- log('connected', { ...protocol.toJSON() });
138
+ log.verbose('connected', { ...protocol.toJSON() });
137
139
  const deviceKey = await extension.completedTrigger.wait({ timeout: invitation.timeout });
138
- log('admitted guest', { guest: deviceKey, ...protocol.toJSON() });
140
+ log.verbose('admitted guest', { guest: deviceKey, ...protocol.toJSON() });
139
141
  guardedState.set(extension, Invitation.State.SUCCESS);
140
142
  metrics.increment('dxos.invitation.success');
141
143
  log.trace('dxos.sdk.invitations-handler.host.onOpen', trace.end({ id: traceId }));
@@ -145,13 +147,14 @@ export class InvitationsHandler {
145
147
  await ctx.dispose();
146
148
  }
147
149
  } catch (err: any) {
150
+ const stateChanged = guardedState.set(extension, Invitation.State.CONNECTING);
148
151
  if (err instanceof TimeoutError) {
149
- if (guardedState.set(extension, Invitation.State.TIMEOUT)) {
152
+ if (stateChanged) {
150
153
  metrics.increment('dxos.invitation.timeout');
151
- log('timeout', { ...protocol.toJSON() });
154
+ log.verbose('timeout', { ...protocol.toJSON() });
152
155
  }
153
156
  } else {
154
- if (guardedState.error(extension, err)) {
157
+ if (stateChanged) {
155
158
  metrics.increment('dxos.invitation.failed');
156
159
  log.error('failed', err);
157
160
  }
@@ -163,17 +166,18 @@ export class InvitationsHandler {
163
166
  });
164
167
  },
165
168
  onError: (err) => {
169
+ const stateChanged = guardedState.set(extension, Invitation.State.CONNECTING);
166
170
  if (err instanceof InvalidInvitationExtensionRoleError) {
167
171
  log('invalid role', { ...err.context });
168
172
  return;
169
173
  }
170
174
  if (err instanceof TimeoutError) {
171
- if (guardedState.set(extension, Invitation.State.TIMEOUT)) {
175
+ if (stateChanged) {
172
176
  metrics.increment('dxos.invitation.timeout');
173
- log('timeout', { err });
177
+ log.verbose('timeout', { err });
174
178
  }
175
179
  } else {
176
- if (guardedState.error(extension, err)) {
180
+ if (stateChanged) {
177
181
  metrics.increment('dxos.invitation.failed');
178
182
  log.error('failed', err);
179
183
  }
@@ -187,19 +191,21 @@ export class InvitationsHandler {
187
191
  if (invitation.lifetime && invitation.created) {
188
192
  if (invitation.created.getTime() + invitation.lifetime * 1000 < Date.now()) {
189
193
  log.warn('invitation has already expired');
190
- } else {
191
- scheduleTask(
192
- ctx,
193
- async () => {
194
- // ensure the swarm is closed before changing state and closing the stream.
195
- await swarmConnection.close();
196
- guardedState.set(null, Invitation.State.EXPIRED);
197
- metrics.increment('dxos.invitation.expired');
198
- await ctx.dispose();
199
- },
200
- invitation.created.getTime() + invitation.lifetime * 1000 - Date.now(),
201
- );
194
+ guardedState.set(null, Invitation.State.EXPIRED);
195
+ void ctx.dispose().catch((err) => log.catch(err));
196
+ return;
202
197
  }
198
+ scheduleTask(
199
+ ctx,
200
+ async () => {
201
+ // ensure the swarm is closed before changing state and closing the stream.
202
+ await swarmConnection.close();
203
+ guardedState.set(null, Invitation.State.EXPIRED);
204
+ metrics.increment('dxos.invitation.expired');
205
+ await ctx.dispose();
206
+ },
207
+ invitation.created.getTime() + invitation.lifetime * 1000 - Date.now(),
208
+ );
203
209
  }
204
210
 
205
211
  let swarmConnection: SwarmConnection;
@@ -262,7 +268,7 @@ export class InvitationsHandler {
262
268
  }
263
269
 
264
270
  connectionCtx.onDispose(async () => {
265
- log('extension disposed', { admitted, currentState: guardedState.current.state });
271
+ log.verbose('extension disposed', { admitted, currentState: guardedState.current.state });
266
272
  if (!admitted) {
267
273
  guardedState.error(extension, new ContextDisposedError());
268
274
  if (shouldCancelInvitationFlow(extension)) {
@@ -353,10 +359,10 @@ export class InvitationsHandler {
353
359
  log.trace('dxos.sdk.invitations-handler.guest.onOpen', trace.end({ id: traceId }));
354
360
  } catch (err: any) {
355
361
  if (err instanceof TimeoutError) {
356
- log('timeout', { ...protocol.toJSON() });
362
+ log.verbose('timeout', { ...protocol.toJSON() });
357
363
  guardedState.set(extension, Invitation.State.TIMEOUT);
358
364
  } else {
359
- log('auth failed', err);
365
+ log.verbose('auth failed', err);
360
366
  guardedState.error(extension, err);
361
367
  }
362
368
  extensionCtx.close(err);
@@ -369,10 +375,10 @@ export class InvitationsHandler {
369
375
  return;
370
376
  }
371
377
  if (err instanceof TimeoutError) {
372
- log('timeout', { ...protocol.toJSON() });
378
+ log.verbose('timeout', { ...protocol.toJSON() });
373
379
  guardedState.set(extension, Invitation.State.TIMEOUT);
374
380
  } else {
375
- log('auth failed', err);
381
+ log.verbose('auth failed', err);
376
382
  guardedState.error(extension, err);
377
383
  }
378
384
  },
@@ -190,7 +190,7 @@ export class InvitationsManager {
190
190
  }
191
191
  }
192
192
 
193
- private _createInvitation(protocol: InvitationProtocol, options?: Partial<Invitation>): Invitation {
193
+ private _createInvitation(protocol: InvitationProtocol, _options?: Partial<Invitation>): Invitation {
194
194
  const {
195
195
  invitationId = PublicKey.random().toHex(),
196
196
  type = Invitation.Type.INTERACTIVE,
@@ -198,13 +198,14 @@ export class InvitationsManager {
198
198
  state = Invitation.State.INIT,
199
199
  timeout = INVITATION_TIMEOUT,
200
200
  swarmKey = PublicKey.random(),
201
- persistent = options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
201
+ persistent = _options?.authMethod !== Invitation.AuthMethod.KNOWN_PUBLIC_KEY, // default no not storing keypairs
202
202
  created = new Date(),
203
203
  guestKeypair = undefined,
204
204
  role = SpaceMember.Role.ADMIN,
205
205
  lifetime = 86400, // 1 day,
206
206
  multiUse = false,
207
- } = options ?? {};
207
+ ...options
208
+ } = _options ?? {};
208
209
  const authCode =
209
210
  options?.authCode ??
210
211
  (authMethod === Invitation.AuthMethod.SHARED_SECRET ? generatePasscode(AUTHENTICATION_CODE_LENGTH) : undefined);
@@ -225,6 +226,7 @@ export class InvitationsManager {
225
226
  role,
226
227
  multiUse,
227
228
  delegationCredentialId: options?.delegationCredentialId,
229
+ ...options,
228
230
  ...protocol.getInvitationContext(),
229
231
  } satisfies Invitation;
230
232
  }
@@ -10,6 +10,7 @@ import {
10
10
  type InvitationsService,
11
11
  QueryInvitationsResponse,
12
12
  } from '@dxos/protocols/proto/dxos/client/services';
13
+ import { trace } from '@dxos/tracing';
13
14
 
14
15
  import { type InvitationsManager } from './invitations-manager';
15
16
 
@@ -30,7 +31,10 @@ export class InvitationsServiceImpl implements InvitationsService {
30
31
  return new Stream<Invitation>(({ next, close }) => {
31
32
  void this._invitationsManager
32
33
  .createInvitation(options)
33
- .then((invitation) => invitation.subscribe(next, close, close))
34
+ .then((invitation) => {
35
+ trace.metrics.increment('dxos.invitation.created');
36
+ invitation.subscribe(next, close, close);
37
+ })
34
38
  .catch(close);
35
39
  });
36
40
  }
@@ -381,12 +381,12 @@ export class ServiceContext extends Resource {
381
381
  identity: identity.identityKey.toHex(),
382
382
  swarms: this.networkManager.topics,
383
383
  });
384
- if (params?.deviceCredential) {
384
+ if (params?.deviceCredential || Boolean((globalThis as any)?.DEVICE_INVITE_INTEROP)) {
385
385
  edgeIdentity = await createChainEdgeIdentity(
386
386
  identity.signer,
387
387
  identity.identityKey,
388
388
  identity.deviceKey,
389
- { credential: params.deviceCredential },
389
+ params?.deviceCredential && { credential: params.deviceCredential },
390
390
  [], // TODO(dmaretskyi): Service access credentials.
391
391
  );
392
392
  } else {
@@ -318,7 +318,7 @@ export class ClientServicesHost {
318
318
 
319
319
  InvitationsService: new InvitationsServiceImpl(this._serviceContext.invitationsManager),
320
320
 
321
- DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
321
+ DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager, this._edgeConnection),
322
322
 
323
323
  SpacesService: new SpacesServiceImpl(
324
324
  this._serviceContext.identityManager,
@@ -65,15 +65,16 @@ describe('EdgeFeedReplicator', () => {
65
65
 
66
66
  test('re-requests metadata on reconnect', async () => {
67
67
  const { endpoint, admitConnection, messageSink } = await createEdge();
68
- const { messenger } = await createClient(endpoint);
68
+ const { messenger, reconnectTrigger } = await createClient(endpoint);
69
69
 
70
70
  await attachReplicator(messenger);
71
71
 
72
72
  admitConnection.wake();
73
73
  await expect.poll(() => messageSink.length).toEqual(1);
74
74
 
75
+ reconnectTrigger.reset();
75
76
  await updateIdentity(messenger);
76
- await messenger.reconnect.waitForCount(1);
77
+ await reconnectTrigger.wait();
77
78
 
78
79
  await expect.poll(() => messageSink.length).toEqual(2);
79
80
  expect(messageSink[1].type).toEqual('get-metadata');
@@ -100,7 +101,7 @@ describe('EdgeFeedReplicator', () => {
100
101
 
101
102
  test('recovers after response sending failure during identity change', async () => {
102
103
  const { endpoint, admitConnection, messageSink, sendResponseMessage } = await createEdge();
103
- const { messenger, sendSpy } = await createClient(endpoint);
104
+ const { messenger, sendSpy, reconnectTrigger } = await createClient(endpoint);
104
105
 
105
106
  const { feed } = await attachReplicator(messenger);
106
107
  await appendMessage(feed);
@@ -117,9 +118,11 @@ describe('EdgeFeedReplicator', () => {
117
118
  await expect.poll(() => sendSpy.mock.calls.length).toEqual(2);
118
119
  sendSpy.mockRestore();
119
120
  expect(messageSink.length).toEqual(0);
121
+
122
+ reconnectTrigger.reset();
120
123
  await updateIdentity(messenger);
124
+ await reconnectTrigger.wait();
121
125
 
122
- await messenger.reconnect.waitForCount(1);
123
126
  await expect.poll(() => messageSink.find((msg) => msg.type === 'data')).toBeDefined();
124
127
  });
125
128
 
@@ -151,8 +154,8 @@ describe('EdgeFeedReplicator', () => {
151
154
  await sleep(100);
152
155
  admitConnection.wake();
153
156
 
154
- await expect.poll(() => messageSink.length).toEqual(2);
155
- expect(messageSink.map((m) => m.type)).toStrictEqual(range(2, () => 'get-metadata'));
157
+ await expect.poll(() => messageSink.length).toEqual(1);
158
+ expect(messageSink.map((m) => m.type)).toStrictEqual(range(1, () => 'get-metadata'));
156
159
  });
157
160
 
158
161
  test('block appended during reconnect', async () => {
@@ -213,10 +216,12 @@ describe('EdgeFeedReplicator', () => {
213
216
  };
214
217
 
215
218
  const createClient = async (endpoint: string) => {
219
+ const reconnectTrigger = new Trigger();
216
220
  const messenger = new EdgeClient(await createEphemeralEdgeIdentity(), { socketEndpoint: endpoint });
221
+ messenger.onReconnected(() => reconnectTrigger.wake());
217
222
  const sendSpy = vi.spyOn(messenger, 'send');
218
223
  await openAndClose(messenger);
219
- return { messenger, sendSpy };
224
+ return { messenger, sendSpy, reconnectTrigger };
220
225
  };
221
226
 
222
227
  const attachReplicator = async (messenger: EdgeClient, options?: { skipOpen?: boolean }) => {
@@ -56,7 +56,7 @@ export class EdgeFeedReplicator extends Resource {
56
56
  log('open');
57
57
  // TODO: handle reconnects
58
58
  this._ctx.onDispose(
59
- this._messenger.addListener((message: RouterMessage) => {
59
+ this._messenger.onMessage((message: RouterMessage) => {
60
60
  if (!message.serviceId) {
61
61
  return;
62
62
  }
@@ -77,11 +77,15 @@ export class EdgeFeedReplicator extends Resource {
77
77
  }),
78
78
  );
79
79
 
80
- this._messenger.connected.on(this._ctx, async () => {
81
- await this._resetConnection();
82
- this._startReplication();
83
- });
80
+ this._ctx.onDispose(
81
+ this._messenger.onReconnected(() => {
82
+ scheduleMicroTask(this._ctx, () => this._handleReconnect());
83
+ }),
84
+ );
85
+ }
84
86
 
87
+ private async _handleReconnect() {
88
+ await this._resetConnection();
85
89
  if (this._messenger.isConnected) {
86
90
  this._startReplication();
87
91
  }
@@ -62,6 +62,7 @@ export const performInvitation = ({
62
62
  }: PerformInvitationParams): [Promise<Result>, Promise<Result>] => {
63
63
  let guestError = false;
64
64
  let guestConnected = false;
65
+ let wereConnected = false;
65
66
  const hostComplete = new Trigger<Result>();
66
67
  const guestComplete = new Trigger<Result>();
67
68
  const authCode = new Trigger<string>();
@@ -72,12 +73,17 @@ export const performInvitation = ({
72
73
  switch (hostInvitation.state) {
73
74
  case Invitation.State.CONNECTING: {
74
75
  if (guestConnected) {
76
+ if (wereConnected) {
77
+ hostComplete.wake({ invitation: hostInvitation });
78
+ }
75
79
  break;
76
80
  }
81
+
77
82
  guestConnected = true;
78
83
  if (hooks?.host?.onConnecting?.(hostObservable)) {
79
84
  break;
80
85
  }
86
+
81
87
  const guestObservable = acceptInvitation(guest, hostInvitation, guestDeviceProfile);
82
88
  guestObservable.subscribe(
83
89
  async (guestInvitation: Invitation) => {
@@ -153,6 +159,7 @@ export const performInvitation = ({
153
159
  }
154
160
 
155
161
  case Invitation.State.CONNECTED: {
162
+ wereConnected = true;
156
163
  hooks?.host?.onConnected?.(hostObservable);
157
164
  break;
158
165
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const DXOS_VERSION = "0.6.14-main.8b352a0";
1
+ export const DXOS_VERSION = "0.6.14-staging.3e2eaca";