@dxos/client-services 0.6.12-staging.e11e696 → 0.6.12

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 (101) hide show
  1. package/dist/lib/browser/{chunk-67FEJJ6J.mjs → chunk-TOAILL4T.mjs} +5127 -5565
  2. package/dist/lib/browser/chunk-TOAILL4T.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +3 -3
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +6 -5
  7. package/dist/lib/browser/testing/index.mjs.map +2 -2
  8. package/dist/lib/node/{chunk-2KIDYJ7O.cjs → chunk-H6C4XY6B.cjs} +4908 -5346
  9. package/dist/lib/node/chunk-H6C4XY6B.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +46 -46
  11. package/dist/lib/node/index.cjs.map +3 -3
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +12 -11
  14. package/dist/lib/node/testing/index.cjs.map +2 -2
  15. package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
  16. package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
  17. package/dist/types/src/packlets/identity/authenticator.test.d.ts +2 -0
  18. package/dist/types/src/packlets/identity/authenticator.test.d.ts.map +1 -0
  19. package/dist/types/src/packlets/identity/contacts-service.d.ts +1 -1
  20. package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
  21. package/dist/types/src/packlets/identity/identity-manager.d.ts +7 -19
  22. package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
  23. package/dist/types/src/packlets/identity/identity.d.ts +1 -8
  24. package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
  25. package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
  26. package/dist/types/src/packlets/services/automerge-host.test.d.ts +2 -0
  27. package/dist/types/src/packlets/services/automerge-host.test.d.ts.map +1 -0
  28. package/dist/types/src/packlets/services/service-context.d.ts +6 -7
  29. package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
  30. package/dist/types/src/packlets/services/service-host.d.ts +0 -1
  31. package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
  32. package/dist/types/src/packlets/spaces/data-space-manager.d.ts +3 -4
  33. package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
  34. package/dist/types/src/packlets/spaces/data-space.d.ts +3 -3
  35. package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
  36. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +0 -3
  37. package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
  38. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts +1 -1
  39. package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
  40. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +6 -31
  41. package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
  42. package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
  43. package/dist/types/src/packlets/testing/test-builder.d.ts +2 -1
  44. package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
  45. package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
  46. package/dist/types/src/version.d.ts +1 -1
  47. package/dist/types/src/version.d.ts.map +1 -1
  48. package/package.json +39 -43
  49. package/src/packlets/devices/devices-service.test.ts +5 -4
  50. package/src/packlets/diagnostics/diagnostics-broadcast.ts +0 -1
  51. package/src/packlets/identity/{authenticator.node.test.ts → authenticator.test.ts} +3 -2
  52. package/src/packlets/identity/authenticator.ts +2 -5
  53. package/src/packlets/identity/contacts-service.ts +1 -1
  54. package/src/packlets/identity/identity-manager.test.ts +6 -5
  55. package/src/packlets/identity/identity-manager.ts +19 -35
  56. package/src/packlets/identity/identity-service.test.ts +8 -4
  57. package/src/packlets/identity/identity.test.ts +239 -128
  58. package/src/packlets/identity/identity.ts +8 -42
  59. package/src/packlets/invitations/device-invitation-protocol.test.ts +4 -7
  60. package/src/packlets/invitations/invitation-host-extension.ts +3 -0
  61. package/src/packlets/invitations/invitations-handler.test.ts +7 -14
  62. package/src/packlets/invitations/invitations-handler.ts +1 -1
  63. package/src/packlets/invitations/space-invitation-protocol.test.ts +3 -4
  64. package/src/packlets/logging/logging.test.ts +2 -1
  65. package/src/packlets/network/network-service.test.ts +3 -2
  66. package/src/packlets/services/automerge-host.test.ts +60 -0
  67. package/src/packlets/services/service-context.test.ts +1 -3
  68. package/src/packlets/services/service-context.ts +28 -64
  69. package/src/packlets/services/service-host.test.ts +12 -8
  70. package/src/packlets/services/service-host.ts +6 -8
  71. package/src/packlets/services/service-registry.test.ts +2 -1
  72. package/src/packlets/spaces/data-space-manager.test.ts +2 -2
  73. package/src/packlets/spaces/data-space-manager.ts +2 -9
  74. package/src/packlets/spaces/data-space.ts +6 -30
  75. package/src/packlets/spaces/edge-feed-replicator.ts +22 -80
  76. package/src/packlets/spaces/epoch-migrations.ts +2 -2
  77. package/src/packlets/spaces/notarization-plugin.test.ts +7 -10
  78. package/src/packlets/spaces/notarization-plugin.ts +29 -169
  79. package/src/packlets/spaces/spaces-service.test.ts +9 -5
  80. package/src/packlets/storage/storage.ts +1 -0
  81. package/src/packlets/system/system-service.test.ts +2 -1
  82. package/src/packlets/testing/test-builder.ts +3 -2
  83. package/src/packlets/worker/worker-runtime.ts +2 -2
  84. package/src/version.ts +5 -1
  85. package/dist/lib/browser/chunk-67FEJJ6J.mjs.map +0 -7
  86. package/dist/lib/node/chunk-2KIDYJ7O.cjs.map +0 -7
  87. package/dist/lib/node-esm/chunk-36ZRRDQI.mjs +0 -8154
  88. package/dist/lib/node-esm/chunk-36ZRRDQI.mjs.map +0 -7
  89. package/dist/lib/node-esm/index.mjs +0 -416
  90. package/dist/lib/node-esm/index.mjs.map +0 -7
  91. package/dist/lib/node-esm/meta.json +0 -1
  92. package/dist/lib/node-esm/testing/index.mjs +0 -418
  93. package/dist/lib/node-esm/testing/index.mjs.map +0 -7
  94. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts +0 -2
  95. package/dist/types/src/packlets/identity/authenticator.node.test.d.ts.map +0 -1
  96. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts +0 -2
  97. package/dist/types/src/packlets/spaces/edge-feed-replicator.test.d.ts.map +0 -1
  98. package/dist/types/src/testing/setup.d.ts +0 -3
  99. package/dist/types/src/testing/setup.d.ts.map +0 -1
  100. package/src/packlets/spaces/edge-feed-replicator.test.ts +0 -251
  101. package/src/testing/setup.ts +0 -11
