@dxos/echo-db 2.33.3-dev.1cc72521 → 2.33.3-dev.762b75aa

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 (77) hide show
  1. package/dist/src/echo.js +2 -2
  2. package/dist/src/echo.js.map +1 -1
  3. package/dist/src/echo.test.js +10 -10
  4. package/dist/src/echo.test.js.map +1 -1
  5. package/dist/src/halo/halo-party.d.ts.map +1 -1
  6. package/dist/src/halo/halo-party.js +1 -1
  7. package/dist/src/halo/halo-party.js.map +1 -1
  8. package/dist/src/halo/halo.d.ts +1 -0
  9. package/dist/src/halo/halo.d.ts.map +1 -1
  10. package/dist/src/halo/halo.js +10 -1
  11. package/dist/src/halo/halo.js.map +1 -1
  12. package/dist/src/halo/identity-manager.d.ts +0 -1
  13. package/dist/src/halo/identity-manager.d.ts.map +1 -1
  14. package/dist/src/halo/identity-manager.js +11 -11
  15. package/dist/src/halo/identity-manager.js.map +1 -1
  16. package/dist/src/halo/identity.d.ts +18 -13
  17. package/dist/src/halo/identity.d.ts.map +1 -1
  18. package/dist/src/halo/identity.js +24 -27
  19. package/dist/src/halo/identity.js.map +1 -1
  20. package/dist/src/invitations/offline-invitation-claimer.d.ts +2 -2
  21. package/dist/src/invitations/offline-invitation-claimer.d.ts.map +1 -1
  22. package/dist/src/invitations/offline-invitation-claimer.js +2 -4
  23. package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
  24. package/dist/src/parties/data-party.d.ts.map +1 -1
  25. package/dist/src/parties/data-party.js +1 -1
  26. package/dist/src/parties/data-party.js.map +1 -1
  27. package/dist/src/parties/data-party.test.d.ts +2 -0
  28. package/dist/src/parties/data-party.test.d.ts.map +1 -0
  29. package/dist/src/parties/data-party.test.js +129 -0
  30. package/dist/src/parties/data-party.test.js.map +1 -0
  31. package/dist/src/parties/party-factory.d.ts +2 -2
  32. package/dist/src/parties/party-factory.d.ts.map +1 -1
  33. package/dist/src/parties/party-factory.js +12 -20
  34. package/dist/src/parties/party-factory.js.map +1 -1
  35. package/dist/src/parties/party-manager.d.ts +2 -2
  36. package/dist/src/parties/party-manager.d.ts.map +1 -1
  37. package/dist/src/parties/party-manager.js +2 -1
  38. package/dist/src/parties/party-manager.js.map +1 -1
  39. package/dist/src/parties/party-manager.test.js +7 -22
  40. package/dist/src/parties/party-manager.test.js.map +1 -1
  41. package/dist/src/pipeline/party-core.test.js +1 -1
  42. package/dist/src/pipeline/party-core.test.js.map +1 -1
  43. package/dist/src/pipeline/party-processor.d.ts +0 -5
  44. package/dist/src/pipeline/party-processor.d.ts.map +1 -1
  45. package/dist/src/pipeline/party-processor.js +0 -7
  46. package/dist/src/pipeline/party-processor.js.map +1 -1
  47. package/dist/src/protocol/credentials-signer.d.ts +4 -4
  48. package/dist/src/protocol/credentials-signer.d.ts.map +1 -1
  49. package/dist/src/protocol/credentials-signer.js +8 -8
  50. package/dist/src/protocol/credentials-signer.js.map +1 -1
  51. package/dist/src/protocol/identity-credentials.d.ts +22 -0
  52. package/dist/src/protocol/identity-credentials.d.ts.map +1 -0
  53. package/dist/src/protocol/identity-credentials.js +50 -0
  54. package/dist/src/protocol/identity-credentials.js.map +1 -0
  55. package/dist/src/protocol/party-protocol-factory.d.ts +3 -4
  56. package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -1
  57. package/dist/src/protocol/party-protocol-factory.js +12 -15
  58. package/dist/src/protocol/party-protocol-factory.js.map +1 -1
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +17 -17
  61. package/src/echo.test.ts +10 -10
  62. package/src/echo.ts +1 -1
  63. package/src/halo/halo-party.ts +1 -2
  64. package/src/halo/halo.ts +8 -1
  65. package/src/halo/identity-manager.ts +13 -14
  66. package/src/halo/identity.ts +39 -41
  67. package/src/invitations/offline-invitation-claimer.ts +6 -7
  68. package/src/parties/data-party.test.ts +212 -0
  69. package/src/parties/data-party.ts +1 -2
  70. package/src/parties/party-factory.ts +14 -20
  71. package/src/parties/party-manager.test.ts +8 -42
  72. package/src/parties/party-manager.ts +4 -3
  73. package/src/pipeline/party-core.test.ts +2 -4
  74. package/src/pipeline/party-processor.ts +0 -13
  75. package/src/protocol/credentials-signer.ts +9 -9
  76. package/src/protocol/identity-credentials.ts +78 -0
  77. package/src/protocol/party-protocol-factory.ts +13 -17
