@dxos/echo-db 2.33.1 → 2.33.2-dev.18eaaced

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 (217) hide show
  1. package/dist/src/echo.d.ts +8 -8
  2. package/dist/src/echo.d.ts.map +1 -1
  3. package/dist/src/echo.js +15 -16
  4. package/dist/src/echo.js.map +1 -1
  5. package/dist/src/echo.test.js +7 -13
  6. package/dist/src/echo.test.js.map +1 -1
  7. package/dist/src/halo/contact-manager.d.ts +4 -4
  8. package/dist/src/halo/contact-manager.d.ts.map +1 -1
  9. package/dist/src/halo/contact-manager.js +10 -4
  10. package/dist/src/halo/contact-manager.js.map +1 -1
  11. package/dist/src/halo/halo-factory.d.ts +14 -9
  12. package/dist/src/halo/halo-factory.d.ts.map +1 -1
  13. package/dist/src/halo/halo-factory.js +47 -14
  14. package/dist/src/halo/halo-factory.js.map +1 -1
  15. package/dist/src/halo/halo-party.d.ts +35 -7
  16. package/dist/src/halo/halo-party.d.ts.map +1 -1
  17. package/dist/src/halo/halo-party.js +97 -18
  18. package/dist/src/halo/halo-party.js.map +1 -1
  19. package/dist/src/halo/halo.d.ts +14 -12
  20. package/dist/src/halo/halo.d.ts.map +1 -1
  21. package/dist/src/halo/halo.js +31 -29
  22. package/dist/src/halo/halo.js.map +1 -1
  23. package/dist/src/halo/halo.test.d.ts +2 -0
  24. package/dist/src/halo/halo.test.d.ts.map +1 -0
  25. package/dist/src/halo/halo.test.js +162 -0
  26. package/dist/src/halo/halo.test.js.map +1 -0
  27. package/dist/src/halo/identity-manager.d.ts +10 -8
  28. package/dist/src/halo/identity-manager.d.ts.map +1 -1
  29. package/dist/src/halo/identity-manager.js +24 -20
  30. package/dist/src/halo/identity-manager.js.map +1 -1
  31. package/dist/src/halo/identity.d.ts +12 -6
  32. package/dist/src/halo/identity.d.ts.map +1 -1
  33. package/dist/src/halo/identity.js +11 -15
  34. package/dist/src/halo/identity.js.map +1 -1
  35. package/dist/src/halo/index.d.ts +1 -1
  36. package/dist/src/halo/index.d.ts.map +1 -1
  37. package/dist/src/halo/index.js +1 -1
  38. package/dist/src/halo/index.js.map +1 -1
  39. package/dist/src/halo/party-opener.js +1 -1
  40. package/dist/src/halo/party-opener.js.map +1 -1
  41. package/dist/src/halo/preferences.d.ts +9 -9
  42. package/dist/src/halo/preferences.d.ts.map +1 -1
  43. package/dist/src/halo/preferences.js +25 -15
  44. package/dist/src/halo/preferences.js.map +1 -1
  45. package/dist/src/index.d.ts +1 -1
  46. package/dist/src/index.js +1 -1
  47. package/dist/src/invitations/greeting-initiator.d.ts +14 -4
  48. package/dist/src/invitations/greeting-initiator.d.ts.map +1 -1
  49. package/dist/src/invitations/greeting-initiator.js +15 -16
  50. package/dist/src/invitations/greeting-initiator.js.map +1 -1
  51. package/dist/src/invitations/greeting-responder.d.ts +3 -3
  52. package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
  53. package/dist/src/invitations/greeting-responder.js +3 -4
  54. package/dist/src/invitations/greeting-responder.js.map +1 -1
  55. package/dist/src/invitations/halo-recovery-initiator.d.ts +6 -4
  56. package/dist/src/invitations/halo-recovery-initiator.d.ts.map +1 -1
  57. package/dist/src/invitations/halo-recovery-initiator.js +15 -26
  58. package/dist/src/invitations/halo-recovery-initiator.js.map +1 -1
  59. package/dist/src/invitations/index.d.ts +1 -1
  60. package/dist/src/invitations/index.js +1 -1
  61. package/dist/src/invitations/{invitation-manager.d.ts → invitation-factory.d.ts} +5 -6
  62. package/dist/src/invitations/invitation-factory.d.ts.map +1 -0
  63. package/dist/src/invitations/{invitation-manager.js → invitation-factory.js} +9 -15
  64. package/dist/src/invitations/invitation-factory.js.map +1 -0
  65. package/dist/src/invitations/offline-invitation-claimer.d.ts +3 -3
  66. package/dist/src/invitations/offline-invitation-claimer.js +1 -1
  67. package/dist/src/parties/{party-internal.d.ts → data-party.d.ts} +13 -11
  68. package/dist/src/parties/data-party.d.ts.map +1 -0
  69. package/dist/src/parties/{party-internal.js → data-party.js} +27 -37
  70. package/dist/src/parties/data-party.js.map +1 -0
  71. package/dist/src/parties/index.d.ts +1 -2
  72. package/dist/src/parties/index.d.ts.map +1 -1
  73. package/dist/src/parties/index.js +1 -2
  74. package/dist/src/parties/index.js.map +1 -1
  75. package/dist/src/parties/party-factory.d.ts +10 -11
  76. package/dist/src/parties/party-factory.d.ts.map +1 -1
  77. package/dist/src/parties/party-factory.js +25 -16
  78. package/dist/src/parties/party-factory.js.map +1 -1
  79. package/dist/src/parties/party-manager.d.ts +9 -9
  80. package/dist/src/parties/party-manager.d.ts.map +1 -1
  81. package/dist/src/parties/party-manager.js +13 -13
  82. package/dist/src/parties/party-manager.js.map +1 -1
  83. package/dist/src/parties/party-manager.test.js +69 -68
  84. package/dist/src/parties/party-manager.test.js.map +1 -1
  85. package/dist/src/{halo → parties}/party-preferences.d.ts +3 -3
  86. package/dist/src/parties/party-preferences.d.ts.map +1 -0
  87. package/dist/src/{halo → parties}/party-preferences.js +3 -3
  88. package/dist/src/parties/party-preferences.js.map +1 -0
  89. package/dist/src/pipeline/index.d.ts +3 -1
  90. package/dist/src/pipeline/index.d.ts.map +1 -1
  91. package/dist/src/pipeline/index.js +3 -1
  92. package/dist/src/pipeline/index.js.map +1 -1
  93. package/dist/src/{metadata → pipeline}/metadata-store.d.ts +0 -0
  94. package/dist/src/{metadata → pipeline}/metadata-store.d.ts.map +1 -1
  95. package/dist/src/{metadata → pipeline}/metadata-store.js +0 -0
  96. package/dist/src/{metadata → pipeline}/metadata-store.js.map +1 -1
  97. package/dist/src/{metadata → pipeline}/metadata-store.test.d.ts +0 -0
  98. package/dist/src/pipeline/metadata-store.test.d.ts.map +1 -0
  99. package/dist/src/{metadata → pipeline}/metadata-store.test.js +0 -0
  100. package/dist/src/{metadata → pipeline}/metadata-store.test.js.map +1 -1
  101. package/dist/src/{parties → pipeline}/party-core.d.ts +0 -0
  102. package/dist/src/pipeline/party-core.d.ts.map +1 -0
  103. package/dist/src/{parties → pipeline}/party-core.js +8 -4
  104. package/dist/src/pipeline/party-core.js.map +1 -0
  105. package/dist/src/{parties → pipeline}/party-core.test.d.ts +0 -0
  106. package/dist/src/pipeline/party-core.test.d.ts.map +1 -0
  107. package/dist/src/{parties → pipeline}/party-core.test.js +3 -4
  108. package/dist/src/pipeline/party-core.test.js.map +1 -0
  109. package/dist/src/pipeline/party-feed-provider.d.ts +3 -2
  110. package/dist/src/pipeline/party-feed-provider.d.ts.map +1 -1
  111. package/dist/src/pipeline/party-feed-provider.js +40 -19
  112. package/dist/src/pipeline/party-feed-provider.js.map +1 -1
  113. package/dist/src/protocol/auth-plugin.d.ts +7 -0
  114. package/dist/src/protocol/auth-plugin.d.ts.map +1 -0
  115. package/dist/src/protocol/auth-plugin.js +16 -0
  116. package/dist/src/protocol/auth-plugin.js.map +1 -0
  117. package/dist/src/protocol/authenticator.d.ts +14 -0
  118. package/dist/src/protocol/authenticator.d.ts.map +1 -0
  119. package/dist/src/protocol/authenticator.js +31 -0
  120. package/dist/src/protocol/authenticator.js.map +1 -0
  121. package/dist/src/protocol/authenticator.test.d.ts +2 -0
  122. package/dist/src/protocol/authenticator.test.d.ts.map +1 -0
  123. package/dist/src/protocol/authenticator.test.js +45 -0
  124. package/dist/src/protocol/authenticator.test.js.map +1 -0
  125. package/dist/src/protocol/credentials-signer.d.ts +31 -0
  126. package/dist/src/protocol/credentials-signer.d.ts.map +1 -0
  127. package/dist/src/protocol/credentials-signer.js +53 -0
  128. package/dist/src/protocol/credentials-signer.js.map +1 -0
  129. package/dist/src/protocol/halo-recovery-plugin.d.ts +10 -0
  130. package/dist/src/protocol/halo-recovery-plugin.d.ts.map +1 -0
  131. package/dist/src/protocol/halo-recovery-plugin.js +18 -0
  132. package/dist/src/protocol/halo-recovery-plugin.js.map +1 -0
  133. package/dist/src/protocol/index.d.ts +7 -0
  134. package/dist/src/protocol/index.d.ts.map +1 -0
  135. package/dist/src/{metadata → protocol}/index.js +7 -2
  136. package/dist/src/protocol/index.js.map +1 -0
  137. package/dist/src/protocol/offline-invitation-plugin.d.ts +9 -0
  138. package/dist/src/protocol/offline-invitation-plugin.d.ts.map +1 -0
  139. package/dist/src/protocol/offline-invitation-plugin.js +17 -0
  140. package/dist/src/protocol/offline-invitation-plugin.js.map +1 -0
  141. package/dist/src/{pipeline → protocol}/party-protocol-factory.d.ts +7 -17
  142. package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -0
  143. package/dist/src/{pipeline → protocol}/party-protocol-factory.js +7 -47
  144. package/dist/src/protocol/party-protocol-factory.js.map +1 -0
  145. package/dist/src/snapshots/snapshot-generator.d.ts +1 -1
  146. package/dist/src/snapshots/snapshot-generator.d.ts.map +1 -1
  147. package/dist/src/testing/testing-factories.js.map +1 -1
  148. package/dist/src/testing/testing.d.ts +2 -2
  149. package/dist/src/testing/testing.d.ts.map +1 -1
  150. package/dist/src/testing/testing.js +1 -7
  151. package/dist/src/testing/testing.js.map +1 -1
  152. package/dist/tsconfig.tsbuildinfo +1 -1
  153. package/package.json +17 -17
  154. package/src/echo.test.ts +8 -14
  155. package/src/echo.ts +107 -109
  156. package/src/halo/contact-manager.ts +9 -5
  157. package/src/halo/halo-factory.ts +82 -19
  158. package/src/halo/halo-party.ts +137 -21
  159. package/src/halo/halo.test.ts +198 -0
  160. package/src/halo/halo.ts +40 -38
  161. package/src/halo/identity-manager.ts +33 -28
  162. package/src/halo/identity.ts +19 -23
  163. package/src/halo/index.ts +1 -1
  164. package/src/halo/party-opener.ts +1 -1
  165. package/src/halo/preferences.ts +29 -18
  166. package/src/index.ts +1 -1
  167. package/src/invitations/greeting-initiator.ts +37 -32
  168. package/src/invitations/greeting-responder.ts +4 -5
  169. package/src/invitations/halo-recovery-initiator.ts +16 -24
  170. package/src/invitations/index.ts +1 -1
  171. package/src/invitations/{invitation-manager.ts → invitation-factory.ts} +8 -15
  172. package/src/invitations/offline-invitation-claimer.ts +3 -3
  173. package/src/parties/{party-internal.ts → data-party.ts} +30 -55
  174. package/src/parties/index.ts +1 -2
  175. package/src/parties/party-factory.ts +31 -21
  176. package/src/parties/party-manager.test.ts +99 -73
  177. package/src/parties/party-manager.ts +17 -17
  178. package/src/{halo → parties}/party-preferences.ts +3 -3
  179. package/src/pipeline/index.ts +3 -1
  180. package/src/{metadata → pipeline}/metadata-store.test.ts +0 -0
  181. package/src/{metadata → pipeline}/metadata-store.ts +0 -0
  182. package/src/{parties → pipeline}/party-core.test.ts +1 -2
  183. package/src/{parties → pipeline}/party-core.ts +12 -7
  184. package/src/pipeline/party-feed-provider.ts +32 -21
  185. package/src/protocol/auth-plugin.ts +14 -0
  186. package/src/protocol/authenticator.test.ts +66 -0
  187. package/src/protocol/authenticator.ts +56 -0
  188. package/src/protocol/credentials-signer.ts +60 -0
  189. package/src/protocol/halo-recovery-plugin.ts +20 -0
  190. package/src/protocol/index.ts +10 -0
  191. package/src/protocol/offline-invitation-plugin.ts +19 -0
  192. package/src/{pipeline → protocol}/party-protocol-factory.ts +10 -82
  193. package/src/snapshots/snapshot-generator.ts +1 -1
  194. package/src/testing/testing-factories.ts +2 -2
  195. package/src/testing/testing.ts +3 -9
  196. package/dist/src/halo/party-preferences.d.ts.map +0 -1
  197. package/dist/src/halo/party-preferences.js.map +0 -1
  198. package/dist/src/invitations/invitation-manager.d.ts.map +0 -1
  199. package/dist/src/invitations/invitation-manager.js.map +0 -1
  200. package/dist/src/metadata/index.d.ts +0 -2
  201. package/dist/src/metadata/index.d.ts.map +0 -1
  202. package/dist/src/metadata/index.js.map +0 -1
  203. package/dist/src/metadata/metadata-store.test.d.ts.map +0 -1
  204. package/dist/src/parties/authenticator.d.ts +0 -5
  205. package/dist/src/parties/authenticator.d.ts.map +0 -1
  206. package/dist/src/parties/authenticator.js +0 -27
  207. package/dist/src/parties/authenticator.js.map +0 -1
  208. package/dist/src/parties/party-core.d.ts.map +0 -1
  209. package/dist/src/parties/party-core.js.map +0 -1
  210. package/dist/src/parties/party-core.test.d.ts.map +0 -1
  211. package/dist/src/parties/party-core.test.js.map +0 -1
  212. package/dist/src/parties/party-internal.d.ts.map +0 -1
  213. package/dist/src/parties/party-internal.js.map +0 -1
  214. package/dist/src/pipeline/party-protocol-factory.d.ts.map +0 -1
  215. package/dist/src/pipeline/party-protocol-factory.js.map +0 -1
  216. package/src/metadata/index.ts +0 -5
  217. package/src/parties/authenticator.ts +0 -31