@@ -2,9 +2,8 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { onTestFinished, describe, expect, test } from 'vitest';
5
+ import expect from 'expect';
6
6
 
7
- import { Event } from '@dxos/async';
8
7
  import { Context } from '@dxos/context';
9
8
  import { CredentialGenerator, verifyCredential } from '@dxos/credentials';
10
9
  import {
@@ -16,9 +15,7 @@ import {
16
15
  SpaceProtocol,
17
16
  valueEncoding,
18
17
  } from '@dxos/echo-pipeline';
19
- import { type EdgeConnection, type MessageListener } from '@dxos/edge-client';
20
18
  import { FeedFactory, FeedStore } from '@dxos/feed-store';
21
- import { type FeedWrapper } from '@dxos/feed-store';
22
19
  import { Keyring } from '@dxos/keyring';
23
20
  import { type PublicKey } from '@dxos/keys';
24
21
  import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
@@ -27,6 +24,7 @@ import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
27
24
  import { AdmittedFeed } from '@dxos/protocols/proto/dxos/halo/credentials';
28
25
  import { createStorage, StorageType } from '@dxos/random-access-storage';
29
26
  import { BlobStore } from '@dxos/teleport-extension-object-sync';
27
+ import { afterTest, describe, test } from '@dxos/test';
30
28
 
31
29
  import { Identity } from './identity';
32
30
 
@@ -44,108 +42,16 @@ const createStores = () => {
44
42
 
45
43
  describe('identity/identity', () => {
46
44
  test('create', async () => {
47
- const setup = await setupIdentity();
48
-
49
- await writeGenesisCredential(setup);
50
-
51
- // Wait for identity to be ready.
52
- await setup.identity.ready();
53
- const identitySigner = setup.identity.getIdentityCredentialSigner();
54
- const credential = await identitySigner.createCredential({
55
- subject: setup.identityKey,
56
- assertion: {
57
- '@type': 'dxos.halo.credentials.IdentityProfile',
58
- profile: {
59
- displayName: 'Alice',
60
- },
61
- },
62
- });
63
-
64
- expect(credential.issuer).toEqual(setup.identityKey);
65
- expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
66
- });
67
-
68
- test('two devices', async () => {
69
- const signalContext = new MemorySignalManagerContext();
70
-
71
- const owner = await setupIdentity({ signalContext });
72
- await writeGenesisCredential(owner);
73
- await owner.identity.ready();
74
-
75
- const secondDevice = (
76
- await setupIdentity({
77
- signalContext,
78
- spaceKey: owner.spaceKey,
79
- identityKey: owner.identityKey,
80
- genesisFeedKey: owner.controlFeed.key,
81
- })
82
- ).identity;
83
-
84
- //
85
- // Second device admission
86
- //
87
- {
88
- const signer = owner.identity.getIdentityCredentialSigner();
89
- void owner.identity.controlPipeline.writer.write({
90
- credential: {
91
- credential: await signer.createCredential({
92
- subject: secondDevice.deviceKey,
93
- assertion: {
94
- '@type': 'dxos.halo.credentials.AuthorizedDevice',
95
- identityKey: owner.identityKey,
96
- deviceKey: secondDevice.deviceKey,
97
- },
98
- }),
99
- },
100
- });
101
-
102
- await secondDevice.ready();
103
- }
104
-
105
- expect(Array.from(owner.identity.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
106
- expect(Array.from(secondDevice.authorizedDeviceKeys.keys())).toEqual([owner.deviceKey, secondDevice.deviceKey]);
107
- });
108
-
109
- test('edge feed replicator', async () => {
110
- let replicationStarted = false;
111
- const connectedEvent = new Event();
112
- const setup = await setupIdentity({
113
- edgeConnection: {
114
- connected: connectedEvent,
115
- open: async () => {},
116
- close: async () => {},
117
- addListener: (_: MessageListener): (() => void) => {
118
- return () => {};
119
- },
120
- send: async (_) => {
121
- replicationStarted = true;
122
- },
123
- } as EdgeConnection,
124
- });
125
-
126
- await writeGenesisCredential(setup);
127
- connectedEvent.emit();
128
-
129
- await expect.poll(() => replicationStarted).toBeTruthy();
130
- });
131
-
132
- const setupIdentity = async (args?: {
133
- signalContext?: MemorySignalManagerContext;
134
- spaceKey?: PublicKey;
135
- identityKey?: PublicKey;
136
- genesisFeedKey?: PublicKey;
137
- edgeConnection?: EdgeConnection;
138
- }): Promise<TestIdentitySetup> => {
139
45
  const { storage, metadataStore, blobStore } = createStores();
140
46
 
141
47
  const keyring = new Keyring();
48
+ const identityKey = await keyring.createKey();
142
49
  const deviceKey = await keyring.createKey();
143
- const identityKey = args?.identityKey ?? (await keyring.createKey());
144
- const spaceKey = args?.spaceKey ?? (await keyring.createKey());
50
+ const spaceKey = await keyring.createKey();
145
51
 
146
52
  const feedStore = new FeedStore<FeedMessage>({
147
53
  factory: new FeedFactory<FeedMessage>({
148
- root: storage.createDirectory(),
54
+ root: storage.createDirectory('feeds'),
149
55
  signer: keyring,
150
56
  hypercore: {
151
57
  valueEncoding,
@@ -171,7 +77,7 @@ describe('identity/identity', () => {
171
77
  },
172
78
  blobStore,
173
79
  networkManager: new SwarmNetworkManager({
174
- signalManager: new MemorySignalManager(args?.signalContext ?? new MemorySignalManagerContext()),
80
+ signalManager: new MemorySignalManager(new MemorySignalManagerContext()),
175
81
  transportFactory: MemoryTransportFactory,
176
82
  }),
177
83
  });
@@ -181,7 +87,7 @@ describe('identity/identity', () => {
181
87
  id: await createIdFromSpaceKey(spaceKey),
182
88
  spaceKey,
183
89
  protocol,
184
- genesisFeed: args?.genesisFeedKey ? await feedStore.openFeed(args.genesisFeedKey) : controlFeed,
90
+ genesisFeed: controlFeed,
185
91
  feedProvider: (feedKey) => feedStore.openFeed(feedKey),
186
92
  memberKey: identityKey,
187
93
  metadataStore,
@@ -197,37 +103,242 @@ describe('identity/identity', () => {
197
103
  identityKey,
198
104
  deviceKey,
199
105
  space,
200
- edgeFeatures: args?.edgeConnection && { feedReplicator: true },
201
- edgeConnection: args?.edgeConnection,
202
106
  });
203
107
 
204
108
  await identity.open(new Context());
205
- onTestFinished(() => identity.close(new Context()));
206
- return { identity, identityKey, keyring, deviceKey, controlFeed, spaceKey, dataFeed };
207
- };
109
+ afterTest(() => identity.close(new Context()));
110
+
111
+ //
112
+ // Identity genesis
113
+ //
114
+ {
115
+ const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
116
+ const credentials = [
117
+ ...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
118
+ await generator.createDeviceAuthorization(deviceKey),
119
+ await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
120
+ ];
121
+
122
+ for (const credential of credentials) {
123
+ await identity.controlPipeline.writer.write({
124
+ credential: { credential },
125
+ });
126
+ }
127
+ }
128
+
129
+ // Wait for identity to be ready.
130
+ await identity.ready();
131
+ const identitySigner = identity.getIdentityCredentialSigner();
132
+ const credential = await identitySigner.createCredential({
133
+ subject: identityKey,
134
+ assertion: {
135
+ '@type': 'dxos.halo.credentials.IdentityProfile',
136
+ profile: {
137
+ displayName: 'Alice',
138
+ },
139
+ },
140
+ });
141
+
142
+ expect(credential.issuer).toEqual(identityKey);
143
+ expect(await verifyCredential(credential)).toEqual({ kind: 'pass' });
144
+ });
208
145
 
209
- const writeGenesisCredential = async (setup: TestIdentitySetup) => {
210
- const generator = new CredentialGenerator(setup.keyring, setup.identityKey, setup.deviceKey);
211
- const credentials = [
212
- ...(await generator.createSpaceGenesis(setup.spaceKey, setup.controlFeed.key)),
213
- await generator.createDeviceAuthorization(setup.deviceKey),
214
- await generator.createFeedAdmission(setup.spaceKey, setup.dataFeed.key, AdmittedFeed.Designation.DATA),
215
- ];
216
-
217
- for (const credential of credentials) {
218
- await setup.identity.controlPipeline.writer.write({
219
- credential: { credential },
146
+ test('two devices', async () => {
147
+ const signalContext = new MemorySignalManagerContext();
148
+
149
+ let spaceKey: PublicKey;
150
+ let identityKey: PublicKey;
151
+ let genesisFeedKey: PublicKey;
152
+ let identity1: Identity;
153
+ let identity2: Identity;
154
+
155
+ //
156
+ // First device
157
+ //
158
+ {
159
+ const { storage, metadataStore, blobStore } = createStores();
160
+
161
+ const keyring = new Keyring();
162
+ identityKey = await keyring.createKey();
163
+ const deviceKey = await keyring.createKey();
164
+ spaceKey = await keyring.createKey();
165
+
166
+ const feedStore = new FeedStore<FeedMessage>({
167
+ factory: new FeedFactory<FeedMessage>({
168
+ root: storage.createDirectory(),
169
+ signer: keyring,
170
+ hypercore: {
171
+ valueEncoding,
172
+ },
173
+ }),
174
+ });
175
+
176
+ const createFeed = async () => {
177
+ const feedKey = await keyring.createKey();
178
+ return feedStore.openFeed(feedKey, { writable: true });
179
+ };
180
+
181
+ const controlFeed = await createFeed();
182
+ genesisFeedKey = controlFeed.key;
183
+
184
+ const dataFeed = await createFeed();
185
+
186
+ const protocol = new SpaceProtocol({
187
+ topic: spaceKey,
188
+ swarmIdentity: {
189
+ peerKey: deviceKey,
190
+ identityKey,
191
+ credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
192
+ credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
193
+ },
194
+ blobStore,
195
+ networkManager: new SwarmNetworkManager({
196
+ signalManager: new MemorySignalManager(signalContext),
197
+ transportFactory: MemoryTransportFactory,
198
+ }),
199
+ });
200
+
201
+ await metadataStore.setIdentityRecord({ haloSpace: { key: spaceKey }, identityKey, deviceKey });
202
+ const space = new Space({
203
+ id: await createIdFromSpaceKey(spaceKey),
204
+ spaceKey,
205
+ protocol,
206
+ genesisFeed: controlFeed,
207
+ feedProvider: (feedKey) => feedStore.openFeed(feedKey),
208
+ memberKey: identityKey,
209
+ metadataStore,
210
+ onDelegatedInvitationStatusChange: async () => {},
211
+ onMemberRolesChanged: async () => {},
220
212
  });
213
+ await space.setControlFeed(controlFeed);
214
+ await space.setDataFeed(dataFeed);
215
+
216
+ const identity = (identity1 = new Identity({
217
+ signer: keyring,
218
+ identityKey,
219
+ deviceKey,
220
+ space,
221
+ }));
222
+
223
+ await identity.open(new Context());
224
+ afterTest(() => identity.close(new Context()));
225
+
226
+ //
227
+ // Identity genesis
228
+ //
229
+ {
230
+ const generator = new CredentialGenerator(keyring, identityKey, deviceKey);
231
+ const credentials = [
232
+ ...(await generator.createSpaceGenesis(spaceKey, controlFeed.key)),
233
+ await generator.createDeviceAuthorization(deviceKey),
234
+ await generator.createFeedAdmission(spaceKey, dataFeed.key, AdmittedFeed.Designation.DATA),
235
+ ];
236
+
237
+ for (const credential of credentials) {
238
+ await identity.controlPipeline.writer.write({
239
+ credential: { credential },
240
+ });
241
+ }
242
+ }
243
+
244
+ // Wait for identity to be ready.
245
+ await identity.ready();
221
246
  }
222
- };
223
- });
224
247
 
225
- type TestIdentitySetup = {
226
- identity: Identity;
227
- keyring: Keyring;
228
- identityKey: PublicKey;
229
- deviceKey: PublicKey;
230
- spaceKey: PublicKey;
231
- controlFeed: FeedWrapper<FeedMessage>;
232
- dataFeed: FeedWrapper<FeedMessage>;
233
- };
248
+ //
249
+ // Second device
250
+ //
251
+ {
252
+ const { storage, metadataStore, blobStore } = createStores();
253
+
254
+ const keyring = new Keyring();
255
+ const deviceKey = await keyring.createKey();
256
+
257
+ const feedStore = new FeedStore<FeedMessage>({
258
+ factory: new FeedFactory<FeedMessage>({
259
+ root: storage.createDirectory(),
260
+ signer: keyring,
261
+ hypercore: {
262
+ valueEncoding,
263
+ },
264
+ }),
265
+ });
266
+
267
+ const createFeed = async () => {
268
+ const feedKey = await keyring.createKey();
269
+ return feedStore.openFeed(feedKey, { writable: true });
270
+ };
271
+
272
+ const controlFeed = await createFeed();
273
+ const dataFeed = await createFeed();
274
+
275
+ const protocol = new SpaceProtocol({
276
+ topic: spaceKey,
277
+ swarmIdentity: {
278
+ peerKey: deviceKey,
279
+ identityKey,
280
+ credentialProvider: MOCK_AUTH_PROVIDER, // createHaloAuthProvider(createCredentialSignerWithKey(keyring, device_key)),
281
+ credentialAuthenticator: MOCK_AUTH_VERIFIER, // createHaloAuthVerifier(() => identity.authorizedDeviceKeys),
282
+ },
283
+ blobStore,
284
+ networkManager: new SwarmNetworkManager({
285
+ signalManager: new MemorySignalManager(signalContext),
286
+ transportFactory: MemoryTransportFactory,
287
+ }),
288
+ });
289
+
290
+ await metadataStore.setIdentityRecord({
291
+ haloSpace: { key: spaceKey },
292
+ identityKey: identity1.identityKey,
293
+ deviceKey,
294
+ });
295
+ const space = new Space({
296
+ id: await createIdFromSpaceKey(spaceKey),
297
+ spaceKey,
298
+ protocol,
299
+ genesisFeed: await feedStore.openFeed(genesisFeedKey),
300
+ feedProvider: (feedKey) => feedStore.openFeed(feedKey),
301
+ memberKey: identityKey,
302
+ metadataStore,
303
+ onDelegatedInvitationStatusChange: async () => {},
304
+ onMemberRolesChanged: async () => {},
305
+ });
306
+ await space.setControlFeed(controlFeed);
307
+ await space.setDataFeed(dataFeed);
308
+
309
+ const identity = (identity2 = new Identity({
310
+ signer: keyring,
311
+ identityKey: identity1.identityKey,
312
+ deviceKey,
313
+ space,
314
+ }));
315
+
316
+ await identity.open(new Context());
317
+ afterTest(() => identity.close(new Context()));
318
+ }
319
+
320
+ //
321
+ // Second device admission
322
+ //
323
+ {
324
+ const signer = identity1.getIdentityCredentialSigner();
325
+ void identity1.controlPipeline.writer.write({
326
+ credential: {
327
+ credential: await signer.createCredential({
328
+ subject: identity2.deviceKey,
329
+ assertion: {
330
+ '@type': 'dxos.halo.credentials.AuthorizedDevice',
331
+ identityKey: identity1.identityKey,
332
+ deviceKey: identity2.deviceKey,
333
+ },
334
+ }),
335
+ },
336
+ });
337
+
338
+ await identity2.ready();
339
+ }
340
+
341
+ expect(Array.from(identity1.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
342
+ expect(Array.from(identity2.authorizedDeviceKeys.keys())).toEqual([identity1.deviceKey, identity2.deviceKey]);
343
+ });
344
+ });
@@ -14,12 +14,10 @@ import {
14
14
  } from '@dxos/credentials';
15
15
  import { type Signer } from '@dxos/crypto';
16
16
  import { type Space } from '@dxos/echo-pipeline';
17
- import { type EdgeConnection } from '@dxos/edge-client';
18
- import { writeMessages, type FeedWrapper } from '@dxos/feed-store';
17
+ import { writeMessages } from '@dxos/feed-store';
19
18
  import { invariant } from '@dxos/invariant';
20
19
  import { PublicKey, type SpaceId } from '@dxos/keys';
21
20
  import { log } from '@dxos/log';
22
- import { type Runtime } from '@dxos/protocols/proto/dxos/config';
23
21
  import { type FeedMessage } from '@dxos/protocols/proto/dxos/echo/feed';
24
22
  import {
25
23
  AdmittedFeed,
@@ -34,7 +32,6 @@ import { type ComplexMap, ComplexSet } from '@dxos/util';
34
32
 
35
33
  import { TrustedKeySetAuthVerifier } from './authenticator';
36
34
  import { DefaultSpaceStateMachine } from './default-space-state-machine';
37
- import { EdgeFeedReplicator } from '../spaces';
38
35
 
39
36
  export type IdentityParams = {
40
37
  identityKey: PublicKey;
@@ -42,9 +39,6 @@ export type IdentityParams = {
42
39
  signer: Signer;
43
40
  space: Space;
44
41
  presence?: Presence;
45
-
46
- edgeConnection?: EdgeConnection;
47
- edgeFeatures?: Runtime.Client.EdgeFeatures;
48
42
  };
49
43
 
50
44
  /**
@@ -58,8 +52,6 @@ export class Identity {
58
52
  private readonly _deviceStateMachine: DeviceStateMachine;
59
53
  private readonly _profileStateMachine: ProfileStateMachine;
60
54
  private readonly _defaultSpaceStateMachine: DefaultSpaceStateMachine;
61
- private readonly _edgeFeedReplicator?: EdgeFeedReplicator = undefined;
62
-
63
55
  public readonly authVerifier: TrustedKeySetAuthVerifier;
64
56
 
65
57
  public readonly identityKey: PublicKey;
@@ -67,15 +59,15 @@ export class Identity {
67
59
 
68
60
  public readonly stateUpdate = new Event();
69
61
 
70
- constructor(params: IdentityParams) {
71
- this.space = params.space;
72
- this._signer = params.signer;
73
- this._presence = params.presence;
62
+ constructor({ space, signer, identityKey, deviceKey, presence }: IdentityParams) {
63
+ this.space = space;
64
+ this._signer = signer;
65
+ this._presence = presence;
74
66
 
75
- this.identityKey = params.identityKey;
76
- this.deviceKey = params.deviceKey;
67
+ this.identityKey = identityKey;
68
+ this.deviceKey = deviceKey;
77
69
 
78
- log.trace('dxos.halo.device', { deviceKey: params.deviceKey });
70
+ log.trace('dxos.halo.device', { deviceKey });
79
71
 
80
72
  this._deviceStateMachine = new DeviceStateMachine({
81
73
  identityKey: this.identityKey,
@@ -96,10 +88,6 @@ export class Identity {
96
88
  update: this.stateUpdate,
97
89
  authTimeout: AUTH_TIMEOUT,
98
90
  });
99
-
100
- if (params.edgeConnection && params.edgeFeatures?.feedReplicator) {
101
- this._edgeFeedReplicator = new EdgeFeedReplicator({ messenger: params.edgeConnection, spaceId: this.space.id });
102
- }
103
91
  }
104
92
 
105
93
  // TODO(burdon): Expose state object?
@@ -117,14 +105,7 @@ export class Identity {
117
105
  await this.space.spaceState.addCredentialProcessor(this._deviceStateMachine);
118
106
  await this.space.spaceState.addCredentialProcessor(this._profileStateMachine);
119
107
  await this.space.spaceState.addCredentialProcessor(this._defaultSpaceStateMachine);
120
-
121
- if (this._edgeFeedReplicator) {
122
- this.space.protocol.feedAdded.append(this._onFeedAdded);
123
- }
124
-
125
108
  await this.space.open(ctx);
126
-
127
- await this._edgeFeedReplicator?.open();
128
109
  }
129
110
 
130
111
  @trace.span()
@@ -134,13 +115,6 @@ export class Identity {
134
115
  await this.space.spaceState.removeCredentialProcessor(this._defaultSpaceStateMachine);
135
116
  await this.space.spaceState.removeCredentialProcessor(this._profileStateMachine);
136
117
  await this.space.spaceState.removeCredentialProcessor(this._deviceStateMachine);
137
-
138
- if (this._edgeFeedReplicator) {
139
- this.space.protocol.feedAdded.remove(this._onFeedAdded);
140
- }
141
-
142
- await this._edgeFeedReplicator?.close();
143
-
144
118
  await this.space.close();
145
119
  }
146
120
 
@@ -177,10 +151,6 @@ export class Identity {
177
151
  return this._presence;
178
152
  }
179
153
 
180
- get signer() {
181
- return this._signer;
182
- }
183
-
184
154
  /**
185
155
  * Issues credentials as identity.
186
156
  * Requires identity to be ready.
@@ -253,8 +223,4 @@ export class Identity {
253
223
  ].map((credential): FeedMessage.Payload => ({ credential: { credential } })),
254
224
  );
255
225
  }
256
-
257
- private _onFeedAdded = async (feed: FeedWrapper<any>) => {
258
- await this._edgeFeedReplicator!.addFeed(feed);
259
- };
260
226
  }
@@ -2,20 +2,19 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import { describe, expect, test, onTestFinished } from 'vitest';
5
+ import { expect } from 'chai';
6
6
 
7
7
  import { asyncChain } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { AlreadyJoinedError } from '@dxos/protocols';
10
10
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
11
+ import { describe, test, afterTest } from '@dxos/test';
11
12
 
12
13
  import { type ServiceContext } from '../services';
13
14
  import { createPeers, createServiceContext, performInvitation } from '../testing';
14
15
 
15
16
  const closeAfterTest = async (peer: ServiceContext) => {
16
- onTestFinished(async () => {
17
- await peer.close();
18
- });
17
+ afterTest(() => peer.close());
19
18
  return peer;
20
19
  };
21
20
 
@@ -23,9 +22,7 @@ describe('services/device', () => {
23
22
  test('creates identity', async () => {
24
23
  const peer = await createServiceContext();
25
24
  await peer.open(new Context());
26
- onTestFinished(async () => {
27
- await peer.close();
28
- });
25
+ afterTest(() => peer.close());
29
26
 
30
27
  const identity = await peer.createIdentity();
31
28
  expect(identity).not.to.be.undefined;
@@ -106,11 +106,13 @@ export class InvitationHostExtension extends RpcExtension<
106
106
 
107
107
  introduce: async (request) => {
108
108
  const { profile, invitationId } = request;
109
+
109
110
  const traceId = PublicKey.random().toHex();
110
111
  log.trace('dxos.sdk.invitation-handler.host.introduce', trace.begin({ id: traceId }));
111
112
 
112
113
  const invitation = this._requireActiveInvitation();
113
114
  this._assertInvitationState(Invitation.State.CONNECTED);
115
+
114
116
  if (invitationId !== invitation?.invitationId) {
115
117
  log.warn('incorrect invitationId', { expected: invitation.invitationId, actual: invitationId });
116
118
  this._callbacks.onError(new Error('Incorrect invitationId.'));
@@ -124,6 +126,7 @@ export class InvitationHostExtension extends RpcExtension<
124
126
  log('guest introduced themselves', { guestProfile: profile });
125
127
  this.guestProfile = profile;
126
128
  this._callbacks.onStateUpdate(Invitation.State.READY_FOR_AUTHENTICATION);
129
+
127
130
  this._challenge =
128
131
  invitation.authMethod === Invitation.AuthMethod.KNOWN_PUBLIC_KEY ? randomBytes(32) : undefined;
129
132
 
@@ -2,13 +2,13 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { beforeEach, onTestFinished, describe, expect, test } from 'vitest';
5
+ import { expect } from 'chai';
6
6
 
7
7
  import { type PushStream, sleep, Trigger, waitForCondition } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { PublicKey } from '@dxos/keys';
10
10
  import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
11
- import { openAndClose } from '@dxos/test-utils';
11
+ import { afterTest, describe, openAndClose, test } from '@dxos/test';
12
12
  import { range } from '@dxos/util';
13
13
 
14
14
  import { type InvitationProtocol } from './invitation-protocol';
@@ -34,7 +34,6 @@ type StateUpdateSink = PushStream<Invitation> & {
34
34
 
35
35
  describe('InvitationHandler', () => {
36
36
  let testBuilder: TestBuilder;
37
-
38
37
  beforeEach(() => {
39
38
  testBuilder = new TestBuilder();
40
39
  });
@@ -164,7 +163,7 @@ describe('InvitationHandler', () => {
164
163
  expect(guest.ctx.disposed).to.be.true;
165
164
  });
166
165
 
167
- test('guest gives up after trying with three hosts', { timeout: 20_000 }, async () => {
166
+ test('guest gives up after trying with three hosts', async () => {
168
167
  const hosts: PeerSetup[] = [await createPeer()];
169
168
  const [host] = hosts;
170
169
  const invitation = await createInvitation(host, { multiUse: true });
@@ -182,7 +181,7 @@ describe('InvitationHandler', () => {
182
181
 
183
182
  await sleep(10);
184
183
  expect(guest.sink.lastState).to.eq(Invitation.State.ERROR);
185
- });
184
+ }).timeout(20_000);
186
185
 
187
186
  test('single host - many guests', async () => {
188
187
  const hosts: PeerSetup[] = [await createPeer()];
@@ -262,9 +261,7 @@ describe('InvitationHandler', () => {
262
261
  });
263
262
  const protocol = new SpaceInvitationProtocol(peer.dataSpaceManager, peer.identity, peer.keyring, spaceKey);
264
263
  const ctx = new Context();
265
- onTestFinished(async () => {
266
- await ctx.dispose();
267
- });
264
+ afterTest(() => ctx.dispose());
268
265
  const sink = newStateUpdateSink();
269
266
  return { ctx, sink, peer, protocol, handler: invitationHandler, spaceKey };
270
267
  };
@@ -272,18 +269,14 @@ describe('InvitationHandler', () => {
272
269
  const hostInvitation = async (setup: PeerSetup, invitation: Invitation) => {
273
270
  await setup.ctx.dispose();
274
271
  setup.ctx = new Context();
275
- onTestFinished(async () => {
276
- await setup.ctx.dispose();
277
- });
272
+ afterTest(() => setup.ctx.dispose());
278
273
  setup.handler.handleInvitationFlow(setup.ctx, setup.sink, setup.protocol, invitation);
279
274
  };
280
275
 
281
276
  const acceptInvitation = async (setup: PeerSetup, invitation: Invitation): Promise<Trigger<string>> => {
282
277
  await setup.ctx.dispose();
283
278
  setup.ctx = new Context();
284
- onTestFinished(async () => {
285
- await setup.ctx.dispose();
286
- });
279
+ afterTest(() => setup.ctx.dispose());
287
280
  const authCodeInput = new Trigger<string>();
288
281
  setup.handler.acceptInvitation(setup.ctx, setup.sink, setup.protocol, invitation, authCodeInput);
289
282
  return authCodeInput;
@@ -463,7 +463,7 @@ export class InvitationsHandler {
463
463
  oldState: stateToString(invitation.state),
464
464
  });
465
465
  } else {
466
- log('invitation state update', {
466
+ log.info('invitation state update', {
467
467
  actor: actor?.constructor.name,
468
468
  newState: stateToString(newState),
469
469
  oldState: stateToString(invitation.state),