@dxos/client-services 0.1.26 → 0.1.27-next.a0dff21

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 (155) hide show
  1. package/dist/lib/browser/{chunk-R2FEBB66.mjs → chunk-OTSGRZZI.mjs} +796 -579
  2. package/dist/lib/browser/chunk-OTSGRZZI.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +19 -15
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/packlets/testing/index.mjs +46 -46
  6. package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
  7. package/dist/lib/node/index.cjs +864 -641
  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 +753 -631
  11. package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
  12. package/dist/types/src/index.d.ts +0 -1
  13. package/dist/types/src/index.d.ts.map +1 -1
  14. package/dist/types/src/packlets/deprecated/index.d.ts +0 -3
  15. package/dist/types/src/packlets/deprecated/index.d.ts.map +1 -1
  16. package/dist/types/src/packlets/{identity/devices-service-impl.d.ts → devices/devices-service.d.ts} +4 -3
  17. package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -0
  18. package/dist/types/src/packlets/devices/index.d.ts +2 -0
  19. package/dist/types/src/packlets/devices/index.d.ts.map +1 -0
  20. package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
  21. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  22. package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -2
  23. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  24. package/dist/types/src/packlets/identity/identity-service.d.ts +14 -0
  25. package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -0
  26. package/dist/types/src/packlets/identity/identity.d.ts +2 -2
  27. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  28. package/dist/types/src/packlets/identity/index.d.ts +1 -0
  29. package/dist/types/src/packlets/identity/index.d.ts.map +1 -1
  30. package/dist/types/src/packlets/invitations/{halo-invitations-handler.d.ts → device-invitations-handler.d.ts} +5 -5
  31. package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -0
  32. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts +2 -0
  33. package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts.map +1 -0
  34. package/dist/types/src/packlets/invitations/{halo-invitations-proxy.d.ts → device-invitations-proxy.d.ts} +2 -2
  35. package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +1 -0
  36. package/dist/types/src/packlets/invitations/{halo-invitations-service.d.ts → device-invitations-service.d.ts} +2 -2
  37. package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -0
  38. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts +2 -0
  39. package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts.map +1 -0
  40. package/dist/types/src/packlets/invitations/index.d.ts +3 -3
  41. package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
  42. package/dist/types/src/packlets/invitations/invitations-handler.d.ts +6 -0
  43. package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
  44. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +1 -1
  45. package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
  46. package/dist/types/src/packlets/services/index.d.ts +0 -1
  47. package/dist/types/src/packlets/services/index.d.ts.map +1 -1
  48. package/dist/types/src/packlets/services/service-context.d.ts +3 -3
  49. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  50. package/dist/types/src/packlets/services/service-definitions.d.ts +5 -7
  51. package/dist/types/src/packlets/services/service-definitions.d.ts.map +1 -1
  52. package/dist/types/src/packlets/services/service-host.d.ts +1 -0
  53. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  54. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +1 -1
  55. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  56. package/dist/types/src/packlets/spaces/data-space.d.ts +1 -1
  57. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  58. package/dist/types/src/packlets/spaces/spaces-service.d.ts +12 -5
  59. package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
  60. package/dist/types/src/packlets/system/index.d.ts +2 -0
  61. package/dist/types/src/packlets/system/index.d.ts.map +1 -0
  62. package/dist/types/src/packlets/system/system-service.d.ts +28 -0
  63. package/dist/types/src/packlets/system/system-service.d.ts.map +1 -0
  64. package/dist/types/src/packlets/system/system-service.test.d.ts +2 -0
  65. package/dist/types/src/packlets/system/system-service.test.d.ts.map +1 -0
  66. package/dist/types/src/packlets/testing/index.d.ts +1 -1
  67. package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
  68. package/dist/types/src/packlets/testing/test-builder.d.ts +1 -1
  69. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  70. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +11 -4
  71. package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
  72. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +6 -1
  73. package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
  74. package/dist/types/src/packlets/vault/index.d.ts +2 -0
  75. package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
  76. package/dist/types/src/packlets/vault/services.d.ts +9 -1
  77. package/dist/types/src/packlets/vault/services.d.ts.map +1 -1
  78. package/dist/types/src/packlets/vault/shell-controller.d.ts +18 -0
  79. package/dist/types/src/packlets/vault/shell-controller.d.ts.map +1 -0
  80. package/dist/types/src/packlets/vault/shell-runtime.d.ts +45 -0
  81. package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -0
  82. package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -1
  83. package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
  84. package/dist/types/src/packlets/vault/worker-session.d.ts +4 -1
  85. package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
  86. package/package.json +29 -28
  87. package/src/index.ts +0 -1
  88. package/src/packlets/deprecated/index.ts +0 -3
  89. package/src/packlets/{identity/devices-service-impl.ts → devices/devices-service.ts} +10 -8
  90. package/src/packlets/devices/index.ts +5 -0
  91. package/src/packlets/devtools/spaces.ts +1 -1
  92. package/src/packlets/identity/authenticator.ts +1 -1
  93. package/src/packlets/identity/identity-manager.test.ts +1 -1
  94. package/src/packlets/identity/identity-manager.ts +2 -2
  95. package/src/packlets/identity/identity-service.ts +67 -0
  96. package/src/packlets/identity/identity.test.ts +1 -1
  97. package/src/packlets/identity/identity.ts +1 -1
  98. package/src/packlets/identity/index.ts +1 -0
  99. package/src/packlets/invitations/{halo-invitations-handler.test.ts → device-invitations-handler.test.ts} +2 -2
  100. package/src/packlets/invitations/{halo-invitations-handler.ts → device-invitations-handler.ts} +4 -4
  101. package/src/packlets/invitations/{halo-invitations-proxy.ts → device-invitations-proxy.ts} +1 -1
  102. package/src/packlets/invitations/{halo-invitations-service.test.ts → device-invitations-service.test.ts} +10 -10
  103. package/src/packlets/invitations/{halo-invitations-service.ts → device-invitations-service.ts} +1 -1
  104. package/src/packlets/invitations/index.ts +3 -3
  105. package/src/packlets/invitations/invitations-handler.ts +6 -0
  106. package/src/packlets/invitations/invitations-service.ts +2 -2
  107. package/src/packlets/invitations/space-invitations-handler.test.ts +1 -1
  108. package/src/packlets/invitations/space-invitations-handler.ts +55 -20
  109. package/src/packlets/services/index.ts +0 -1
  110. package/src/packlets/services/service-context.test.ts +3 -3
  111. package/src/packlets/services/service-context.ts +5 -5
  112. package/src/packlets/services/service-definitions.ts +14 -14
  113. package/src/packlets/services/service-host.test.ts +9 -9
  114. package/src/packlets/services/service-host.ts +40 -25
  115. package/src/packlets/spaces/data-space-manager.test.ts +1 -1
  116. package/src/packlets/spaces/data-space-manager.ts +4 -4
  117. package/src/packlets/spaces/data-space.ts +3 -3
  118. package/src/packlets/spaces/spaces-service.ts +93 -11
  119. package/src/packlets/system/index.ts +5 -0
  120. package/src/packlets/system/system-service.test.ts +80 -0
  121. package/src/packlets/system/system-service.ts +70 -0
  122. package/src/packlets/testing/index.ts +1 -1
  123. package/src/packlets/testing/test-builder.ts +3 -3
  124. package/src/packlets/vault/iframe-host-runtime.ts +28 -10
  125. package/src/packlets/vault/iframe-proxy-runtime.ts +16 -1
  126. package/src/packlets/vault/index.ts +2 -0
  127. package/src/packlets/vault/services.ts +17 -1
  128. package/src/packlets/vault/shell-controller.ts +56 -0
  129. package/src/packlets/vault/shell-runtime.ts +121 -0
  130. package/src/packlets/vault/worker-runtime.ts +3 -1
  131. package/src/packlets/vault/worker-session.ts +28 -19
  132. package/dist/lib/browser/chunk-R2FEBB66.mjs.map +0 -7
  133. package/dist/types/src/packlets/deprecated/invitations.d.ts +0 -47
  134. package/dist/types/src/packlets/deprecated/invitations.d.ts.map +0 -1
  135. package/dist/types/src/packlets/deprecated/profile.d.ts +0 -18
  136. package/dist/types/src/packlets/deprecated/profile.d.ts.map +0 -1
  137. package/dist/types/src/packlets/deprecated/space.d.ts +0 -23
  138. package/dist/types/src/packlets/deprecated/space.d.ts.map +0 -1
  139. package/dist/types/src/packlets/deprecated/system.d.ts +0 -24
  140. package/dist/types/src/packlets/deprecated/system.d.ts.map +0 -1
  141. package/dist/types/src/packlets/identity/devices-service-impl.d.ts.map +0 -1
  142. package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +0 -1
  143. package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts +0 -2
  144. package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts.map +0 -1
  145. package/dist/types/src/packlets/invitations/halo-invitations-proxy.d.ts.map +0 -1
  146. package/dist/types/src/packlets/invitations/halo-invitations-service.d.ts.map +0 -1
  147. package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts +0 -2
  148. package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts.map +0 -1
  149. package/dist/types/src/packlets/services/signer.d.ts +0 -6
  150. package/dist/types/src/packlets/services/signer.d.ts.map +0 -1
  151. package/src/packlets/deprecated/invitations.ts +0 -63
  152. package/src/packlets/deprecated/profile.ts +0 -85
  153. package/src/packlets/deprecated/space.ts +0 -258
  154. package/src/packlets/deprecated/system.ts +0 -48
  155. package/src/packlets/services/signer.ts +0 -11