@@ -22,12 +22,12 @@ import { NetworkManager } from '@dxos/network-manager';
22
22
  import { ObjectModel } from '@dxos/object-model';
23
23
 
24
24
  import { IdentityNotInitializedError } from '../errors';
25
- import { IdentityProvider } from '../halo';
26
25
  import {
27
26
  createDataPartyAdmissionMessages,
28
27
  GreetingInitiator, InvitationDescriptor, InvitationDescriptorType, OfflineInvitationClaimer
29
28
  } from '../invitations';
30
29
  import { PartyFeedProvider, PartyOptions } from '../pipeline';
30
+ import { IdentityCredentialsProvider } from '../protocol/identity-credentials';
31
31
  import { SnapshotStore } from '../snapshots';
32
32
  import { DataParty, PARTY_ITEM_TYPE } from './data-party';
33
33
 
@@ -38,7 +38,7 @@ const log = debug('dxos:echo-db:party-factory');
38
38
  */
39
39
  export class PartyFactory {
40
40
  constructor (
41
- private readonly _identityProvider: IdentityProvider,
41
+ private readonly _identityProvider: IdentityCredentialsProvider,
42
42
  private readonly _networkManager: NetworkManager,
43
43
  private readonly _modelFactory: ModelFactory,
44
44
  private readonly _snapshotStore: SnapshotStore,
@@ -52,8 +52,6 @@ export class PartyFactory {
52
52
  @timed(5_000)
53
53
  async createParty (): Promise<DataParty> {
54
54
  const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
55
- assert(identity.identityGenesis, 'HALO not initialized.');
56
- assert(identity.deviceKeyChain, 'Device KeyChain not initialized.');
57
55
  assert(!this._options.readOnly, 'PartyFactory is read-only.');
58
56
 
59
57
  const partyKey = await identity.keyring.createKeyRecord({ type: KeyType.PARTY });
@@ -66,7 +64,7 @@ export class PartyFactory {
66
64
 
67
65
  // PartyGenesis (self-signed by Party).
68
66
  await party.processor.writeHaloMessage(createPartyGenesisMessage(
69
- identity.signer,
67
+ identity.keyring,
70
68
  partyKey,
71
69
  writableFeed.key,
72
70
  partyKey)
@@ -74,15 +72,16 @@ export class PartyFactory {
74
72
 
75
73
  // KeyAdmit (IdentityGenesis in an Envelope signed by Party).
76
74
  await party.processor.writeHaloMessage(createEnvelopeMessage(
77
- identity.signer,
75
+ identity.keyring,
78
76
  partyKey.publicKey,
79
77
  wrapMessage(identity.identityGenesis),
80
78
  [partyKey])
81
79
  );
82
80
 
83
81
  // FeedAdmit (signed by the Device KeyChain).
82
+ // TODO(dmaretskyi): Is this really needed since a feed is already admitted by party genesis message.
84
83
  await party.processor.writeHaloMessage(createFeedAdmitMessage(
85
- identity.signer,
84
+ identity.keyring,
86
85
  partyKey.publicKey,
87
86
  writableFeed.key,
88
87
  [identity.deviceKeyChain]
@@ -91,7 +90,7 @@ export class PartyFactory {
91
90
  // IdentityInfo in an Envelope signed by the Device KeyChain.
92
91
  if (identity.identityInfo) {
93
92
  await party.processor.writeHaloMessage(createEnvelopeMessage(
94
- identity.signer,
93
+ identity.keyring,
95
94
  partyKey.publicKey,
96
95
  wrapMessage(identity.identityInfo),
97
96
  [identity.deviceKeyChain]
@@ -138,13 +137,12 @@ export class PartyFactory {
138
137
  );
139
138
 
140
139
  await party.open();
141
- assert(identity.identityKey, 'No identity key.');
142
140
  const isHalo = identity.identityKey.publicKey.equals(partyKey);
143
141
  const signingKey = isHalo ? identity.deviceKey : identity.deviceKeyChain;
144
142
  assert(signingKey, 'No device key or keychain.');
145
143
  // Write the Feed genesis message.
146
144
  await party.processor.writeHaloMessage(createFeedAdmitMessage(
147
- identity.signer,
145
+ identity.keyring,
148
146
  partyKey,
149
147
  feedKeyPair.publicKey,
150
148
  [signingKey]
@@ -213,7 +211,7 @@ export class PartyFactory {
213
211
  async (partyKey, nonce) => [createDataPartyAdmissionMessages(
214
212
  identity.createCredentialsSigner(),
215
213
  partyKey,
216
- identity.identityGenesis ?? raise(new IdentityNotInitializedError()),
214
+ identity.identityGenesis,
217
215
  nonce
218
216
  )]
219
217
  );
@@ -223,13 +221,11 @@ export class PartyFactory {
223
221
  const party = await this.addParty(partyKey, hints);
224
222
  await initiator.destroy();
225
223
  if (!haloInvitation) {
226
- assert(identity.deviceKeyChain);
227
-
228
224
  // Copy our signed IdentityInfo into the new Party.
229
225
  const infoMessage = identity.identityInfo;
230
226
  if (infoMessage) {
231
227
  await party.processor.writeHaloMessage(createEnvelopeMessage(
232
- identity.signer,
228
+ identity.keyring,
233
229
  partyKey,
234
230
  wrapMessage(infoMessage),
235
231
  [identity.deviceKeyChain]
@@ -244,8 +240,6 @@ export class PartyFactory {
244
240
  const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
245
241
 
246
242
  assert(!this._options.readOnly, 'PartyFactory is read-only');
247
- assert(identity.identityGenesis, 'IdentityGenesis must exist');
248
- assert(identity.deviceKeyChain, 'Device KeyChain must exist');
249
243
 
250
244
  const partyKey = await identity.keyring.createKeyRecord({ type: KeyType.PARTY });
251
245
  const party = await this.constructParty(partyKey.publicKey);
@@ -257,7 +251,7 @@ export class PartyFactory {
257
251
 
258
252
  // PartyGenesis (self-signed by Party).
259
253
  await party.processor.writeHaloMessage(createPartyGenesisMessage(
260
- identity.signer,
254
+ identity.keyring,
261
255
  partyKey,
262
256
  writableFeed.key,
263
257
  partyKey)
@@ -265,7 +259,7 @@ export class PartyFactory {
265
259
 
266
260
  // KeyAdmit (IdentityGenesis in an Envelope signed by Party).
267
261
  await party.processor.writeHaloMessage(createEnvelopeMessage(
268
- identity.signer,
262
+ identity.keyring,
269
263
  partyKey.publicKey,
270
264
  wrapMessage(identity.identityGenesis),
271
265
  [partyKey]
@@ -273,7 +267,7 @@ export class PartyFactory {
273
267
 
274
268
  // FeedAdmit (signed by the Device KeyChain).
275
269
  await party.processor.writeHaloMessage(createFeedAdmitMessage(
276
- identity.signer,
270
+ identity.keyring,
277
271
  partyKey.publicKey,
278
272
  writableFeed.key,
279
273
  [identity.deviceKeyChain]
@@ -282,7 +276,7 @@ export class PartyFactory {
282
276
  // IdentityInfo in an Envelope signed by the Device KeyChain.
283
277
  if (identity.identityInfo) {
284
278
  await party.processor.writeHaloMessage(createEnvelopeMessage(
285
- identity.signer,
279
+ identity.keyring,
286
280
  partyKey.publicKey,
287
281
  wrapMessage(identity.identityInfo),
288
282
  [identity.deviceKeyChain]
@@ -33,9 +33,9 @@ import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
33
33
  import { afterTest, testTimeout } from '@dxos/testutils';
34
34
 
35
35
  import { Item } from '../api';
36
- import { HaloFactory, Identity, IdentityManager } from '../halo';
37
36
  import { defaultInvitationAuthenticator, OfflineInvitationClaimer } from '../invitations';
38
37
  import { MetadataStore, PartyFeedProvider } from '../pipeline';
38
+ import { createTestIdentityCredentials } from '../protocol/identity-credentials';
39
39
  import { SnapshotStore } from '../snapshots';
40
40
  import { messageLogger } from '../testing';
41
41
  import { createRamStorage } from '../util';
@@ -58,33 +58,12 @@ const setup = async () => {
58
58
  const keyring = new Keyring();
59
59
  const metadataStore = new MetadataStore(createRamStorage());
60
60
  const feedStore = new FeedStore(createStorage('', StorageType.RAM), { valueEncoding: codec });
61
-
62
- const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
63
-
64
- assert(keyring.keys.length === 1);
65
-
66
61
  const snapshotStore = new SnapshotStore(createStorage('', StorageType.RAM));
67
62
  const modelFactory = new ModelFactory().registerModel(ObjectModel);
68
63
  const networkManager = new NetworkManager();
69
64
  const feedProviderFactory = (partyKey: PublicKey) => new PartyFeedProvider(metadataStore, keyring, feedStore, partyKey);
70
65
 
71
- const haloFactory = new HaloFactory(
72
- networkManager,
73
- modelFactory,
74
- snapshotStore,
75
- feedProviderFactory,
76
- keyring,
77
- {
78
- writeLogger: messageLogger('<<<'),
79
- readLogger: messageLogger('>>>')
80
- }
81
- );
82
- const haloParty = await haloFactory.createHalo({
83
- identityDisplayName: identityKey.publicKey.humanize()
84
- });
85
- afterTest(() => haloParty.close());
86
- const identity = new Identity(keyring, haloParty);
87
-
66
+ const identity = await createTestIdentityCredentials(keyring);
88
67
  const partyFactory = new PartyFactory(
89
68
  () => identity,
90
69
  networkManager,
@@ -171,33 +150,22 @@ describe('Party manager', () => {
171
150
  test('Create from cold start', async () => {
172
151
  const storage = createStorage('', StorageType.RAM);
173
152
  const feedStore = new FeedStore(storage, { valueEncoding: codec });
174
-
175
153
  const keyring = new Keyring();
176
154
  const metadataStore = new MetadataStore(createRamStorage());
177
-
178
- const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
179
- await keyring.createKeyRecord({ type: KeyType.DEVICE });
180
-
181
155
  const modelFactory = new ModelFactory().registerModel(ObjectModel);
182
156
  const snapshotStore = new SnapshotStore(createStorage('', StorageType.RAM));
183
157
  const networkManager = new NetworkManager();
184
158
  const feedProviderFactory = (partyKey: PublicKey) => new PartyFeedProvider(metadataStore, keyring, feedStore, partyKey);
159
+
160
+ const identity = await createTestIdentityCredentials(keyring);
185
161
  const partyFactory = new PartyFactory(
186
- () => identityManager.identity,
162
+ () => identity,
187
163
  networkManager,
188
164
  modelFactory,
189
165
  snapshotStore,
190
166
  feedProviderFactory
191
167
  );
192
- const haloFactory: HaloFactory = new HaloFactory(
193
- networkManager,
194
- modelFactory,
195
- snapshotStore,
196
- feedProviderFactory,
197
- keyring
198
- );
199
- const identityManager = new IdentityManager(keyring, haloFactory, metadataStore);
200
- const partyManager = new PartyManager(metadataStore, snapshotStore, () => identityManager.identity, partyFactory);
168
+ const partyManager = new PartyManager(metadataStore, snapshotStore, () => identity, partyFactory);
201
169
 
202
170
  /* TODO(telackey): Injecting "raw" Parties into the feeds behind the scenes seems fishy to me, as it writes the
203
171
  * Party messages in a slightly different way than the code inside PartyFactory does, and so could easily diverge
@@ -221,7 +189,7 @@ describe('Party manager', () => {
221
189
  assert(feedKey);
222
190
 
223
191
  const feedStream = createWritableFeedStream(feed);
224
- feedStream.write({ halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey) });
192
+ feedStream.write({ halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identity.identityKey) });
225
193
  feedStream.write({
226
194
  echo: checkType<EchoEnvelope>({
227
195
  itemId: 'foo',
@@ -235,8 +203,6 @@ describe('Party manager', () => {
235
203
  }
236
204
 
237
205
  // Open.
238
- await identityManager.createHalo();
239
- afterTest(() => identityManager.close());
240
206
  await partyManager.open();
241
207
  expect(partyManager.parties).toHaveLength(numParties);
242
208
  await partyManager.close();
@@ -450,7 +416,7 @@ describe('Party manager', () => {
450
416
  // Redeem the invitation on B.
451
417
  expect(partyManagerB.parties).toHaveLength(0);
452
418
  const partyB = await partyManagerB.joinParty(invitationDescriptor,
453
- OfflineInvitationClaimer.createSecretProvider(identityB));
419
+ OfflineInvitationClaimer.createSecretProvider(identityB.createCredentialsSigner()));
454
420
  expect(partyB).toBeDefined();
455
421
  log(`Joined ${partyB.key.toHex()}`);
456
422
 
@@ -13,9 +13,9 @@ import { timed } from '@dxos/debug';
13
13
  import { PartyKey, PartySnapshot } from '@dxos/echo-protocol';
14
14
  import { ComplexMap, boolGuard } from '@dxos/util';
15
15
 
16
- import { IdentityProvider } from '../halo';
17
16
  import { InvitationDescriptor } from '../invitations';
18
17
  import { MetadataStore } from '../pipeline';
18
+ import { IdentityCredentialsProvider } from '../protocol/identity-credentials';
19
19
  import { SnapshotStore } from '../snapshots';
20
20
  import { DataParty, PARTY_ITEM_TYPE, PARTY_TITLE_PROPERTY } from './data-party';
21
21
  import { PartyFactory } from './party-factory';
@@ -51,7 +51,7 @@ export class PartyManager {
51
51
  constructor (
52
52
  private readonly _metadataStore: MetadataStore,
53
53
  private readonly _snapshotStore: SnapshotStore,
54
- private readonly _identityProvider: IdentityProvider,
54
+ private readonly _identityProvider: IdentityCredentialsProvider,
55
55
  private readonly _partyFactory: PartyFactory
56
56
  ) {}
57
57
 
@@ -74,10 +74,11 @@ export class PartyManager {
74
74
 
75
75
  let partyKeys = this._metadataStore.parties.map(party => party.key).filter(boolGuard);
76
76
 
77
+ // Identity may be undefined, for example, on the first start.
77
78
  const identity = this._identityProvider();
78
79
 
79
80
  // TODO(telackey): Does it make any sense to load other parties if we don't have an HALO?
80
- if (identity?.identityKey) {
81
+ if (identity) {
81
82
  partyKeys = partyKeys.filter(partyKey => !partyKey.equals(identity.identityKey!.publicKey));
82
83
  }
83
84
 
@@ -325,12 +325,10 @@ describe('PartyCore', () => {
325
325
 
326
326
  createTestProtocolPair(
327
327
  new ReplicatorProtocolPluginFactory(
328
- peer1.partyFeedProvider,
329
- peer1.party.processor.getActiveFeedSet()
328
+ peer1.partyFeedProvider
330
329
  ).createPlugins().map(r => r.createExtension()),
331
330
  new ReplicatorProtocolPluginFactory(
332
- partyFeedProvider,
333
- peer1.party.processor.getActiveFeedSet()
331
+ partyFeedProvider
334
332
  ).createPlugins().map(r => r.createExtension())
335
333
  );
336
334
 
@@ -20,11 +20,6 @@ import { jsonReplacer } from '@dxos/util';
20
20
 
21
21
  const log = debug('dxos:echo-db:party-processor');
22
22
 
23
- export interface FeedSetProvider {
24
- get(): FeedKey[]
25
- added: Event<FeedKey>
26
- }
27
-
28
23
  /**
29
24
  * TODO(burdon): Wrapper/Bridge between HALO APIs.
30
25
  */
@@ -108,14 +103,6 @@ export class PartyProcessor {
108
103
  return this._state.getAdmittedBy(feedKey);
109
104
  }
110
105
 
111
- // TODO(burdon): Rename xxxProvider.
112
- getActiveFeedSet (): FeedSetProvider {
113
- return {
114
- get: () => this.feedKeys,
115
- added: this.feedAdded
116
- };
117
- }
118
-
119
106
  getOfflineInvitation (invitationID: Buffer) {
120
107
  return this._state.getInvitation(invitationID);
121
108
  }
@@ -19,17 +19,17 @@ export class CredentialsSigner {
19
19
 
20
20
  return new CredentialsSigner(
21
21
  keyring,
22
- () => identityKey,
23
- () => deviceKey,
24
- () => deviceKey
22
+ identityKey,
23
+ deviceKey,
24
+ deviceKey
25
25
  );
26
26
  }
27
27
 
28
28
  constructor (
29
29
  private readonly _signer: Signer,
30
- private readonly _getIdentityKey: () => KeyRecord,
31
- private readonly _getDeviceKey: () => KeyRecord,
32
- private readonly _getDeviceSigningKeys: () => KeyRecord | KeyChain
30
+ private readonly _identityKey: KeyRecord,
31
+ private readonly _deviceKey: KeyRecord,
32
+ private readonly _signingKeys: KeyRecord | KeyChain
33
33
  ) {}
34
34
 
35
35
  get signer (): Signer {
@@ -37,11 +37,11 @@ export class CredentialsSigner {
37
37
  }
38
38
 
39
39
  getIdentityKey (): KeyRecord {
40
- return this._getIdentityKey();
40
+ return this._identityKey;
41
41
  }
42
42
 
43
43
  getDeviceKey (): KeyRecord {
44
- return this._getDeviceKey();
44
+ return this._deviceKey;
45
45
  }
46
46
 
47
47
  /**
@@ -55,6 +55,6 @@ export class CredentialsSigner {
55
55
  * Devices need to sign with their keyChain including the device key admission credential in the signature.
56
56
  */
57
57
  getDeviceSigningKeys (): KeyRecord | KeyChain {
58
- return this._getDeviceSigningKeys();
58
+ return this._signingKeys;
59
59
  }
60
60
  }
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2022 DXOS.org
3
+ //
4
+
5
+ import { createIdentityInfoMessage, createKeyAdmitMessage, createPartyGenesisMessage, KeyChain, KeyRecord, Keyring, KeyType, SignedMessage } from '@dxos/credentials';
6
+
7
+ import { ContactManager, Preferences } from '../halo';
8
+ import { CredentialsSigner } from './credentials-signer';
9
+
10
+ /**
11
+ * Provides access to identity credentials without revealing the underlying mechanism (HALO party).
12
+ */
13
+ export interface IdentityCredentials {
14
+ keyring: Keyring
15
+ identityKey: KeyRecord
16
+ deviceKey: KeyRecord
17
+ deviceKeyChain: KeyChain
18
+ identityGenesis: SignedMessage
19
+ identityInfo: SignedMessage | undefined
20
+ displayName: string | undefined
21
+ createCredentialsSigner(): CredentialsSigner
22
+ preferences: Preferences | undefined
23
+ contacts: ContactManager | undefined
24
+ }
25
+
26
+ export type IdentityCredentialsProvider = () => IdentityCredentials | undefined
27
+
28
+ export async function createTestIdentityCredentials (keyring: Keyring): Promise<IdentityCredentials> {
29
+ const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
30
+ const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
31
+ const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
32
+
33
+ const partyGenesis = createPartyGenesisMessage(keyring, identityKey, feedKey.publicKey, deviceKey);
34
+ const keyAdmit = createKeyAdmitMessage(keyring, identityKey.publicKey, identityKey);
35
+
36
+ const messageMap = new Map();
37
+ messageMap.set(identityKey.publicKey.toHex(), keyAdmit);
38
+ messageMap.set(deviceKey.publicKey.toHex(), partyGenesis);
39
+ const deviceKeyChain = Keyring.buildKeyChain(deviceKey.publicKey, messageMap, [feedKey.publicKey]);
40
+
41
+ const displayName = identityKey.publicKey.humanize();
42
+ const identityInfo = createIdentityInfoMessage(keyring, displayName, identityKey);
43
+
44
+ return {
45
+ keyring,
46
+ identityKey,
47
+ deviceKey,
48
+ deviceKeyChain,
49
+ identityGenesis: keyAdmit.payload as SignedMessage,
50
+ identityInfo: identityInfo.payload as SignedMessage,
51
+ displayName,
52
+ createCredentialsSigner: () => new CredentialsSigner(keyring, identityKey, deviceKey, deviceKeyChain),
53
+ preferences: undefined,
54
+ contacts: undefined
55
+ };
56
+ }
57
+
58
+ export async function deriveTestDeviceCredentials (identity: IdentityCredentials): Promise<IdentityCredentials> {
59
+ const deviceKey = await identity.keyring.createKeyRecord({ type: KeyType.DEVICE });
60
+ const keyAdmit = createKeyAdmitMessage(identity.keyring, identity.identityKey.publicKey, deviceKey, [identity.identityKey]);
61
+
62
+ const messageMap = new Map();
63
+ messageMap.set(identity.identityKey.publicKey.toHex(), identity.identityGenesis);
64
+ messageMap.set(deviceKey.publicKey.toHex(), keyAdmit);
65
+ const deviceKeyChain = Keyring.buildKeyChain(deviceKey.publicKey, messageMap, []);
66
+
67
+ return {
68
+ ...identity,
69
+ deviceKey,
70
+ deviceKeyChain,
71
+ createCredentialsSigner: () => new CredentialsSigner(
72
+ identity.keyring,
73
+ identity.identityKey,
74
+ deviceKey,
75
+ deviceKeyChain
76
+ )
77
+ };
78
+ }
@@ -6,7 +6,7 @@ import debug from 'debug';
6
6
 
7
7
  import { synchronized } from '@dxos/async';
8
8
  import { discoveryKey, keyToString, PublicKey } from '@dxos/crypto';
9
- import { FeedKey, FeedSetProvider, PartyKey } from '@dxos/echo-protocol';
9
+ import { FeedKey, PartyKey } from '@dxos/echo-protocol';
10
10
  import type { HypercoreFeed } from '@dxos/feed-store';
11
11
  import { Protocol } from '@dxos/mesh-protocol';
12
12
  import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
@@ -32,12 +32,11 @@ export class PartyProtocolFactory {
32
32
  private readonly _networkManager: NetworkManager,
33
33
  private readonly _feedProvider: PartyFeedProvider,
34
34
  private readonly _peerId: PublicKey,
35
- private readonly _credentials: CredentialsProvider,
36
- activeFeeds: FeedSetProvider
35
+ private readonly _credentials: CredentialsProvider
37
36
  ) {
38
37
  // Replication.
39
38
  this._replicatorProtocolPluginFactory =
40
- new ReplicatorProtocolPluginFactory(this._feedProvider, activeFeeds);
39
+ new ReplicatorProtocolPluginFactory(this._feedProvider);
41
40
  }
42
41
 
43
42
  async start (plugins: Plugin[]) {
@@ -125,34 +124,31 @@ export class PartyProtocolFactory {
125
124
  */
126
125
  export class ReplicatorProtocolPluginFactory {
127
126
  constructor (
128
- private readonly _feedProvider: PartyFeedProvider,
129
- private readonly _activeFeeds: FeedSetProvider
127
+ private readonly _feedProvider: PartyFeedProvider
130
128
  ) {}
131
129
 
132
130
  createPlugins () {
133
131
  return [
134
132
  new Replicator({
135
133
  load: async () => {
136
- const partyFeeds = await Promise.all(this._activeFeeds.get().map(feedKey => this._openFeed(feedKey)));
137
- log(`Loading feeds: ${partyFeeds.map(feed => keyToString(feed.key))}`);
138
- return partyFeeds.map((feed) => {
139
- return { discoveryKey: feed.discoveryKey };
140
- });
134
+ const feeds = this._feedProvider.getFeeds();
135
+ log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
136
+ return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
141
137
  },
142
138
 
143
139
  subscribe: (addFeedToReplicatedSet: (feed: any) => void) => {
144
- return this._activeFeeds.added.on(async (feedKey) => {
145
- log(`Adding feed: ${feedKey.toHex()}`);
146
- const feed = await this._openFeed(feedKey);
147
- addFeedToReplicatedSet({ discoveryKey: feed.discoveryKey });
140
+ return this._feedProvider.feedOpened.on(async (feed) => {
141
+ log(`Adding feed: ${feed.key.toHex()}`);
142
+ addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
148
143
  });
149
144
  },
150
145
 
151
146
  replicate: async (remoteFeeds, info) => {
152
147
  // We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
153
148
  // TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
154
- log(`Replicating: peerId=${info.session}; feeds=${this._activeFeeds.get().map(key => key.toHex())}`);
155
- return Promise.all(this._activeFeeds.get().map(feedKey => this._openFeed(feedKey)));
149
+ const feeds = this._feedProvider.getFeeds();
150
+ log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
151
+ return feeds.map(feed => feed.feed);
156
152
  }
157
153
  })
158
154
  ];