@dxos/echo-db 2.33.8 → 2.33.9-dev.7d11f506

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 (103) hide show
  1. package/dist/src/halo/halo-factory.d.ts +1 -1
  2. package/dist/src/halo/halo-factory.d.ts.map +1 -1
  3. package/dist/src/halo/halo-factory.js +7 -6
  4. package/dist/src/halo/halo-factory.js.map +1 -1
  5. package/dist/src/halo/halo-party.d.ts +4 -6
  6. package/dist/src/halo/halo-party.d.ts.map +1 -1
  7. package/dist/src/halo/halo-party.js +10 -4
  8. package/dist/src/halo/halo-party.js.map +1 -1
  9. package/dist/src/halo/identity-manager.d.ts.map +1 -1
  10. package/dist/src/halo/identity-manager.js +8 -2
  11. package/dist/src/halo/identity-manager.js.map +1 -1
  12. package/dist/src/halo/party-opener.d.ts.map +1 -1
  13. package/dist/src/halo/party-opener.js +2 -4
  14. package/dist/src/halo/party-opener.js.map +1 -1
  15. package/dist/src/halo/preferences.d.ts.map +1 -1
  16. package/dist/src/halo/preferences.js +3 -6
  17. package/dist/src/halo/preferences.js.map +1 -1
  18. package/dist/src/invitations/greeting-initiator.d.ts +5 -4
  19. package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
  20. package/dist/src/invitations/greeting-initiator.js +2 -2
  21. package/dist/src/invitations/greeting-initiator.js.map +1 -1
  22. package/dist/src/invitations/greeting-responder.d.ts +4 -7
  23. package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
  24. package/dist/src/invitations/greeting-responder.js +4 -18
  25. package/dist/src/invitations/greeting-responder.js.map +1 -1
  26. package/dist/src/invitations/invitation-factory.d.ts +2 -1
  27. package/dist/src/invitations/invitation-factory.d.ts.map +1 -1
  28. package/dist/src/invitations/invitation-factory.js +3 -5
  29. package/dist/src/invitations/invitation-factory.js.map +1 -1
  30. package/dist/src/packlets/database/data-mirror.test.js +1 -1
  31. package/dist/src/packlets/database/data-mirror.test.js.map +1 -1
  32. package/dist/src/packlets/database/item-demuxer.test.js +1 -1
  33. package/dist/src/packlets/database/item-demuxer.test.js.map +1 -1
  34. package/dist/src/packlets/database/testing.js +1 -1
  35. package/dist/src/packlets/database/testing.js.map +1 -1
  36. package/dist/src/packlets/database/timeframe-clock.d.ts +2 -1
  37. package/dist/src/packlets/database/timeframe-clock.d.ts.map +1 -1
  38. package/dist/src/packlets/database/timeframe-clock.js +15 -5
  39. package/dist/src/packlets/database/timeframe-clock.js.map +1 -1
  40. package/dist/src/parties/data-party.d.ts +4 -3
  41. package/dist/src/parties/data-party.d.ts.map +1 -1
  42. package/dist/src/parties/data-party.js +9 -5
  43. package/dist/src/parties/data-party.js.map +1 -1
  44. package/dist/src/parties/data-party.test.js +12 -12
  45. package/dist/src/parties/data-party.test.js.map +1 -1
  46. package/dist/src/parties/party-factory.d.ts +2 -4
  47. package/dist/src/parties/party-factory.d.ts.map +1 -1
  48. package/dist/src/parties/party-factory.js +11 -8
  49. package/dist/src/parties/party-factory.js.map +1 -1
  50. package/dist/src/parties/party-manager.d.ts +1 -1
  51. package/dist/src/parties/party-manager.d.ts.map +1 -1
  52. package/dist/src/parties/party-manager.js +13 -13
  53. package/dist/src/parties/party-manager.js.map +1 -1
  54. package/dist/src/parties/party-manager.test.js +9 -6
  55. package/dist/src/parties/party-manager.test.js.map +1 -1
  56. package/dist/src/pipeline/feed-muxer.js +1 -1
  57. package/dist/src/pipeline/feed-muxer.js.map +1 -1
  58. package/dist/src/pipeline/feed-muxer.test.js +2 -2
  59. package/dist/src/pipeline/feed-muxer.test.js.map +1 -1
  60. package/dist/src/pipeline/message-selector.d.ts +1 -2
  61. package/dist/src/pipeline/message-selector.d.ts.map +1 -1
  62. package/dist/src/pipeline/message-selector.js +4 -31
  63. package/dist/src/pipeline/message-selector.js.map +1 -1
  64. package/dist/src/pipeline/metadata-store.d.ts +7 -2
  65. package/dist/src/pipeline/metadata-store.d.ts.map +1 -1
  66. package/dist/src/pipeline/metadata-store.js +9 -0
  67. package/dist/src/pipeline/metadata-store.js.map +1 -1
  68. package/dist/src/pipeline/party-feed-provider.d.ts +2 -2
  69. package/dist/src/pipeline/party-feed-provider.d.ts.map +1 -1
  70. package/dist/src/pipeline/party-feed-provider.js +2 -1
  71. package/dist/src/pipeline/party-feed-provider.js.map +1 -1
  72. package/dist/src/pipeline/party-pipeline.d.ts +5 -5
  73. package/dist/src/pipeline/party-pipeline.d.ts.map +1 -1
  74. package/dist/src/pipeline/party-pipeline.js +6 -7
  75. package/dist/src/pipeline/party-pipeline.js.map +1 -1
  76. package/dist/src/pipeline/party-pipeline.test.js +13 -18
  77. package/dist/src/pipeline/party-pipeline.test.js.map +1 -1
  78. package/dist/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +17 -17
  80. package/src/halo/halo-factory.ts +6 -6
  81. package/src/halo/halo-party.ts +14 -6
  82. package/src/halo/identity-manager.ts +11 -2
  83. package/src/halo/party-opener.ts +2 -4
  84. package/src/halo/preferences.ts +4 -8
  85. package/src/invitations/greeting-initiator.ts +8 -2
  86. package/src/invitations/greeting-responder.ts +7 -26
  87. package/src/invitations/invitation-factory.ts +2 -2
  88. package/src/packlets/database/data-mirror.test.ts +2 -2
  89. package/src/packlets/database/item-demuxer.test.ts +2 -2
  90. package/src/packlets/database/testing.ts +2 -2
  91. package/src/packlets/database/timeframe-clock.ts +4 -1
  92. package/src/parties/data-party.test.ts +12 -12
  93. package/src/parties/data-party.ts +14 -6
  94. package/src/parties/party-factory.ts +17 -9
  95. package/src/parties/party-manager.test.ts +9 -6
  96. package/src/parties/party-manager.ts +14 -12
  97. package/src/pipeline/feed-muxer.test.ts +2 -2
  98. package/src/pipeline/feed-muxer.ts +2 -2
  99. package/src/pipeline/message-selector.ts +4 -35
  100. package/src/pipeline/metadata-store.ts +15 -2
  101. package/src/pipeline/party-feed-provider.ts +2 -2
  102. package/src/pipeline/party-pipeline.test.ts +13 -19
  103. package/src/pipeline/party-pipeline.ts +13 -12
