@dxos/echo-db 2.33.5-dev.0d84e06f → 2.33.5-dev.33d2877e

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 (56) hide show
  1. package/dist/src/halo/halo-factory.d.ts +2 -2
  2. package/dist/src/halo/halo-factory.d.ts.map +1 -1
  3. package/dist/src/halo/halo-factory.js +2 -2
  4. package/dist/src/halo/halo-factory.js.map +1 -1
  5. package/dist/src/halo/halo-party.d.ts +3 -2
  6. package/dist/src/halo/halo-party.d.ts.map +1 -1
  7. package/dist/src/halo/halo-party.js +8 -4
  8. package/dist/src/halo/halo-party.js.map +1 -1
  9. package/dist/src/halo/party-opener.d.ts.map +1 -1
  10. package/dist/src/halo/party-opener.js +3 -1
  11. package/dist/src/halo/party-opener.js.map +1 -1
  12. package/dist/src/invitations/greeting-initiator.d.ts +2 -2
  13. package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
  14. package/dist/src/invitations/greeting-initiator.js +2 -1
  15. package/dist/src/invitations/greeting-initiator.js.map +1 -1
  16. package/dist/src/parties/data-party.d.ts +3 -3
  17. package/dist/src/parties/data-party.d.ts.map +1 -1
  18. package/dist/src/parties/data-party.js +8 -4
  19. package/dist/src/parties/data-party.js.map +1 -1
  20. package/dist/src/parties/data-party.test.js +5 -5
  21. package/dist/src/parties/data-party.test.js.map +1 -1
  22. package/dist/src/parties/party-factory.d.ts +2 -2
  23. package/dist/src/parties/party-factory.d.ts.map +1 -1
  24. package/dist/src/parties/party-factory.js +2 -2
  25. package/dist/src/parties/party-factory.js.map +1 -1
  26. package/dist/src/parties/party-manager.d.ts +3 -4
  27. package/dist/src/parties/party-manager.d.ts.map +1 -1
  28. package/dist/src/parties/party-manager.js +3 -5
  29. package/dist/src/parties/party-manager.js.map +1 -1
  30. package/dist/src/parties/party-manager.test.js +1 -4
  31. package/dist/src/parties/party-manager.test.js.map +1 -1
  32. package/dist/src/pipeline/metadata-store.js +1 -1
  33. package/dist/src/pipeline/metadata-store.js.map +1 -1
  34. package/dist/src/pipeline/party-core.d.ts +18 -4
  35. package/dist/src/pipeline/party-core.d.ts.map +1 -1
  36. package/dist/src/pipeline/party-core.js +7 -10
  37. package/dist/src/pipeline/party-core.js.map +1 -1
  38. package/dist/src/pipeline/party-core.test.js +4 -5
  39. package/dist/src/pipeline/party-core.test.js.map +1 -1
  40. package/dist/src/snapshots/snapshot-store.js +1 -1
  41. package/dist/src/snapshots/snapshot-store.js.map +1 -1
  42. package/dist/tsconfig.tsbuildinfo +1 -1
  43. package/package.json +17 -17
  44. package/src/halo/halo-factory.ts +3 -4
  45. package/src/halo/halo-party.ts +6 -4
  46. package/src/halo/party-opener.ts +3 -1
  47. package/src/invitations/greeting-initiator.ts +5 -4
  48. package/src/parties/data-party.test.ts +7 -6
  49. package/src/parties/data-party.ts +6 -5
  50. package/src/parties/party-factory.ts +2 -3
  51. package/src/parties/party-manager.test.ts +1 -4
  52. package/src/parties/party-manager.ts +3 -5
  53. package/src/pipeline/metadata-store.ts +1 -1
  54. package/src/pipeline/party-core.test.ts +4 -5
  55. package/src/pipeline/party-core.ts +27 -11
  56. package/src/snapshots/snapshot-store.ts +1 -1
@@ -4,6 +4,7 @@
4
4
 
5
5
  import debug from 'debug';
6
6
 