package/src/echo.ts CHANGED
@@ -9,7 +9,7 @@ import memdown from 'memdown';
9
9
  import { synchronized } from '@dxos/async';
10
10
  import { Keyring, KeyStore, SecretProvider } from '@dxos/credentials';
11
11
  import { PublicKey } from '@dxos/crypto';
12
- import { InvalidStateError } from '@dxos/debug';
12
+ import { InvalidStateError, raise } from '@dxos/debug';
13
13
  import { codec, DataService, PartyKey, PartySnapshot } from '@dxos/echo-protocol';
14
14
  import { FeedStore } from '@dxos/feed-store';
15
15
  import { ModelFactory } from '@dxos/model-factory';
@@ -20,13 +20,12 @@ import { SubscriptionGroup } from '@dxos/util';
20
20
 
21
21
  import { ResultSet } from './api';
22
22
  import { DataServiceRouter } from './database';
23
- import { InvalidStorageVersionError } from './errors';
23
+ import { IdentityNotInitializedError, InvalidStorageVersionError } from './errors';
24
24
  import { HALO } from './halo';
25
25
  import { autoPartyOpener } from './halo/party-opener';
26
26
  import { InvitationDescriptor, OfflineInvitationClaimer } from './invitations';
27
- import { MetadataStore, STORAGE_VERSION } from './metadata';
28
- import { OpenProgress, PartyFactory, PartyInternal, PartyManager } from './parties';
29
- import { PartyFeedProvider } from './pipeline';
27
+ import { OpenProgress, PartyFactory, DataParty, PartyManager } from './parties';
28
+ import { MetadataStore, STORAGE_VERSION, PartyFeedProvider } from './pipeline';
30
29
  import { SnapshotStore } from './snapshots';