@@ -25,12 +25,12 @@ import {
25
25
  verify
26
26
  } from '@dxos/crypto';
27
27
  import { checkType } from '@dxos/debug';
28
- import { codec, EchoEnvelope, Timeframe } from '@dxos/echo-protocol';
28
+ import { codec, EchoEnvelope } from '@dxos/echo-protocol';
29
29
  import { createWritableFeedStream, FeedStore } from '@dxos/feed-store';
30
30
  import { ModelFactory } from '@dxos/model-factory';
31
31
  import { NetworkManager } from '@dxos/network-manager';
32
32
  import { ObjectModel } from '@dxos/object-model';
33
- import { PublicKey } from '@dxos/protocols';
33
+ import { PublicKey, Timeframe } from '@dxos/protocols';
34
34
  import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
35
35
  import { afterTest, testTimeout } from '@dxos/testutils';
36
36
  import { humanize } from '@dxos/util';
@@ -134,17 +134,19 @@ describe('Party manager', () => {
134
134
 
135
135
  // TODO(burdon): Create multiple feeds.
136
136
  const { publicKey, secretKey } = createKeyPair();
137
- const { feed } = await feedStore.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
137
+ const feed = await feedStore.openReadWriteFeed(PublicKey.from(publicKey), secretKey);
138
138
  const feedKey = await keyring.addKeyRecord({
139
139
  publicKey: PublicKey.from(feed.key),
140
140
  secretKey: feed.secretKey,
141
141
  type: KeyType.FEED
142
142
  });
143
143
 
144
- const feedStream = createWritableFeedStream(feed);
145
- feedStream.write(createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey));
144
+ await feed.append({
145
+ timeframe: new Timeframe(),
146
+ halo: createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey)
147
+ });
146
148
 