@@ -8,20 +8,20 @@ import waitForExpect from 'wait-for-expect';
8
8
 
9
9
  import { asyncChain, Trigger } from '@dxos/async';
10
10
  import { raise } from '@dxos/debug';
11
- import { Invitation, HaloInvitationsService } from '@dxos/protocols/proto/dxos/client/services';
11
+ import { Invitation, DeviceInvitationsService } from '@dxos/protocols/proto/dxos/client/services';
12
12
  import { describe, test, afterTest } from '@dxos/test';
13
13
 
14
14
  import { ServiceContext } from '../services';
15
15
  import { createPeers } from '../testing';
16
- import { HaloInvitationsProxy } from './halo-invitations-proxy';
17
- import { HaloInvitationsServiceImpl } from './halo-invitations-service';
16
+ import { DeviceInvitationsProxy } from './device-invitations-proxy';
17
+ import { DeviceInvitationsServiceImpl } from './device-invitations-service';
18
18
 
19
19
  const closeAfterTest = async (peer: ServiceContext) => {
20
20
  afterTest(() => peer.close());
21
21
  return peer;
22
22
  };
23
23
 
24
- describe('services/halo-invitation-service', () => {
24
+ describe('services/device-invitation-service', () => {
25
25
  test('creates identity and invites peer', async () => {
26
26
  const [host, guest] = await asyncChain<ServiceContext>([closeAfterTest])(createPeers(2));
27
27
 
@@ -29,14 +29,14 @@ describe('services/halo-invitation-service', () => {
29
29
  expect(host.identityManager.identity!.authorizedDeviceKeys.size).to.eq(1);
30
30
 
31
31
  // prettier-ignore
32
- const service1: HaloInvitationsService = new HaloInvitationsServiceImpl(
32
+ const service1: DeviceInvitationsService = new DeviceInvitationsServiceImpl(
33
33
  host.identityManager,
34
- host.haloInvitations
34
+ host.deviceInvitations
35
35
  );
36
36
  // prettier-ignore
37
- const service2: HaloInvitationsService = new HaloInvitationsServiceImpl(
37
+ const service2: DeviceInvitationsService = new DeviceInvitationsServiceImpl(
38
38
  guest.identityManager,
39
- guest.haloInvitations
39
+ guest.deviceInvitations
40
40
  );
41
41
 
42
42
  const success1 = new Trigger<Invitation>();
@@ -45,11 +45,11 @@ describe('services/halo-invitation-service', () => {
45
45
  const authenticationCode = new Trigger<string>();
46
46
 
47
47
  {
48
- const proxy1 = new HaloInvitationsProxy(service1);
48
+ const proxy1 = new DeviceInvitationsProxy(service1);
49
49
  const observable1 = proxy1.createInvitation();
50
50
  observable1.subscribe({
51
51
  onConnecting: (invitation: Invitation) => {
52
- const proxy2 = new HaloInvitationsProxy(service2);
52
+ const proxy2 = new DeviceInvitationsProxy(service2);
53
53
  const observable2 = proxy2.acceptInvitation(invitation);
54
54
  observable2.subscribe({
55
55
  onAuthenticating: async () => {
@@ -11,7 +11,7 @@ import { AbstractInvitationsService } from './invitations-service';
11
11
  /**
12
12
  * Adapts invitation service observable to client/service stream.
13
13
  */
14
- export class HaloInvitationsServiceImpl extends AbstractInvitationsService {
14
+ export class DeviceInvitationsServiceImpl extends AbstractInvitationsService {
15
15
  // prettier-ignore
16
16
  constructor (
17
17
  identityManager: IdentityManager,
@@ -3,9 +3,9 @@
3
3
  //
4
4
 
5
5
  export * from './encoder';
6
- export * from './halo-invitations-handler';
7
- export * from './halo-invitations-proxy';
8
- export * from './halo-invitations-service';
6
+ export * from './device-invitations-handler';
7
+ export * from './device-invitations-proxy';
8
+ export * from './device-invitations-service';
9
9
  export * from './invitations';
10
10
  export * from './invitations-handler';
11
11
  export * from './invitations-proxy';
@@ -5,6 +5,7 @@
5
5
  import { PublicKey } from '@dxos/keys';
6
6
  import { NetworkManager } from '@dxos/network-manager';
7
7
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
8
+ import { AuthMethod } from '@dxos/protocols/proto/dxos/halo/invitations';
8
9
 
9
10
  import { AuthenticatingInvitationObservable, CancellableInvitationObservable } from './invitations';
10
11
 
@@ -13,6 +14,11 @@ export type InvitationsOptions = {
13
14
  timeout?: number;
14
15
  // Used for debugging.
15
16
  swarmKey?: PublicKey;
17
+ /**
18
+ * Authentication method.
19
+ * @default AuthMethod.SHARED_SECRET
20
+ */
21
+ authMethod?: AuthMethod;
16
22
  };
17
23
 
18
24
  /**
@@ -43,8 +43,8 @@ export abstract class AbstractInvitationsService<T = void> implements Invitation
43
43
  log('stream opened', this.getLoggingContext());
44
44
 
45
45
  let invitationId: string;
46
- const { type, swarmKey } = invitation;
47
- const observable = invitationsHandler.createInvitation(context, { type, swarmKey });
46
+ const { type, swarmKey, authMethod } = invitation;
47
+ const observable = invitationsHandler.createInvitation(context, { type, swarmKey, authMethod });
48
48
  observable.subscribe({
49
49
  onConnecting: (invitation) => {
50
50
  assert(invitation.invitationId);
@@ -7,7 +7,7 @@ import assert from 'node:assert';
7
7
 
8
8
  import { asyncChain, latch, Trigger } from '@dxos/async';
9
9
  import { raise } from '@dxos/debug';
10
- import { testLocalDatabase } from '@dxos/echo-db/testing';
10
+ import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
11
11
  import { PublicKey } from '@dxos/keys';
12
12
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
13
13
  import { afterTest, describe, test } from '@dxos/test';
@@ -7,7 +7,7 @@ import assert from 'node:assert';
7
7
  import { scheduleTask, sleep, Trigger } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { createAdmissionCredentials, generatePasscode, getCredentialAssertion } from '@dxos/credentials';
10
- import { SigningContext } from '@dxos/echo-db';
10
+ import { SigningContext } from '@dxos/echo-pipeline';
11
11
  import { writeMessages } from '@dxos/feed-store';
12
12
  import { Keyring } from '@dxos/keyring';
13
13
  import { PublicKey } from '@dxos/keys';
@@ -20,7 +20,9 @@ import { ProfileDocument } from '@dxos/protocols/proto/dxos/halo/credentials';
20
20
  import {
21
21
  AuthenticationRequest,
22
22
  AuthenticationResponse,
23
+ AuthMethod,
23
24
  Introduction,
25
+ IntroductionResponse,
24
26
  SpaceAdmissionCredentials,
25
27
  SpaceAdmissionRequest,
26
28
  SpaceHostService
@@ -70,7 +72,8 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
70
72
  invitationId: PublicKey.random().toHex(),
71
73
  swarmKey: swarmKey ?? PublicKey.random(),
72
74
  spaceKey: space.key,
73
- authenticationCode: generatePasscode(AUTHENTICATION_CODE_LENGTH)
75
+ authMethod: options?.authMethod ?? AuthMethod.SHARED_SECRET,
76
+ authenticationCode: generatePasscode(AUTHENTICATION_CODE_LENGTH) // TODO(dmaretskyi): Don't generate if authMethod === NONE .
74
77
  };
75
78
 
76
79
  const ctx = new Context({
@@ -85,7 +88,7 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
85
88
  await swarmConnection?.close();
86
89
  });
87
90
 
88
- let authenticationCode: string;
91
+ let authenticationPassed = false;
89
92
  let authenticationRetry = 0;
90
93
 
91
94
  // Called for every connecting peer.
@@ -106,18 +109,41 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
106
109
  // TODO(burdon): Is this the right place to set this state?
107
110
  // TODO(dmaretskyi): Should we expose guest's profile in this callback?
108
111
  observable.callback.onAuthenticating?.(invitation);
112
+
113
+ return {
114
+ spaceKey:
115
+ type === Invitation.Type.INTERACTIVE_TESTING || type === Invitation.Type.MULTIUSE_TESTING
116
+ ? space.key
117
+ : undefined,
118
+ authMethod: invitation.authMethod!
119
+ };
109
120
  },
110
121
 
111
122
  authenticate: async ({ authenticationCode: code }) => {
112
123
  log('received authentication request', { authenticationCode: code });
113
124
  let status = AuthenticationResponse.Status.OK;
114
- if (invitation.authenticationCode) {
115
- if (authenticationRetry++ > MAX_OTP_ATTEMPTS) {
116
- status = AuthenticationResponse.Status.INVALID_OPT_ATTEMPTS;
117
- } else if (code !== invitation.authenticationCode) {
118
- status = AuthenticationResponse.Status.INVALID_OTP;
119
- } else {
120
- authenticationCode = code;
125
+
126
+ switch (invitation.authMethod) {
127
+ case AuthMethod.NONE: {
128
+ log('authentication not required');
129
+ return { status: AuthenticationResponse.Status.OK };
130
+ }
131
+ case AuthMethod.SHARED_SECRET: {
132
+ if (invitation.authenticationCode) {
133
+ if (authenticationRetry++ > MAX_OTP_ATTEMPTS) {
134
+ status = AuthenticationResponse.Status.INVALID_OPT_ATTEMPTS;
135
+ } else if (code !== invitation.authenticationCode) {
136
+ status = AuthenticationResponse.Status.INVALID_OTP;
137
+ } else {
138
+ authenticationPassed = true;
139
+ }
140
+ }
141
+ break;
142
+ }
143
+ default: {
144
+ log.error('invalid authentication method', { authMethod: invitation.authMethod });
145
+ status = AuthenticationResponse.Status.INTERNAL_ERROR;
146
+ break;
121
147
  }
122
148
  }
123
149
 
@@ -127,13 +153,8 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
127
153
  requestAdmission: async ({ identityKey, deviceKey, controlFeedKey, dataFeedKey }) => {
128
154
  try {
129
155
  // Check authenticated.
130
- if (
131
- invitation.type !== Invitation.Type.INTERACTIVE_TESTING &&
132
- invitation.type !== Invitation.Type.MULTIUSE_TESTING
133
- ) {
134
- if (invitation.authenticationCode === undefined || invitation.authenticationCode !== authenticationCode) {
135
- throw new Error(`invalid authentication code: ${authenticationCode}`);
136
- }
156
+ if (isAuthenticationRequired(invitation) && !authenticationPassed) {
157
+ throw new Error('Not authenticated');
137
158
  }
138
159
 
139
160
  log('writing guest credentials', { host: this._signingContext.deviceKey, guest: deviceKey });
@@ -252,13 +273,22 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
252
273
 
253
274
  // 1. Introduce guest to host.
254
275
  log('introduce', { guest: this._signingContext.deviceKey });
255
- await extension.rpc.SpaceHostService.introduce({
276
+ const introductionResponse = await extension.rpc.SpaceHostService.introduce({
256
277
  profile: this._signingContext.profile
257
278
  });
279
+ log('introduce response', { guest: this._signingContext.deviceKey, response: introductionResponse });
280
+ invitation.authMethod = introductionResponse.authMethod;
281
+ if (introductionResponse.spaceKey) {
282
+ invitation.spaceKey = introductionResponse.spaceKey;
283
+ }
284
+
285
+ // TODO(dmaretskyi): Add a callback here to notify that we have introduced ourselves to the host (regradless of auth requirements).
258
286
 
259
287
  // 2. Get authentication code.
260
288
  // TODO(burdon): Test timeout (options for timeouts at different steps).
261
- if (invitation.type === undefined || invitation.type === Invitation.Type.INTERACTIVE) {
289
+ if (isAuthenticationRequired(invitation)) {
290
+ observable.callback.onAuthenticating?.(invitation);
291
+
262
292
  for (let attempt = 1; attempt <= MAX_OTP_ATTEMPTS; attempt++) {
263
293
  log('guest waiting for authentication code...');
264
294
  observable.callback.onAuthenticating?.(invitation);
@@ -346,11 +376,16 @@ export class SpaceInvitationsHandler extends AbstractInvitationsHandler<DataSpac
346
376
  }
347
377
  }
348
378
 
379
+ const isAuthenticationRequired = (invitation: Invitation) =>
380
+ invitation.authMethod !== AuthMethod.NONE &&
381
+ invitation.type !== Invitation.Type.INTERACTIVE_TESTING &&
382
+ invitation.type !== Invitation.Type.MULTIUSE_TESTING;
383
+
349
384
  type HostSpaceInvitationExtensionCallbacks = {
350
385
  // Deliberately not async to not block the extensions opening.
351
386
  onOpen: () => void;
352
387
 
353
- introduce: (introduction: Introduction) => Promise<void>;
388
+ introduce: (introduction: Introduction) => Promise<IntroductionResponse>;
354
389
  authenticate: (request: AuthenticationRequest) => Promise<AuthenticationResponse>;
355
390
  requestAdmission: (request: SpaceAdmissionRequest) => Promise<SpaceAdmissionCredentials>;
356
391
  };
@@ -7,4 +7,3 @@ export * from './service-definitions';
7
7
  export * from './service-host';
8
8
  export * from './service-proxy';
9
9
  export * from './service-registry';
10
- export * from './signer';
@@ -16,7 +16,7 @@ describe('services/ServiceContext', () => {
16
16
  const space1 = await device1.dataSpaceManager!.createSpace();
17
17
 
18
18
  const device2 = createServiceContext({ signalContext: networkContext });
19
- await performInvitation(device1.haloInvitations, device2.haloInvitations, undefined);
19
+ await performInvitation(device1.deviceInvitations, device2.deviceInvitations, undefined);
20
20
 
21
21
  const space2 = await device2.dataSpaceManager!.spaces.get(space1.key);
22
22
  await syncItems(space1.dataPipelineController, space2!.dataPipelineController);
@@ -28,7 +28,7 @@ describe('services/ServiceContext', () => {
28
28
  await device1.createIdentity();
29
29
 
30
30
  const device2 = createServiceContext({ signalContext: networkContext });
31
- await performInvitation(device1.haloInvitations, device2.haloInvitations, undefined);
31
+ await performInvitation(device1.deviceInvitations, device2.deviceInvitations, undefined);
32
32
 
33
33
  const space1 = await device1.dataSpaceManager!.createSpace();
34
34
  await device2.dataSpaceManager?.updated.waitForCondition(() => !!device2.dataSpaceManager!.spaces.get(space1.key));
@@ -42,7 +42,7 @@ describe('services/ServiceContext', () => {
42
42
  await device1.createIdentity();
43
43
 
44
44
  const device2 = createServiceContext({ signalContext: networkContext });
45
- await performInvitation(device1.haloInvitations, device2.haloInvitations, undefined);
45
+ await performInvitation(device1.deviceInvitations, device2.deviceInvitations, undefined);
46
46
 
47
47
  const identity2 = createServiceContext({ signalContext: networkContext });
48
48
  await identity2.createIdentity();
@@ -7,12 +7,12 @@ import { CredentialConsumer, getCredentialAssertion } from '@dxos/credentials';
7
7
  import { failUndefined } from '@dxos/debug';
8
8
  import {
9
9
  valueEncoding,
10
- DataServiceSubscriptions,
11
10
  MetadataStore,
12
11
  SpaceManager,
13
12
  SigningContext,
13
+ DataServiceSubscriptions,
14
14
  SnapshotStore
15
- } from '@dxos/echo-db';
15
+ } from '@dxos/echo-pipeline';
16
16
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
17
17
  import { Keyring } from '@dxos/keyring';
18
18
  import { log } from '@dxos/log';
@@ -23,7 +23,7 @@ import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
23
23
  import { Storage } from '@dxos/random-access-storage';
24
24
 
25
25
  import { CreateIdentityOptions, IdentityManager, JoinIdentityParams } from '../identity';
26
- import { HaloInvitationsHandler, SpaceInvitationsHandler } from '../invitations';
26
+ import { DeviceInvitationsHandler, SpaceInvitationsHandler } from '../invitations';
27
27
  import { DataSpaceManager } from '../spaces/data-space-manager';
28
28
 
29
29
  /**
@@ -39,7 +39,7 @@ export class ServiceContext {
39
39
  public readonly keyring: Keyring;
40
40
  public readonly spaceManager: SpaceManager;
41
41
  public readonly identityManager: IdentityManager;
42
- public readonly haloInvitations: HaloInvitationsHandler;
42
+ public readonly deviceInvitations: DeviceInvitationsHandler;
43
43
 
44
44
  private _deviceSpaceSync?: CredentialConsumer<any>;
45
45
 
@@ -82,7 +82,7 @@ export class ServiceContext {
82
82
 
83
83
  // TODO(burdon): _initialize called in multiple places.
84
84
  // TODO(burdon): Call _initialize on success.
85
- this.haloInvitations = new HaloInvitationsHandler({
85
+ this.deviceInvitations = new DeviceInvitationsHandler({
86
86
  networkManager: this.networkManager,
87
87
  getIdentity: () => this.identityManager.identity ?? failUndefined(),
88
88
  acceptIdentity: this._acceptIdentity.bind(this),
@@ -3,13 +3,14 @@
3
3
  //
4
4
 
5
5
  import { schema } from '@dxos/protocols';
6
- import { ProfileService, SystemService, SpaceService } from '@dxos/protocols/proto/dxos/client';
7
6
  import {
8
- HaloInvitationsService,
7
+ DevicesService,
8
+ DeviceInvitationsService,
9
+ IdentityService,
10
+ NetworkService,
9
11
  SpaceInvitationsService,
10
12
  SpacesService,
11
- DevicesService,
12
- NetworkService
13
+ SystemService
13
14
  } from '@dxos/protocols/proto/dxos/client/services';
14
15
  import { DevtoolsHost, TracingService } from '@dxos/protocols/proto/dxos/devtools/host';
15
16
  import { DataService } from '@dxos/protocols/proto/dxos/echo/service';
@@ -20,19 +21,19 @@ import { createServiceBundle, ServiceBundle } from '@dxos/rpc';
20
21
  //
21
22
 
22
23
  export type ClientServices = {
23
- HaloInvitationsService: HaloInvitationsService;
24
+ SystemService: SystemService;
25
+
26
+ IdentityService: IdentityService;
27
+ DeviceInvitationsService: DeviceInvitationsService;
24
28
  DevicesService: DevicesService;
25
29
 
26
30
  SpaceInvitationsService: SpaceInvitationsService;
27
31
  SpacesService: SpacesService;
32
+ DataService: DataService;
28
33
 
29
34
  NetworkService: NetworkService;
30
35
 
31
36
  // TODO(burdon): Deprecated.
32
- SpaceService: SpaceService;
33
- DataService: DataService;
34
- ProfileService: ProfileService;
35
- SystemService: SystemService;
36
37
  DevtoolsHost: DevtoolsHost;
37
38
  TracingService: TracingService;
38
39
  };
@@ -52,17 +53,16 @@ export interface ClientServicesProvider {
52
53
  * Services supported by host.
53
54
  */
54
55
  export const clientServiceBundle = createServiceBundle<ClientServices>({
55
- HaloInvitationsService: schema.getService('dxos.client.services.HaloInvitationsService'),
56
+ SystemService: schema.getService('dxos.client.services.SystemService'),
57
+ IdentityService: schema.getService('dxos.client.services.IdentityService'),
58
+ DeviceInvitationsService: schema.getService('dxos.client.services.DeviceInvitationsService'),
56
59
  DevicesService: schema.getService('dxos.client.services.DevicesService'),
57
60
  SpaceInvitationsService: schema.getService('dxos.client.services.SpaceInvitationsService'),
58
61
  SpacesService: schema.getService('dxos.client.services.SpacesService'),
62
+ DataService: schema.getService('dxos.echo.service.DataService'),
59
63
  NetworkService: schema.getService('dxos.client.services.NetworkService'),
60
64
 
61
65
  // TODO(burdon): Deprecated.
62
- SpaceService: schema.getService('dxos.client.SpaceService'),
63
- DataService: schema.getService('dxos.echo.service.DataService'),
64
- ProfileService: schema.getService('dxos.client.ProfileService'),
65
- SystemService: schema.getService('dxos.client.SystemService'),
66
66
  DevtoolsHost: schema.getService('dxos.devtools.host.DevtoolsHost'),
67
67
  TracingService: schema.getService('dxos.devtools.host.TracingService')
68
68
  });
@@ -20,8 +20,8 @@ describe('ClientServicesHost', () => {
20
20
  await host.open();
21
21
  afterTest(() => host.close());
22
22
 
23
- await host.services.ProfileService!.createProfile({});
24
- const { publicKey: spaceKey } = await host.services.SpaceService!.createSpace();
23
+ await host.services.IdentityService!.createIdentity({});
24
+ const { spaceKey } = await host.services.SpacesService!.createSpace();
25
25
 
26
26
  const stream = host.services.SpacesService!.queryCredentials({ spaceKey });
27
27
  const [done, tick] = latch({ count: 3 });
@@ -39,18 +39,18 @@ describe('ClientServicesHost', () => {
39
39
  await host.open();
40
40
  afterTest(() => host.close());
41
41
 
42
- await host.services.ProfileService!.createProfile({});
42
+ await host.services.IdentityService!.createIdentity({});
43
43
 
44
44
  const testCredential = await createMockCredential({
45
45
  signer: host._serviceContext.keyring,
46
46
  issuer: host._serviceContext.identityManager.identity!.deviceKey
47
47
  });
48
48
 
49
- // Test if Profile exposes haloSpace key.
49
+ // Test if Identity exposes haloSpace key.
50
50
  const haloSpace = new Trigger<PublicKey>();
51
- host.services.ProfileService!.subscribeProfile()!.subscribe(({ profile }) => {
52
- if (profile?.haloSpace) {
53
- haloSpace.wake(profile.haloSpace);
51
+ host.services.IdentityService!.queryIdentity()!.subscribe(({ identity }) => {
52
+ if (identity?.spaceKey) {
53
+ haloSpace.wake(identity.spaceKey);
54
54
  }
55
55
  });
56
56
 
@@ -76,7 +76,7 @@ describe('ClientServicesHost', () => {
76
76
  await host.open();
77
77
  afterTest(() => host.close());
78
78
 
79
- await host.services.ProfileService!.createProfile({});
79
+ await host.services.IdentityService!.createIdentity({});
80
80
 
81
81
  const testCredential = await createMockCredential({
82
82
  signer: host._serviceContext.keyring,
@@ -85,7 +85,7 @@ describe('ClientServicesHost', () => {
85
85
 
86
86
  const nonce = new Uint8Array([0, 0, 0, 0]);
87
87
 
88
- const presentation = await host.services.ProfileService!.signPresentation({
88
+ const presentation = await host.services.IdentityService!.signPresentation({
89
89
  presentation: {
90
90
  credentials: [testCredential]
91
91
  },
@@ -2,24 +2,29 @@
2
2
  // Copyright 2021 DXOS.org
3
3
  //
4
4
 
5
+ import assert from 'node:assert';
6
+
7
+ import { Event } from '@dxos/async';
5
8
  import { Config } from '@dxos/config';
6
9
  import { raise } from '@dxos/debug';
7
10
  import { DocumentModel } from '@dxos/document-model';
8
- import { DataServiceImpl } from '@dxos/echo-db';
11
+ import { DataServiceImpl } from '@dxos/echo-pipeline';
9
12
  import { log } from '@dxos/log';
10
13
  import { ModelFactory } from '@dxos/model-factory';
11
14
  import { NetworkManager } from '@dxos/network-manager';
12
- import { Status } from '@dxos/protocols/proto/dxos/client';
15
+ import { SystemStatus } from '@dxos/protocols/proto/dxos/client/services';
13
16
  import { Storage } from '@dxos/random-access-storage';
14
17
  import { TextModel } from '@dxos/text-model';
15
18
 
16
- import { SpaceServiceImpl, ProfileServiceImpl, TracingServiceImpl, SystemServiceImpl } from '../deprecated';
19
+ import { TracingServiceImpl } from '../deprecated';
20
+ import { DevicesServiceImpl } from '../devices';
17
21
  import { DevtoolsServiceImpl, DevtoolsHostEvents } from '../devtools';
18
- import { DevicesServiceImpl } from '../identity/devices-service-impl';
19
- import { HaloInvitationsServiceImpl, SpaceInvitationsServiceImpl } from '../invitations';
22
+ import { IdentityServiceImpl } from '../identity';
23
+ import { DeviceInvitationsServiceImpl, SpaceInvitationsServiceImpl } from '../invitations';
20
24
  import { NetworkServiceImpl } from '../network';
21
25
  import { SpacesServiceImpl } from '../spaces';
22
26
  import { createStorageObjects } from '../storage';
27
+ import { SystemServiceImpl } from '../system';
23
28
  import { VaultResourceLock } from '../vault';
24
29
  import { ServiceContext } from './service-context';
25
30
  import { ClientServicesProvider, ClientServices, clientServiceBundle } from './service-definitions';
@@ -48,6 +53,7 @@ export class ClientServicesHost implements ClientServicesProvider {
48
53
  private readonly _systemService: SystemServiceImpl;
49
54
 
50
55
  private readonly _config: Config;
56
+ private readonly _statusUpdate = new Event<void>();
51
57
  private readonly _modelFactory: ModelFactory;
52
58
  private readonly _networkManager: NetworkManager;
53
59
  private readonly _storage: Storage;
@@ -64,6 +70,7 @@ export class ClientServicesHost implements ClientServicesProvider {
64
70
  // TODO(burdon): Create ApolloLink abstraction (see Client).
65
71
  networkManager,
66
72
  storage = createStorageObjects(config.get('runtime.client.storage', {})!).storage,
73
+ // TODO(wittjosiah): Turn this on by default.
67
74
  lockKey
68
75
  }: ClientServicesHostParams) {
69
76
  this._config = config;
@@ -82,20 +89,21 @@ export class ClientServicesHost implements ClientServicesProvider {
82
89
  this._systemService = new SystemServiceImpl({
83
90
  config: this._config,
84
91
 
85
- onInit: async () => {
86
- await this._resourceLock?.acquire();
87
- },
92
+ statusUpdate: this._statusUpdate,
88
93
 
89
- onStatus: async () => {
90
- if (!this.isOpen) {
91
- return { status: Status.INACTIVE };
92
- }
94
+ getCurrentStatus: () => (this.isOpen ? SystemStatus.ACTIVE : SystemStatus.INACTIVE),
93
95
 
94
- return { status: Status.ACTIVE };
96
+ onUpdateStatus: async (status: SystemStatus) => {
97
+ if (!this.isOpen && status === SystemStatus.ACTIVE) {
98
+ await this._resourceLock?.acquire();
99
+ } else if (this.isOpen && status === SystemStatus.INACTIVE) {
100
+ await this._resourceLock?.release();
101
+ }
95
102
  },
96
103
 
97
104
  onReset: async () => {
98
- await this._serviceContext?.reset();
105
+ assert(this._serviceContext, 'service host is closed');
106
+ await this._serviceContext.reset();
99
107
  }
100
108
  });
101
109
 
@@ -123,6 +131,7 @@ export class ClientServicesHost implements ClientServicesProvider {
123
131
  }
124
132
 
125
133
  log('opening...');
134
+ await this._resourceLock?.acquire();
126
135
 
127
136
  // TODO(wittjosiah): Make re-entrant.
128
137
  // TODO(burdon): Break into components.
@@ -130,34 +139,38 @@ export class ClientServicesHost implements ClientServicesProvider {
130
139
 
131
140
  // TODO(burdon): Start to think of DMG (dynamic services).
132
141
  this._serviceRegistry.setServices({
133
- // TODO(burdon): Move to new protobuf definitions.
134
142
  SystemService: this._systemService,
135
143
 
136
- HaloInvitationsService: new HaloInvitationsServiceImpl(
137
- this._serviceContext.identityManager,
138
- this._serviceContext.haloInvitations
139
- ),
144
+ IdentityService: new IdentityServiceImpl(this._serviceContext),
140
145
 
141
146
  DevicesService: new DevicesServiceImpl(this._serviceContext.identityManager),
142
147
 
148
+ DeviceInvitationsService: new DeviceInvitationsServiceImpl(
149
+ this._serviceContext.identityManager,
150
+ this._serviceContext.deviceInvitations
151
+ ),
152
+
143
153
  SpaceInvitationsService: new SpaceInvitationsServiceImpl(
144
154
  this._serviceContext.identityManager,
145
155
  () => this._serviceContext.spaceInvitations ?? raise(new Error('SpaceInvitations not initialized')),
146
156
  () => this._serviceContext.dataSpaceManager ?? raise(new Error('SpaceManager not initialized'))
147
157
  ),
148
158
 
149
- SpacesService: new SpacesServiceImpl(this._serviceContext.spaceManager),
159
+ SpacesService: new SpacesServiceImpl(
160
+ this._serviceContext.identityManager,
161
+ this._serviceContext.spaceManager,
162
+ this._serviceContext.dataServiceSubscriptions,
163
+ async () => {
164
+ await this._serviceContext.initialized.wait();
165
+ return this._serviceContext.dataSpaceManager!;
166
+ }
167
+ ),
150
168
 
151
169
  DataService: new DataServiceImpl(this._serviceContext.dataServiceSubscriptions),
152
170
 
153
171
  NetworkService: new NetworkServiceImpl(this._serviceContext.networkManager),
154
172
 
155
173
  // TODO(burdon): Move to new protobuf definitions.
156
- ProfileService: new ProfileServiceImpl(this._serviceContext),
157
-
158
- // TODO(burdon): Port old SubscribeSpaces to QueryServices>
159
- SpaceService: new SpaceServiceImpl(this._serviceContext),
160
-
161
174
  TracingService: new TracingServiceImpl(this._config),
162
175
  DevtoolsHost: new DevtoolsServiceImpl({
163
176
  events: new DevtoolsHostEvents(),
@@ -168,6 +181,7 @@ export class ClientServicesHost implements ClientServicesProvider {
168
181
 
169
182
  await this._serviceContext.open();
170
183
  this._open = true;
184
+ this._statusUpdate.emit();
171
185
  const deviceKey = this._serviceContext.identityManager.identity?.deviceKey;
172
186
  log('opened', { deviceKey });
173
187
  }
@@ -182,6 +196,7 @@ export class ClientServicesHost implements ClientServicesProvider {
182
196
  this._serviceRegistry.setServices({ SystemService: this._systemService });
183
197
  await this._serviceContext.close();
184
198
  this._open = false;
199
+ this._statusUpdate.emit();
185
200
  log('closed', { deviceKey });
186
201
  }
187
202
  }
@@ -6,7 +6,7 @@ import { expect } from 'chai';
6
6
 
7
7
  import { createAdmissionCredentials } from '@dxos/credentials';
8
8
  import { DocumentModel } from '@dxos/document-model';
9
- import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-db';
9
+ import { AuthStatus, DataServiceSubscriptions } from '@dxos/echo-pipeline';
10
10
  import { writeMessages } from '@dxos/feed-store';
11
11
  import { log } from '@dxos/log';
12
12
  import { ModelFactory } from '@dxos/model-factory';
@@ -8,15 +8,15 @@ import { Event, synchronized, trackLeaks } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { getCredentialAssertion } from '@dxos/credentials';
10
10
  import {
11
- DataServiceSubscriptions,
12
11
  MetadataStore,
13
12
  SigningContext,
14
- SnapshotStore,
15
13
  Space,
16
14
  spaceGenesis,
17
15
  SpaceManager,
18
- SnapshotManager
19
- } from '@dxos/echo-db';
16
+ DataServiceSubscriptions,
17
+ SnapshotManager,
18
+ SnapshotStore
19
+ } from '@dxos/echo-pipeline';
20
20
  import { FeedStore } from '@dxos/feed-store';
21
21
  import { Keyring } from '@dxos/keyring';
22
22
  import { PublicKey } from '@dxos/keys';