31
30
  import { createRamStorage } from './util';
32
31
 
@@ -34,7 +33,7 @@ const log = debug('dxos:echo');
34
33
  const error = log.extend('error');
35
34
 
36
35
  // eslint-disable-next-line @typescript-eslint/no-empty-interface
37
- export interface PartyFilter {}
36
+ export interface PartyFilter { }
38
37
 
39
38
  /**
40
39
  * Various options passed to `ECHO.create`.
@@ -133,7 +132,7 @@ export class ECHO {
133
132
  this._keyring = new Keyring(new KeyStore(keyStorage));
134
133
  this._feedStore = new FeedStore(feedStorage, { valueEncoding: codec });
135
134
 
136
- const createFeedProvider = (partyKey: PublicKey) => new PartyFeedProvider(
135
+ const feedProviderFactory = (partyKey: PublicKey) => new PartyFeedProvider(
137
136
  this._metadataStore,
138
137
  this._keyring,
139
138
  this._feedStore,
@@ -153,7 +152,7 @@ export class ECHO {
153
152
  this._networkManager,
154
153
  this._modelFactory,
155
154
  this._snapshotStore,
156
- createFeedProvider,
155
+ feedProviderFactory,
157
156
  options
158
157
  );
159
158
 
@@ -164,18 +163,19 @@ export class ECHO {
164
163
  partyFactory
165
164
  );
166
165
 
167
- // TODO(burdon): Why does this need both PartyManager and PartyFactory?
168
166
  this._halo = new HALO({
169
167
  keyring: this._keyring,
170
- partyManager: this._partyManager,
171
- partyFactory,
172
168
  networkManager: this._networkManager,
173
- metadataStore: this._metadataStore
169
+ metadataStore: this._metadataStore,
170
+ feedProviderFactory: feedProviderFactory,
171
+ modelFactory: this._modelFactory,
172
+ snapshotStore: this._snapshotStore,
173
+ options
174
174
  });
175
175
 
176
176
  this._halo.identityReady.once(() => {
177
177
  // It might be the case that halo gets closed before this has a chance to execute.
178
- if (this.halo.identity.halo?.isOpen) {
178
+ if (this.halo.identity?.halo.isOpen) {
179
179
  this._subs.push(autoPartyOpener(this.halo.identity.preferences!, this._partyManager));
180
180
  }
181
181
  });
@@ -260,7 +260,7 @@ export class ECHO {
260
260
  /**
261
261
  * Closes the ECHO instance.
262
262
  */