7
+ import { KeyType } from '@dxos/credentials';
7
8
  import { SubscriptionGroup, Unsubscribe } from '@dxos/util';
8
9
 
9
10
  import { PartyManager } from '../parties';
@@ -25,7 +26,8 @@ export const autoPartyOpener = (preferences: Preferences, partyManager: PartyMan
25
26
  for (const partyDesc of values) {
26
27
  if (!partyManager.parties.some(x => x.key === partyDesc.partyKey)) {
27
28
  log(`Auto-opening new Party from HALO: ${partyDesc.partyKey.toHex()} hints=${JSON.stringify(partyDesc.keyHints)}`);
28
- await partyManager.addParty(partyDesc.partyKey, partyDesc.keyHints);
29
+ const feedHints = partyDesc.keyHints.filter(hint => hint.type === KeyType.FEED).map(hint => hint.publicKey!);
30
+ await partyManager.addParty(partyDesc.partyKey, feedHints);
29
31
  }
30
32
  }
31
33
  }));
@@ -20,7 +20,8 @@ import {
20
20
  SecretProvider,
21
21
  WithTypeUrl,
22
22
  ERR_GREET_CONNECTED_TO_SWARM_TIMEOUT,
23
- SignedMessage
23
+ SignedMessage,
24
+ NotarizeResponse
24
25
  } from '@dxos/credentials';
25
26
  import { keyToString, PublicKey } from '@dxos/crypto';
26
27
  import { FullyConnectedTopology, NetworkManager } from '@dxos/network-manager';