147
- await partyManager.addParty(partyKey.publicKey, [PublicKey.from(feed.key)]);
149
+ await partyManager.addParty(partyKey.publicKey, feed.key);
148
150
 
149
151
  await update;
150
152
  });
@@ -185,6 +187,7 @@ describe('Party manager', () => {
185
187
  assert(keyRecord, 'Key is not found in keyring');
186
188
  assert(keyRecord.secretKey, 'Missing secret key');
187
189
  await metadataStore.addPartyFeed(partyKey.publicKey, keyRecord.publicKey);
190
+ await metadataStore.setGenesisFeed(partyKey.publicKey, keyRecord.publicKey);
188
191
 
189
192
  // TODO(burdon): Create multiple feeds.
190
193
  const { feed } = await feedStore.openReadWriteFeed(keyRecord.publicKey, keyRecord.secretKey);
@@ -7,7 +7,7 @@ import debug from 'debug';
7
7
  import unionWith from 'lodash.unionwith';
8
8
 
9
9
  import { Event, synchronized } from '@dxos/async';
10
- import { KeyHint, KeyType, SecretProvider } from '@dxos/credentials';
10
+ import { SecretProvider } from '@dxos/credentials';
11
11
  import { failUndefined, timed } from '@dxos/debug';
12
12
  import { PartyKey, PartySnapshot } from '@dxos/echo-protocol';
13
13
  import { PublicKey } from '@dxos/protocols';
@@ -96,11 +96,15 @@ export class PartyManager {
96
96
  const snapshot = await this._snapshotStore.load(partyKey);
97
97
 
98
98
  const metadata = this._metadataStore.getParty(partyKey) ?? failUndefined();
99
+ if (!metadata.genesisFeedKey) {
100
+ log(`Skipping loading party with missing genesis feed key: ${partyKey}`);
101
+ continue;
102
+ }
99
103
 
100
104
  const party = snapshot
101
105
  ? await this._partyFactory.constructPartyFromSnapshot(snapshot)
102
106
  : await this._partyFactory.constructParty(partyKey);
103
- party._setFeedHints(metadata.feedKeys ?? []);
107
+ party._setGenesisFeedKey(metadata.genesisFeedKey);
104
108
 
105
109
  const isActive = identity?.preferences?.isPartyActive(partyKey) ?? true;
106
110
  if (isActive) {
@@ -163,7 +167,7 @@ export class PartyManager {
163
167
  * Construct a party object and start replicating with the remote peer that created that party.
164
168
  */
165
169
  @synchronized
166
- async addParty (partyKey: PartyKey, feedHints: PublicKey[] = []) {
170
+ async addParty (partyKey: PartyKey, genesisFeedKey: PublicKey) {
167
171
  assert(this._open, 'PartyManager is not open.');
168
172
 
169
173
  /*
@@ -176,11 +180,14 @@ export class PartyManager {
176
180
  return this._parties.get(partyKey);
177
181
  }
178
182
 
179
- log(`Adding party partyKey=${partyKey.toHex()} hints=${feedHints.length}`);
183
+ log(`Adding party partyKey=${partyKey.toHex()}`);
180
184
  const party = await this._partyFactory.constructParty(partyKey);
181
- party._setFeedHints(feedHints);
182
- await party.open();
185
+ party._setGenesisFeedKey(genesisFeedKey);
186
+
183
187
  await this._metadataStore.addParty(party.key);
188
+ await this._metadataStore.setGenesisFeed(party.key, genesisFeedKey);
189
+
190
+ await party.open();
184
191
  this._setParty(party);
185
192
  return party;
186
193
  }
@@ -327,14 +334,9 @@ export class PartyManager {
327
334
  return;
328
335
  }
329
336
 
330
- const keyHints: KeyHint[] = [
331
- ...party.processor.memberKeys.map(publicKey => ({ publicKey: publicKey, type: KeyType.UNKNOWN })),
332
- ...party.processor.feedKeys.map(publicKey => ({ publicKey: publicKey, type: KeyType.FEED }))
333
- ];
334
-
335
337
  await identity.preferences.recordPartyJoining({
336
338
  partyKey: party.key,
337
- keyHints
339
+ genesisFeed: party.genesisFeedKey
338
340
  });
339
341
  }
340
342
  }
@@ -9,10 +9,10 @@ import { it as test } from 'mocha';
9
9
  import { waitForCondition, latch } from '@dxos/async';
10
10
  import { createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
11
11
  import { createId, createKeyPair } from '@dxos/crypto';
12
- import { codec, createFeedWriter, FeedSelector, FeedStoreIterator, IEchoStream, Timeframe } from '@dxos/echo-protocol';
12
+ import { codec, createFeedWriter, FeedSelector, FeedStoreIterator, IEchoStream } from '@dxos/echo-protocol';
13
13
  import { FeedStore, createWritableFeedStream } from '@dxos/feed-store';
14
14
  import { createSetPropertyMutation } from '@dxos/model-factory';
15
- import { PublicKey } from '@dxos/protocols';
15
+ import { PublicKey, Timeframe } from '@dxos/protocols';
16
16
  import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
17
17
  import { jsonReplacer } from '@dxos/util';
18
18
 
@@ -9,9 +9,9 @@ import { Event } from '@dxos/async';
9
9
  import { Message as HaloMessage } from '@dxos/credentials';
10
10
  import { checkType } from '@dxos/debug';
11
11
  import {
12
- createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter, Timeframe
12
+ createFeedMeta, EchoEnvelope, FeedMessage, FeedStoreIterator, FeedWriter, IEchoStream, mapFeedWriter
13
13
  } from '@dxos/echo-protocol';
14
- import { PublicKey } from '@dxos/protocols';
14
+ import { PublicKey, Timeframe } from '@dxos/protocols';
15
15
  import { jsonReplacer } from '@dxos/util';
16
16
 
17
17
  import { EchoProcessor, TimeframeClock } from '../packlets/database';
@@ -5,12 +5,9 @@
5
5
  import assert from 'assert';
6
6
  import debug from 'debug';
7
7
 
8
- import { getPartyCredentialMessageType, PartyCredential } from '@dxos/credentials';
9
8
  import { MessageSelector } from '@dxos/echo-protocol';
10
- import { PublicKey } from '@dxos/protocols';
11
9
 
12
10
  import { TimeframeClock } from '../packlets/database';
13
- import { PartyStateProvider } from './party-processor';
14
11
 
15
12
  const log = debug('dxos:echo-db:message-selector');
16
13
 
@@ -23,44 +20,16 @@ const log = debug('dxos:echo-db:message-selector');
23
20
  * @param partyProcessor
24
21
  * @param timeframeClock
25
22
  */
26
- export const createMessageSelector = (partyProcessor: PartyStateProvider, timeframeClock: TimeframeClock): MessageSelector => candidates => {
27
- // Check ECHO message candidates first since they are less expensive than HALO cancidates.
23
+ export const createMessageSelector = (timeframeClock: TimeframeClock): MessageSelector => candidates => {
24
+ // Pick the first candidate with a valid timeframe that has no gaps.
28
25
  for (let i = 0; i < candidates.length; i++) {
29
- const { data: { timeframe, echo } } = candidates[i];
30
- const feedKey = PublicKey.from(candidates[i].key);
31
- if (!echo) {
32
- continue;
33
- }
34
-
35
- assert(timeframe);
36
- if (partyProcessor.isFeedAdmitted(feedKey) && !timeframeClock.hasGaps(timeframe)) {
37
- return i;
38
- }
39
- }
40
-
41
- // Check HALO message candidates.
42
- for (let i = 0; i < candidates.length; i++) {
43
- const { data: { timeframe, halo } } = candidates[i];
44
- const feedKey = PublicKey.from(candidates[i].key);
45
- if (!halo) {
46
- continue;
47
- }
26
+ const { data: { timeframe } } = candidates[i];
48
27
 
49
28
  assert(timeframe);
50
- if (partyProcessor.isFeedAdmitted(feedKey) && !timeframeClock.hasGaps(timeframe)) {
29
+ if (!timeframeClock.hasGaps(timeframe)) {
51
30
  return i;
52
31
  }
53
-
54
- if (partyProcessor.genesisRequired) {
55
- try { // TODO(dmaretskyi): Get getPartyCredentialMessageType crashes for some reason.
56
- // TODO(telackey): Add check that this is for the right Party.
57
- if (getPartyCredentialMessageType(halo) === PartyCredential.Type.PARTY_GENESIS) {
58
- return i;
59
- }
60
- } catch { }
61
- }
62
32
  }
63
-
64
33
  // Not ready for this message yet.
65
34
  log('Skipping...');
66
35
  };
@@ -7,8 +7,8 @@ import debug from 'debug';
7
7
 
8
8
  import { synchronized } from '@dxos/async';
9
9
  import { failUndefined } from '@dxos/debug';
10
- import { EchoMetadata, PartyMetadata, schema, Timeframe } from '@dxos/echo-protocol';
11
- import { PublicKey } from '@dxos/protocols';
10
+ import { EchoMetadata, PartyMetadata, schema } from '@dxos/echo-protocol';
11
+ import { PublicKey, Timeframe } from '@dxos/protocols';
12
12
  import { Directory } from '@dxos/random-access-multi-storage';
13
13
 
14
14
  /**
@@ -20,6 +20,11 @@ export const STORAGE_VERSION = 1;
20
20
 
21
21
  const log = debug('dxos:snapshot-store');
22
22
 
23
+ export interface AddPartyOptions {
24
+ key: PublicKey
25
+ genesisFeed: PublicKey
26
+ }
27
+
23
28
  export class MetadataStore {
24
29
  private _metadata: EchoMetadata = {
25
30
  version: STORAGE_VERSION,
@@ -147,6 +152,14 @@ export class MetadataStore {
147
152
  await this._save();
148
153
  }
149
154
 
155
+ async setGenesisFeed (partyKey: PublicKey, feedKey: PublicKey): Promise<void> {
156
+ assert(PublicKey.isPublicKey(feedKey));
157
+ await this.addPartyFeed(partyKey, feedKey);
158
+ const party = this.getParty(partyKey) ?? failUndefined();
159
+ party.genesisFeedKey = feedKey;
160
+ await this._save();
161
+ }
162
+
150
163
  /**
151
164
  * Sets the data feed key in the party specified by public key and saves updated data in persistent storage.
152
165
  * Update party's feed list.
@@ -7,9 +7,9 @@ import debug from 'debug';
7
7
 
8
8
  import { Event, synchronized } from '@dxos/async';
9
9
  import { Keyring, KeyType } from '@dxos/credentials';
10
- import { FeedSelector, FeedStoreIterator, MessageSelector, Timeframe } from '@dxos/echo-protocol';
10
+ import { FeedSelector, FeedStoreIterator, MessageSelector } from '@dxos/echo-protocol';
11
11
  import { FeedDescriptor, FeedStore } from '@dxos/feed-store';
12
- import { PublicKey } from '@dxos/protocols';
12
+ import { PublicKey, Timeframe } from '@dxos/protocols';
13
13
  import { ComplexMap } from '@dxos/util';
14
14
 
15
15
  import { MetadataStore } from './metadata-store';
@@ -5,16 +5,16 @@
5
5
  import expect from 'expect';
6
6
  import { it as test } from 'mocha';
7
7
 
8
- import { promiseTimeout } from '@dxos/async';
8
+ import { promiseTimeout, sleep } from '@dxos/async';
9
9
  import { createFeedAdmitMessage, createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
10
10
  import { createId } from '@dxos/crypto';
11
11
  import { checkType } from '@dxos/debug';
12
- import { codec, FeedMessage, Timeframe } from '@dxos/echo-protocol';
12
+ import { codec, FeedMessage } from '@dxos/echo-protocol';
13
13
  import { FeedStore } from '@dxos/feed-store';
14
14
  import { createTestProtocolPair } from '@dxos/mesh-protocol';
15
15
  import { ModelFactory } from '@dxos/model-factory';
16
16
  import { ObjectModel } from '@dxos/object-model';
17
- import { PublicKey } from '@dxos/protocols';
17
+ import { PublicKey, Timeframe } from '@dxos/protocols';
18
18
  import { createStorage, StorageType } from '@dxos/random-access-multi-storage';
19
19
  import { afterTest } from '@dxos/testutils';
20
20
 
@@ -49,7 +49,7 @@ describe('PartyPipeline', () => {
49
49
  );
50
50
 
51
51
  const feed = await partyFeedProvider.createOrOpenWritableFeed();
52
- await party.open({ feedHints: [feed.key] });
52
+ await party.open({ genesisFeedKey: feed.key });
53
53
  afterTest(async () => party.close());
54
54
 
55
55
  // PartyGenesis (self-signed by Party).
@@ -104,7 +104,7 @@ describe('PartyPipeline', () => {
104
104
  }
105
105
 
106
106
  await party.close();
107
- await party.open({ feedHints: [feedKey] });
107
+ await party.open({ genesisFeedKey: feedKey });
108
108
 
109
109
  {
110
110
  await party.database.select().exec().update.waitFor(result => result.entities.length === 2);
@@ -132,7 +132,7 @@ describe('PartyPipeline', () => {
132
132
  expect(partyFeedProvider.getFeeds().find(k => k.key.equals(feedKey.publicKey))).toBeTruthy();
133
133
  });
134
134
 
135
- test('opens feed from hints', async () => {
135
+ test('does not open unrelated feeds', async () => {
136
136
  const storage = createStorage('', StorageType.RAM);
137
137
  const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
138
138
  afterTest(async () => feedStore.close());
@@ -158,21 +158,19 @@ describe('PartyPipeline', () => {
158
158
  PublicKey.random()
159
159
  );
160
160
 
161
- await partyFeedProvider.createOrOpenWritableFeed();
161
+ const writeFeed = await partyFeedProvider.createOrOpenWritableFeed();
162
162
 
163
- const feedOpened = feedStore.feedOpenedEvent.waitForCount(1);
164
-
165
- await party.open({ feedHints: [otherFeedKey] });
163
+ await party.open({ genesisFeedKey: writeFeed.key });
166
164
  afterTest(async () => party.close());
167
165
 
168
- await feedOpened;
166
+ // Wait for events to be processed.
167
+ await sleep(5);
169
168
 
170
- expect(partyFeedProvider.getFeeds().some(k => k.key.equals(otherFeedKey))).toEqual(true);
169
+ expect(partyFeedProvider.getFeeds().some(k => k.key.equals(otherFeedKey))).toEqual(false);
171
170
  });
172
171
 
173
172
  test('manually create item', async () => {
174
173
  const { party, partyFeedProvider } = await setup();
175
- await party.open();
176
174
 
177
175
  const feed = await partyFeedProvider.createOrOpenWritableFeed();
178
176
 
@@ -193,7 +191,6 @@ describe('PartyPipeline', () => {
193
191
 
194
192
  test('admit a second feed to the party', async () => {
195
193
  const { party, keyring, partyKey, feedStore } = await setup();
196
- await party.open();
197
194
 
198
195
  const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
199
196
  const fullKey = keyring.getFullKey(feedKey.publicKey);
@@ -223,7 +220,6 @@ describe('PartyPipeline', () => {
223
220
 
224
221
  test('admit feed and then open it', async () => {
225
222
  const { party, keyring, partyKey, feedStore } = await setup();
226
- await party.open();
227
223
 
228
224
  const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
229
225
  const fullKey = keyring.getFullKey(feedKey.publicKey);
@@ -270,7 +266,7 @@ describe('PartyPipeline', () => {
270
266
  expect(timeframe.isEmpty()).toBeFalsy();
271
267
 
272
268
  await party.close();
273
- await party.open({ feedHints: [feedKey], targetTimeframe: timeframe });
269
+ await party.open({ genesisFeedKey: feedKey, targetTimeframe: timeframe });
274
270
  });
275
271
 
276
272
  test('two instances replicating', async () => {
@@ -304,9 +300,7 @@ describe('PartyPipeline', () => {
304
300
  [peer1.partyKey]
305
301
  ));
306
302
 
307
- await party2.open({
308
- feedHints: [peer1.feedKey]
309
- });
303
+ await party2.open({ genesisFeedKey: peer1.feedKey });
310
304
  afterTest(async () => party2.close());
311
305
 
312
306
  createTestProtocolPair(
@@ -7,9 +7,11 @@ import assert from 'assert';
7
7
  import { synchronized } from '@dxos/async';
8
8
  import { KeyType, Message as HaloMessage } from '@dxos/credentials';
9
9
  import { timed } from '@dxos/debug';
10
- import { createFeedWriter, DatabaseSnapshot, FeedSelector, FeedWriter, PartyKey, PartySnapshot, Timeframe } from '@dxos/echo-protocol';
10
+ import {
11
+ createFeedWriter, DatabaseSnapshot, FeedSelector, FeedWriter, PartyKey, PartySnapshot
12
+ } from '@dxos/echo-protocol';
11
13
  import { ModelFactory } from '@dxos/model-factory';
12
- import { PublicKey } from '@dxos/protocols';
14
+ import { PublicKey, Timeframe } from '@dxos/protocols';
13
15
  import { SubscriptionGroup } from '@dxos/util';
14
16
 
15
17
  import { createMessageSelector, PartyProcessor, PartyFeedProvider, FeedMuxer } from '.';
@@ -30,9 +32,9 @@ export interface PipelineOptions {
30
32
 
31
33
  export interface OpenOptions {
32
34
  /**
33
- * Keys of initial feeds needed to bootstrap the party.
35
+ * Initial feed that contains PartyGenesis message and acts as the root for the feed DAG.
34
36
  */
35
- feedHints?: PublicKey[]
37
+ genesisFeedKey: PublicKey
36
38
  /**
37
39
  * Timeframe to start processing feed messages from.
38
40
  */
@@ -123,9 +125,9 @@ export class PartyPipeline {
123
125
  */
124
126
  @synchronized
125
127
  @timed(1_000)
126
- async open (options: OpenOptions = {}) {
128
+ async open (options: OpenOptions) {
127
129
  const {
128
- feedHints = [],
130
+ genesisFeedKey,
129
131
  initialTimeframe,
130
132
  targetTimeframe
131
133
  } = options;
@@ -147,17 +149,16 @@ export class PartyPipeline {
147
149
  void this._feedProvider.createOrOpenReadOnlyFeed(feed);
148
150
  }));
149
151
 
150
- if (feedHints.length > 0) {
151
- await this._partyProcessor.takeHints(feedHints.map(publicKey => ({ publicKey, type: KeyType.FEED })));
152
- }
152
+ // TODO(dmaretskyi): We still need to hint at the genesis feed for some reason, not doing this breaks invitation tests.
153
+ await this._partyProcessor.takeHints([{ type: KeyType.FEED, publicKey: genesisFeedKey }]);
153
154
 
154
155
  //
155
156
  // Pipeline
156
157
  //
157
158
 
158
159
  const iterator = await this._feedProvider.createIterator(
159
- createMessageSelector(this._partyProcessor, this._timeframeClock),
160
- createFeedSelector(this._partyProcessor, feedHints),
160
+ createMessageSelector(this._timeframeClock),
161
+ createFeedSelector(this._partyProcessor, genesisFeedKey),
161
162
  initialTimeframe
162
163
  );
163
164
 
@@ -256,4 +257,4 @@ export class PartyPipeline {
256
257
  }
257
258
  }
258
259
 
259
- const createFeedSelector = (partyProcessor: PartyProcessor, hints: PublicKey[]): FeedSelector => feed => hints.some(hint => hint.equals(feed.key)) || partyProcessor.isFeedAdmitted(feed.key);
260
+ const createFeedSelector = (partyProcessor: PartyProcessor, genesisFeed: PublicKey): FeedSelector => feed => genesisFeed.equals(feed.key) || partyProcessor.isFeedAdmitted(feed.key);