263
- @synchronized
263
+ @synchronized
264
264
  async close () {
265
265
  if (!this.isOpen) {
266
266
  return;
@@ -268,10 +268,8 @@ export class ECHO {
268
268
 
269
269
  this._subs.unsubscribe();
270
270
 
271
- // TODO(marik-d): Should be `_identityManager.close()`.
272
271
  await this.halo.close();
273
272
 
274
- // TODO(marik-d): Close network manager.
275
273
  await this._partyManager.close();
276
274
 
277
275
  await this._feedStore.close();
@@ -279,107 +277,107 @@ export class ECHO {
279
277
  await this.networkManager.destroy();
280
278
  }
281
279
 
282
- /**
283
- * Removes all data and closes this ECHO instance.
284
- *
285
- * The instance will be in an unusable state at this point and a page refresh is recommended.
286
- */
287
- // TODO(burdon): Enable re-open.
288
- async reset () {
289
- await this.close();
290
-
291
- try {
292
- if (this._feedStore.storage.destroy) {
293
- await this._feedStore.storage.destroy();
294
- }
295
- } catch (err: any) {
296
- error('Error clearing feed storage:', err);
297
- }
298
-
299
- await this.halo.reset();
300
-
301
- try {
302
- await this._snapshotStore.clear();
303
- } catch (err: any) {
304
- error('Error clearing snapshot storage:', err);
305
- }
306
-
307
- try {
308
- await this._metadataStore.clear();
309
- } catch (err: any) {
310
- error('Error clearing metadata storage:', err);
311
- }
312
- }
313
-
314
- //
315
- // Parties.
316
- //
317
-
318
- /**
280
+ /**
281
+ * Removes all data and closes this ECHO instance.
282
+ *
283
+ * The instance will be in an unusable state at this point and a page refresh is recommended.
284
+ */
285
+ // TODO(burdon): Enable re-open.
286
+ async reset () {
287
+ await this.close();
288
+
289
+ try {
290
+ if (this._feedStore.storage.destroy) {
291
+ await this._feedStore.storage.destroy();
292
+ }
293
+ } catch (err: any) {
294
+ error('Error clearing feed storage:', err);
295
+ }
296
+
297
+ await this.halo.reset();
298
+
299
+ try {
300
+ await this._snapshotStore.clear();
301
+ } catch (err: any) {
302
+ error('Error clearing snapshot storage:', err);
303
+ }
304
+
305
+ try {
306
+ await this._metadataStore.clear();
307
+ } catch (err: any) {
308
+ error('Error clearing metadata storage:', err);
309
+ }
310
+ }
311
+
312
+ //
313
+ // Parties.
314
+ //
315
+
316
+ /**
319
317
  * Creates a new party.
320
318
  */
321
- async createParty (): Promise<PartyInternal> {
322
- await this.open();
319
+ async createParty (): Promise<DataParty> {
320
+ await this.open();
321
+
322
+ const party = await this._partyManager.createParty();
323
+ await party.open();
323
324
 
324
- const party = await this._partyManager.createParty();
325
- await party.open();
325
+ return party;
326
+ }
326
327
 
327
- return party;
328
- }
328
+ /**
329
+ * Clones an existing party from a snapshot.
330
+ * @param snapshot
331
+ */
332
+ async cloneParty (snapshot: PartySnapshot) {
333
+ await this.open();
329
334
 
330
- /**
331
- * Clones an existing party from a snapshot.
332
- * @param snapshot
333
- */
334
- async cloneParty (snapshot: PartySnapshot) {
335
- await this.open();
335
+ const party = await this._partyManager.cloneParty(snapshot);
336
+ await party.open();
336
337
 
337
- const party = await this._partyManager.cloneParty(snapshot);
338
- await party.open();
338
+ return party;
339
+ }
339
340
 
340
- return party;
341
- }
341
+ /**
342
+ * Returns an individual party by it's key.
343
+ * @param {PartyKey} partyKey
344
+ */
345
+ getParty (partyKey: PartyKey): DataParty | undefined {
346
+ if (!this._partyManager.isOpen) {
347
+ throw new InvalidStateError();
348
+ }
342
349
 
343
- /**
344
- * Returns an individual party by it's key.
345
- * @param {PartyKey} partyKey
346
- */
347
- getParty (partyKey: PartyKey): PartyInternal | undefined {
348
- if (!this._partyManager.isOpen) {
349
- throw new InvalidStateError();
350
- }
351
-
352
- const party = this._partyManager.parties.find(party => party.key.equals(partyKey));
353
- return party;
354
- }
355
-
356
- /**
357
- * Queries for a set of Parties matching the optional filter.
358
- * @param {PartyFilter} filter
359
- */
360
- // eslint-disable-next-line unused-imports/no-unused-vars
361
- queryParties (filter?: PartyFilter): ResultSet<PartyInternal> {
362
- if (!this._partyManager.isOpen) {
363
- throw new InvalidStateError();
364
- }
365
-
366
- return new ResultSet(
367
- this._partyManager.update.discardParameter(),
368
- () => this._partyManager.parties
369
- );
370
- }
371
-
372
- /**
373
- * Joins a party that was created by another peer and starts replicating with it.
374
- * @param invitationDescriptor Invitation descriptor passed from another peer.
375
- * @param secretProvider Shared secret provider, the other peer creating the invitation must have the same secret.
376
- */
377
- async joinParty (invitationDescriptor: InvitationDescriptor, secretProvider?: SecretProvider): Promise<PartyInternal> {
378
- assert(this._partyManager.isOpen, new InvalidStateError());
350
+ const party = this._partyManager.parties.find(party => party.key.equals(partyKey));
351
+ return party;
352
+ }
379
353
 
380
- const actualSecretProvider =
381
- secretProvider ?? OfflineInvitationClaimer.createSecretProvider(this.halo.identity);
354
+ /**
355
+ * Queries for a set of Parties matching the optional filter.
356
+ * @param {PartyFilter} filter
357
+ */
358
+ // eslint-disable-next-line unused-imports/no-unused-vars
359
+ queryParties (filter?: PartyFilter): ResultSet<DataParty> {
360
+ if (!this._partyManager.isOpen) {
361
+ throw new InvalidStateError();
362
+ }
363
+
364
+ return new ResultSet(
365
+ this._partyManager.update.discardParameter(),
366
+ () => this._partyManager.parties
367
+ );
368
+ }
382
369
 
383
- return this._partyManager.joinParty(invitationDescriptor, actualSecretProvider);
384
- }
370
+ /**
371
+ * Joins a party that was created by another peer and starts replicating with it.
372
+ * @param invitationDescriptor Invitation descriptor passed from another peer.
373
+ * @param secretProvider Shared secret provider, the other peer creating the invitation must have the same secret.
374
+ */
375
+ async joinParty (invitationDescriptor: InvitationDescriptor, secretProvider?: SecretProvider): Promise<DataParty> {
376
+ assert(this._partyManager.isOpen, new InvalidStateError());
377
+
378
+ const actualSecretProvider =
379
+ secretProvider ?? OfflineInvitationClaimer.createSecretProvider(this.halo.identity ?? raise(new IdentityNotInitializedError()));
380
+
381
+ return this._partyManager.joinParty(invitationDescriptor, actualSecretProvider);
382
+ }
385
383
  }
@@ -4,10 +4,12 @@
4
4
 
5
5
  import { Event } from '@dxos/async';
6
6
  import { PublicKey } from '@dxos/crypto';
7
+ import { raise } from '@dxos/debug';
7
8
  import { ObjectModel } from '@dxos/object-model';
8
9
 
9
- import { Item, ResultSet } from '../api';
10
- import { PartyInternal, PartyMember } from '../parties';
10
+ import { Database, Item, ResultSet } from '../api';
11
+ import { IdentityNotInitializedError } from '../errors';
12
+ import { PartyMember } from '../parties';
11
13
  import { HALO_PARTY_CONTACT_LIST_TYPE } from './halo-party';
12
14
 
13
15
  // TODO(burdon): Create different class (additional properties).
@@ -18,16 +20,18 @@ export type Contact = PartyMember;
18
20
  */
19
21
  export class ContactManager {
20
22
  constructor (
21
- private readonly _party: PartyInternal
23
+ private readonly _getDatabase: () => Database | undefined
22
24
  ) {}
23
25
 
24
26
  getContactListItem (): Item<ObjectModel> | undefined {
25
- return this._party.database.select({ type: HALO_PARTY_CONTACT_LIST_TYPE }).exec().entities[0];
27
+ const database = this._getDatabase() ?? raise(new IdentityNotInitializedError());
28
+ return database.select({ type: HALO_PARTY_CONTACT_LIST_TYPE }).exec().entities[0];
26
29
  }
27
30
 
28
31
  queryContacts (): ResultSet<Contact> {
32
+ const database = this._getDatabase() ?? raise(new IdentityNotInitializedError());
29
33
  const event = new Event();
30
- const result = this._party.database.select({ type: HALO_PARTY_CONTACT_LIST_TYPE }).exec();
34
+ const result = database.select({ type: HALO_PARTY_CONTACT_LIST_TYPE }).exec();
31
35
  result.update.on(() => {
32
36
  event.emit();
33
37
  });
@@ -13,18 +13,24 @@ import {
13
13
  Keyring,
14
14
  KeyType,
15
15
  Filter,
16
- SecretProvider
16
+ SecretProvider,
17
+ KeyHint,
18
+ createFeedAdmitMessage
17
19
  } from '@dxos/credentials';
18
20
  import { keyToString, PublicKey, keyPairFromSeedPhrase } from '@dxos/crypto';
21
+ import { ModelFactory } from '@dxos/model-factory';
19
22
  import { NetworkManager } from '@dxos/network-manager';
20
23
  import { ObjectModel } from '@dxos/object-model';
21
24
 
22
- import { HaloRecoveryInitiator, InvitationDescriptor } from '../invitations';
23
- import { PartyFactory, PartyInternal, PARTY_ITEM_TYPE } from '../parties';
25
+ import { createHaloPartyAdmissionMessage, GreetingInitiator, HaloRecoveryInitiator, InvitationDescriptor, InvitationDescriptorType, OfflineInvitationClaimer } from '../invitations';
26
+ import { PARTY_ITEM_TYPE } from '../parties';
27
+ import { PartyFeedProvider, PartyOptions } from '../pipeline';
28
+ import { CredentialsSigner } from '../protocol/credentials-signer';
29
+ import { SnapshotStore } from '../snapshots';
24
30
  import {
31
+ HaloParty,
25
32
  HALO_PARTY_CONTACT_LIST_TYPE, HALO_PARTY_DEVICE_PREFERENCES_TYPE, HALO_PARTY_PREFERENCES_TYPE
26
33
  } from './halo-party';
27
- import { Identity } from './identity';
28
34
 
29
35
  /**
30
36
  * Options allowed when creating the HALO.
@@ -41,16 +47,32 @@ const log = debug('dxos:echo-db:halo-factory');
41
47
  */
42
48
  export class HaloFactory {
43
49
  constructor (
44
- private readonly _partyFactory: PartyFactory,
45
50
  private readonly _networkManager: NetworkManager,
46
- private readonly _keyring: Keyring
51
+ private readonly _modelFactory: ModelFactory,
52
+ private readonly _snapshotStore: SnapshotStore,
53
+ private readonly _feedProviderFactory: (partyKey: PublicKey) => PartyFeedProvider,
54
+ private readonly _keyring: Keyring,
55
+ private readonly _options: PartyOptions = {}
47
56
  ) {}
48
57
 
49
- async constructParty (partyKey: PublicKey) {
50
- return this._partyFactory.constructParty(partyKey);
58
+ async constructParty (hints: KeyHint[]): Promise<HaloParty> {
59
+ const credentialsSigner = CredentialsSigner.createDirectDeviceSigner(this._keyring);
60
+ const feedProvider = this._feedProviderFactory(credentialsSigner.getIdentityKey().publicKey);
61
+ const halo = new HaloParty(
62
+ this._modelFactory,
63
+ this._snapshotStore,
64
+ feedProvider,
65
+ credentialsSigner,
66
+ this._networkManager,
67
+ hints,
68
+ undefined,
69
+ this._options
70
+ );
71
+
72
+ return halo;
51
73
  }
52
74
 
53
- async createHalo (options: HaloCreationOptions = {}): Promise<PartyInternal> {
75
+ async createHalo (options: HaloCreationOptions = {}): Promise<HaloParty> {
54
76
  // Don't use `identityManager.identityKey`, because that doesn't check for the secretKey.
55
77
  const identityKey = this._keyring.findKey(Keyring.signingFilter({ type: KeyType.IDENTITY }));
56
78
  assert(identityKey, 'Identity key required.');
@@ -59,8 +81,10 @@ export class HaloFactory {
59
81
  await this._keyring.createKeyRecord({ type: KeyType.DEVICE });
60
82
 
61
83
  // 1. Create a feed for the HALO.
62
- const halo = await this._partyFactory.constructParty(identityKey.publicKey);
63
- const { feed } = await halo.feedProvider.createOrOpenWritableFeed();
84
+ const halo = await this.constructParty([]);
85
+ const feedKey = await halo.getWriteFeedKey();
86
+ const feedKeyPair = this._keyring.getKey(feedKey);
87
+ assert(feedKeyPair);
64
88
 
65
89
  // Connect the pipeline.
66
90
  await halo.open();
@@ -70,8 +94,6 @@ export class HaloFactory {
70
94
  * B. Device key (the first "member" of the Identity's HALO).
71
95
  * C. Feed key (the feed owned by the Device).
72
96
  */
73
- const feedKeyPair = this._keyring.getKey(feed.key);
74
- assert(feedKeyPair);
75
97
  await halo.processor.writeHaloMessage(createPartyGenesisMessage(this._keyring, identityKey, feedKeyPair.publicKey, deviceKey));
76
98
 
77
99
  /* 3. Make a special self-signed KeyAdmit message which will serve as an "IdentityGenesis" message. This
@@ -105,15 +127,16 @@ export class HaloFactory {
105
127
  return halo;
106
128
  }
107
129
 
108
- async recoverHalo (identity: Identity, seedPhrase: string) {
130
+ async recoverHalo (seedPhrase: string) {
109
131
  const recoveredKeyPair = keyPairFromSeedPhrase(seedPhrase);
110
132
  await this._keyring.addKeyRecord({
111
133
  publicKey: PublicKey.from(recoveredKeyPair.publicKey),
112
134
  secretKey: recoveredKeyPair.secretKey,
113
135
  type: KeyType.IDENTITY
114
136
  });
137
+ await this._keyring.createKeyRecord({ type: KeyType.DEVICE });
115
138
 
116
- const recoverer = new HaloRecoveryInitiator(this._networkManager, identity);
139
+ const recoverer = new HaloRecoveryInitiator(this._networkManager, CredentialsSigner.createDirectDeviceSigner(this._keyring));
117
140
  await recoverer.connect();
118
141
 
119
142
  const invitationDescriptor = await recoverer.claim();
@@ -122,7 +145,7 @@ export class HaloFactory {
122
145
  }
123
146
 
124
147
  async joinHalo (invitationDescriptor: InvitationDescriptor, secretProvider: SecretProvider) {
125
- assert(!this._keyring.findKey(Filter.matches({ type: KeyType.PARTY })), 'Identity key must NOT exist.');
148
+ assert(!this._keyring.findKey(Filter.matches({ type: KeyType.IDENTITY })), 'Identity key must not exist.');
126
149
 
127
150
  return this._joinHalo(invitationDescriptor, secretProvider);
128
151
  }
@@ -131,9 +154,9 @@ export class HaloFactory {
131
154
  log(`Admitting device with invitation: ${keyToString(invitationDescriptor.invitation)}`);
132
155
  assert(invitationDescriptor.identityKey);
133
156
 
134
- const identityKey = this._keyring.findKey(Keyring.signingFilter({ type: KeyType.IDENTITY }));
157
+ let identityKey = this._keyring.findKey(Keyring.signingFilter({ type: KeyType.IDENTITY }));
135
158
  if (!identityKey) {
136
- await this._keyring.addPublicKey({
159
+ identityKey = await this._keyring.addPublicKey({
137
160
  type: KeyType.IDENTITY,
138
161
  publicKey: invitationDescriptor.identityKey,
139
162
  own: true,
@@ -143,11 +166,51 @@ export class HaloFactory {
143
166
  assert(identityKey.publicKey.equals(invitationDescriptor.identityKey),
144
167
  'Identity key must match invitation');
145
168
  }
169
+ assert(identityKey);
146
170
 
147
171
  const deviceKey = this._keyring.findKey(Keyring.signingFilter({ type: KeyType.DEVICE })) ??
148
172
  await this._keyring.createKeyRecord({ type: KeyType.DEVICE });
149
173
 
150
- const halo = await this._partyFactory.joinParty(invitationDescriptor, secretProvider);
174
+ const originalInvitation = invitationDescriptor;
175
+
176
+ const credentialsSigner = CredentialsSigner.createDirectDeviceSigner(this._keyring);
177
+ // Claim the offline invitation and convert it into an interactive invitation.
178
+ if (invitationDescriptor.type === InvitationDescriptorType.OFFLINE) {
179
+ const invitationClaimer = new OfflineInvitationClaimer(this._networkManager, invitationDescriptor);
180
+ await invitationClaimer.connect();
181
+ invitationDescriptor = await invitationClaimer.claim();
182
+ log(`Party invitation triggered interactive Greeting at: ${JSON.stringify({ original: originalInvitation.invitation, interactive: invitationDescriptor.invitation })}`);
183
+ await invitationClaimer.destroy();
184
+ }
185
+
186
+ const initiator = new GreetingInitiator(
187
+ this._networkManager,
188
+ invitationDescriptor,
189
+ async (partyKey, nonce) => {
190
+ assert(partyKey.equals(identityKey!.publicKey));
191
+ return [createHaloPartyAdmissionMessage(credentialsSigner, nonce)];
192
+ }
193
+ );
194
+
195
+ await initiator.connect();
196
+ const { partyKey, hints } = await initiator.redeemInvitation(secretProvider);
197
+
198
+ /*
199
+ * TODO(telackey): We shouldn't have to add our key here, it should be in the hints, but our hint
200
+ * mechanism is broken by not waiting on the messages to be processed before returning.
201
+ */
202
+ const halo = await this.constructParty(hints);
203
+ await halo.open();
204
+
205
+ // Write the Feed genesis message.
206
+ await halo.processor.writeHaloMessage(createFeedAdmitMessage(
207
+ credentialsSigner.signer,
208
+ partyKey,
209
+ await halo.getWriteFeedKey(),
210
+ [credentialsSigner.getDeviceKey()]
211
+ ));
212
+ await initiator.destroy();
213
+
151
214
  await halo.database.createItem({
152
215
  model: ObjectModel,
153
216
  type: HALO_PARTY_DEVICE_PREFERENCES_TYPE,