@@ -111,7 +112,7 @@ export class GreetingInitiator {
111
112
  /**
112
113
  * Called after connecting to initiate greeting protocol exchange.
113
114
  */
114
- async redeemInvitation (secretProvider: SecretProvider) {
115
+ async redeemInvitation (secretProvider: SecretProvider): Promise<{ partyKey: PublicKey, hints: PublicKey[] }> {
115
116
  assert(this._state === GreetingState.CONNECTED);
116
117
  const { swarmKey } = this._invitationDescriptor;
117
118
 
@@ -150,7 +151,7 @@ export class GreetingInitiator {
150
151
  const credentialMessages = await this._getMessagesToNotarize(PublicKey.from(partyKey), nonce);
151
152
 
152
153
  // Send the signed payload to the greeting responder.
153
- const notarizeResponse = await this._greeterPlugin.send(responderPeerId,
154
+ const notarizeResponse: NotarizeResponse = await this._greeterPlugin.send(responderPeerId,
154
155
  createGreetingNotarizeMessage(secret, credentialMessages as WithTypeUrl<Message>[]));
155
156
 
156
157
  //
@@ -171,7 +172,7 @@ export class GreetingInitiator {
171
172
  this._state = GreetingState.SUCCEEDED;
172
173
  return {
173
174
  partyKey,
174
- hints: notarizeResponse.hints
175
+ hints: notarizeResponse.feedHints ?? []
175
176
  };
176
177
  }
177
178
 
@@ -5,7 +5,7 @@
5
5
  import expect from 'expect';
6
6
  import { it as test } from 'mocha';
7
7
 
8
- import { createKeyAdmitMessage, createPartyGenesisMessage, defaultSecretProvider, KeyHint, Keyring, KeyType, codec as haloCodec } from '@dxos/credentials';
8
+ import { createKeyAdmitMessage, createPartyGenesisMessage, defaultSecretProvider, Keyring, KeyType, codec as haloCodec } from '@dxos/credentials';
9
9
  import { PublicKey } from '@dxos/crypto';
10
10
  import { codec } from '@dxos/echo-protocol';
11
11
  import { FeedStore } from '@dxos/feed-store';
@@ -22,7 +22,7 @@ import { SnapshotStore } from '../snapshots';
22
22
  import { DataParty } from './data-party';
23
23
 
24
24
  describe('DataParty', () => {
25
- const createParty = async (identity: IdentityCredentials, partyKey: PublicKey, hints: KeyHint[]) => {
25
+ const createParty = async (identity: IdentityCredentials, partyKey: PublicKey, feedHints: PublicKey[]) => {
26
26
 
27
27
  const storage = createStorage('', StorageType.RAM);
28
28
  const snapshotStore = new SnapshotStore(storage.directory('snapshots'));
@@ -40,7 +40,7 @@ describe('DataParty', () => {
40
40
  identity.createCredentialsSigner(),
41
41
  identity.preferences,
42
42
  networkManager,
43
- hints
43
+ feedHints
44
44
  );
45
45
  };
46
46
 
@@ -88,6 +88,7 @@ describe('DataParty', () => {
88
88
  feed.key,
89
89
  partyKey
90
90
  ));
91
+ await party.processor.feedAdded.waitForCount(1);
91
92
 
92
93
  const authenticator = createAuthenticator(party.processor, identity.createCredentialsSigner(), party.credentialsWriter);
93
94
  const credentialsProvider = createCredentialsProvider(identity.createCredentialsSigner(), party.key, feed.key);
@@ -112,6 +113,8 @@ describe('DataParty', () => {
112
113
  feed.key,
113
114
  partyKey
114
115
  ));
116
+ await party.processor.feedAdded.waitForCount(1);
117
+
115
118
  const authenticator = createAuthenticator(party.processor, identityA.createCredentialsSigner(), party.credentialsWriter);
116
119
 
117
120
  const identityB = await deriveTestDeviceCredentials(identityA);
@@ -145,9 +148,7 @@ describe('DataParty', () => {
145
148
  ));
146
149
 
147
150
  const identityB = await deriveTestDeviceCredentials(identityA);
148
- const partyB = await createParty(identityB, partyKey.publicKey, [
149
- { type: KeyType.FEED, publicKey: feedA.key }
150
- ]);
151
+ const partyB = await createParty(identityB, partyKey.publicKey, [feedA.key]);
151
152
  await partyB.open();
152
153
 
153
154
  await partyA.database.createItem({ type: 'test:item-a' });
@@ -5,7 +5,6 @@
5
5
  import assert from 'assert';
6
6
 
7
7
  import { synchronized, Event } from '@dxos/async';
8
- import { KeyHint } from '@dxos/credentials';
9
8
  import { PublicKey } from '@dxos/crypto';
10
9
  import { timed } from '@dxos/debug';
11
10
  import { PartyKey, PartySnapshot, Timeframe } from '@dxos/echo-protocol';
@@ -57,8 +56,8 @@ export class DataParty {
57
56
  // TODO(dmaretskyi): Pull this out to a higher level. Should preferences be part of client API instead?
58
57
  private readonly _profilePreferences: Preferences | undefined,
59
58
  private readonly _networkManager: NetworkManager,
60
- private readonly _hints: KeyHint[] = [],
61
- _initialTimeframe?: Timeframe,
59
+ private readonly _feedHints: PublicKey[] = [],
60
+ private readonly _initialTimeframe?: Timeframe,
62
61
  _options: PartyOptions = {}
63
62
  ) {
64
63
  this._partyCore = new PartyCore(
@@ -67,7 +66,6 @@ export class DataParty {
67
66
  modelFactory,
68
67
  snapshotStore,
69
68
  this._credentialsSigner.getIdentityKey().publicKey,
70
- _initialTimeframe,
71
69
  _options
72
70
  );
73
71
 
@@ -152,7 +150,10 @@ export class DataParty {
152
150
  return this;
153
151
  }
154
152
 
155
- await this._partyCore.open(this._hints);
153
+ await this._partyCore.open({
154
+ feedHints: this._feedHints,
155
+ initialTimeframe: this._initialTimeframe
156
+ });
156
157
 
157
158
  this._invitationManager = new InvitationFactory(
158
159
  this._partyCore.processor,
@@ -9,7 +9,6 @@ import {
9
9
  createEnvelopeMessage,
10
10
  createFeedAdmitMessage,
11
11
  createPartyGenesisMessage,
12
- KeyHint,
13
12
  KeyType,
14
13
  SecretProvider,
15
14
  wrapMessage
@@ -111,7 +110,7 @@ export class PartyFactory {
111
110
  * @param partyKey
112
111
  * @param hints
113
112
  */
114
- async constructParty (partyKey: PartyKey, hints: KeyHint[] = [], initialTimeframe?: Timeframe) {
113
+ async constructParty (partyKey: PartyKey, feedHints: PublicKey[] = [], initialTimeframe?: Timeframe) {
115
114
  const identity = this._identityProvider() ?? raise(new IdentityNotInitializedError());
116
115
 
117
116
  // TODO(marik-d): Support read-only parties if this feed doesn't exist?
@@ -128,7 +127,7 @@ export class PartyFactory {
128
127
  identity.createCredentialsSigner(),
129
128
  identity.preferences,
130
129
  this._networkManager,
131
- hints,
130
+ feedHints,
132
131
  initialTimeframe,
133
132
  this._options
134
133
  );
@@ -140,10 +140,7 @@ describe('Party manager', () => {
140
140
  const feedStream = createWritableFeedStream(feed);
141
141
  feedStream.write(createPartyGenesisMessage(keyring, partyKey, feedKey.publicKey, identityKey));
142
142
 
143
- await partyManager.addParty(partyKey.publicKey, [{
144
- type: KeyType.FEED,
145
- publicKey: PublicKey.from(feed.key)
146
- }]);
143
+ await partyManager.addParty(partyKey.publicKey, [PublicKey.from(feed.key)]);
147
144
 
148
145
  await update;
149
146
  });
@@ -157,11 +157,9 @@ export class PartyManager {
157
157
 
158
158
  /**
159
159
  * Construct a party object and start replicating with the remote peer that created that party.
160
- * @param partyKey
161
- * @param hints
162
160
  */
163
161
  @synchronized
164
- async addParty (partyKey: PartyKey, hints: KeyHint[] = []) {
162
+ async addParty (partyKey: PartyKey, feedHints: PublicKey[] = []) {
165
163
  assert(this._open, 'PartyManager is not open.');
166
164
 
167
165
  /*
@@ -174,8 +172,8 @@ export class PartyManager {
174
172
  return this._parties.get(partyKey);
175
173
  }
176
174
 
177
- log(`Adding party partyKey=${partyKey.toHex()} hints=${hints.length}`);
178
- const party = await this._partyFactory.constructParty(partyKey, hints);
175
+ log(`Adding party partyKey=${partyKey.toHex()} hints=${feedHints.length}`);
176
+ const party = await this._partyFactory.constructParty(partyKey, feedHints);
179
177
  await party.open();
180
178
  await this._metadataStore.addParty(party.key);
181
179
  this._setParty(party);
@@ -90,7 +90,7 @@ export class MetadataStore {
90
90
  */
91
91
  async clear (): Promise<void> {
92
92
  log('Clearing all echo metadata...');
93
- await this._directory.destroy();
93
+ await this._directory.delete();
94
94
  }
95
95
 
96
96
  /**
@@ -161,7 +161,7 @@ describe('PartyCore', () => {
161
161
 
162
162
  const feedOpened = feedStore.feedOpenedEvent.waitForCount(1);
163
163
 
164
- await party.open([{ type: KeyType.FEED, publicKey: otherFeedKey }]);
164
+ await party.open({ feedHints: [otherFeedKey] });
165
165
  afterTest(async () => party.close());
166
166
 
167
167
  await feedOpened;
@@ -281,10 +281,9 @@ describe('PartyCore', () => {
281
281
  [peer1.partyKey]
282
282
  ));
283
283
 
284
- await party2.open([{
285
- publicKey: peer1.feedKey,
286
- type: KeyType.FEED
287
- }]);
284
+ await party2.open({
285
+ feedHints: [peer1.feedKey]
286
+ });
288
287
  afterTest(async () => party2.close());
289
288
 
290
289
  createTestProtocolPair(
@@ -5,7 +5,7 @@
5
5
  import assert from 'assert';
6
6
 
7
7
  import { synchronized } from '@dxos/async';
8
- import { KeyHint, KeyType, Message as HaloMessage } from '@dxos/credentials';
8
+ import { KeyType, Message as HaloMessage } from '@dxos/credentials';
9
9
  import { PublicKey } from '@dxos/crypto';
10
10
  import { timed } from '@dxos/debug';
11
11
  import { createFeedWriter, DatabaseSnapshot, FeedWriter, PartyKey, PartySnapshot, Timeframe } from '@dxos/echo-protocol';
@@ -28,6 +28,22 @@ export interface PartyOptions {
28
28
  snapshotInterval?: number;
29
29
  }
30
30
 
31
+ export interface OpenOptions {
32
+ /**
33
+ * Keys of initial feeds needed to bootstrap the party.
34
+ */
35
+ feedHints?: PublicKey[]
36
+ /**
37
+ * Timeframe to start processing feed messages from.
38
+ */
39
+ initialTimeframe?: Timeframe
40
+ /**
41
+ * Timeframe which must be reached until further processing.
42
+ * PartyCore.open will block until this timeframe is reached.
43
+ */
44
+ targetTimeframe?: Timeframe
45
+ }
46
+
31
47
  /**
32
48
  * Encapsulates core components needed by a party:
33
49
  * - ECHO database with item-manager & item-demuxer.
@@ -55,7 +71,6 @@ export class PartyCore {
55
71
  private readonly _modelFactory: ModelFactory,
56
72
  private readonly _snapshotStore: SnapshotStore,
57
73
  private readonly _memberKey: PublicKey,
58
- private readonly _initialTimeframe?: Timeframe,
59
74
  private readonly _options: PartyOptions = {}
60
75
  ) { }
61
76
 
@@ -108,12 +123,17 @@ export class PartyCore {
108
123
  */
109
124
  @synchronized
110
125
  @timed(1_000)
111
- async open (keyHints: KeyHint[] = []) {
126
+ async open (options: OpenOptions = {}) {
127
+ const {
128
+ feedHints = [],
129
+ initialTimeframe
130
+ } = options;
131
+
112
132
  if (this.isOpen) {
113
133
  return this;
114
134
  }
115
135
 
116
- this._timeframeClock = new TimeframeClock(this._initialTimeframe);
136
+ this._timeframeClock = new TimeframeClock(initialTimeframe);
117
137
 
118
138
  // Open all feeds known from metadata and open or create a writable feed to the party.
119
139
  await this._feedProvider.openKnownFeeds();
@@ -128,12 +148,8 @@ export class PartyCore {
128
148
  void this._feedProvider.createOrOpenReadOnlyFeed(feed);
129
149
  }));
130
150
 
131
- // Hint at our own writable feed.
132
- // TODO(dmaretskyi): Does not seem like it should be required, but without it replication between devices (B -> A) breaks.
133
- await this._partyProcessor.takeHints([{ type: KeyType.FEED, publicKey: writableFeed.key }]);
134
-
135
- if (keyHints.length > 0) {
136
- await this._partyProcessor.takeHints(keyHints);
151
+ if (feedHints.length > 0) {
152
+ await this._partyProcessor.takeHints(feedHints.map(publicKey => ({ publicKey, type: KeyType.FEED })));
137
153
  }
138
154
 
139
155
  //
@@ -142,7 +158,7 @@ export class PartyCore {
142
158
 
143
159
  const iterator = await this._feedProvider.createIterator(
144
160
  createMessageSelector(this._partyProcessor, this._timeframeClock),
145
- this._initialTimeframe
161
+ initialTimeframe
146
162
  );
147
163
 
148
164
  this._pipeline = new Pipeline(
@@ -59,6 +59,6 @@ export class SnapshotStore {
59
59
  */
60
60
  async clear () {
61
61
  log('Clearing all snapshots..');
62
- await this._directory.destroy();
62
+ await this._directory.delete();
63
63
  }
64
64
  }