@@ -47,7 +47,11 @@ import {
4747import { migrate } from './lib/drizzle-helpers.js'
4848import { omit } from './lib/omit.js'
4949import { MemberApi } from './member-api.js'
50- import { SyncApi , kHandleDiscoveryKey } from './sync/sync-api.js'
50+ import {
51+ SyncApi ,
52+ kHandleDiscoveryKey ,
53+ kWaitForInitialSyncWithPeer ,
54+ } from './sync/sync-api.js'
5155import { Logger } from './logger.js'
5256import { IconApi } from './icon-api.js'
5357import { readConfig } from './config-import.js'
@@ -77,8 +81,9 @@ const EMPTY_PROJECT_SETTINGS = Object.freeze({})
7781 * @extends {TypedEmitter<{ close: () => void }> }
7882 */
7983export class MapeoProject extends TypedEmitter {
80- #projectId
84+ #projectKey
8185 #deviceId
86+ #identityKeypair
8287 #coreManager
8388 #indexWriter
8489 #dataStores
@@ -135,10 +140,12 @@ export class MapeoProject extends TypedEmitter {
135140
136141 this . #l = Logger . create ( 'project' , logger )
137142 this . #deviceId = getDeviceId ( keyManager )
138- this . #projectId = projectKeyToId ( projectKey )
143+ this . #projectKey = projectKey
139144 this . #loadingConfig = false
140145 this . #isArchiveDevice = isArchiveDevice
141146
147+ const getReplicationStream = this [ kProjectReplicate ] . bind ( this , true )
148+
142149 ///////// 1. Setup database
143150
144151 this . #sqlite = new Database ( dbPath )
@@ -317,7 +324,7 @@ export class MapeoProject extends TypedEmitter {
317324 } ,
318325 } ) ,
319326 }
320- const identityKeypair = keyManager . getIdentityKeypair ( )
327+ this . # identityKeypair = keyManager . getIdentityKeypair ( )
321328 const coreKeypairs = getCoreKeypairs ( {
322329 projectKey,
323330 projectSecretKey,
@@ -326,31 +333,33 @@ export class MapeoProject extends TypedEmitter {
326333 this . #coreOwnership = new CoreOwnership ( {
327334 dataType : this . #dataTypes. coreOwnership ,
328335 coreKeypairs,
329- identityKeypair,
336+ identityKeypair : this . #identityKeypair ,
330337 } )
331338 this . #roles = new Roles ( {
332339 dataType : this . #dataTypes. role ,
333340 coreOwnership : this . #coreOwnership,
334341 coreManager : this . #coreManager,
335342 projectKey : projectKey ,
336- deviceKey : keyManager . getIdentityKeypair ( ) . publicKey ,
343+ deviceKey : this . #identityKeypair . publicKey ,
337344 } )
338345
339346 this . #memberApi = new MemberApi ( {
340347 deviceId : this . #deviceId,
341348 roles : this . #roles,
342349 coreOwnership : this . #coreOwnership,
343350 encryptionKeys,
351+ getProjectName : this . #getProjectName. bind ( this ) ,
344352 projectKey,
345353 rpc : localPeers ,
354+ getReplicationStream,
355+ waitForInitialSyncWithPeer : ( deviceId , abortSignal ) =>
356+ this . $sync [ kWaitForInitialSyncWithPeer ] ( deviceId , abortSignal ) ,
346357 dataTypes : {
347358 deviceInfo : this . #dataTypes. deviceInfo ,
348359 project : this . #dataTypes. projectSettings ,
349360 } ,
350361 } )
351362
352- const projectPublicId = projectKeyToPublicId ( projectKey )
353-
354363 this . #blobStore = new BlobStore ( {
355364 coreManager : this . #coreManager,
356365 } )
@@ -362,7 +371,7 @@ export class MapeoProject extends TypedEmitter {
362371 if ( ! base . endsWith ( '/' ) ) {
363372 base += '/'
364373 }
365- return base + projectPublicId
374+ return base + this . # projectPublicId
366375 } ,
367376 } )
368377
@@ -374,7 +383,7 @@ export class MapeoProject extends TypedEmitter {
374383 if ( ! base . endsWith ( '/' ) ) {
375384 base += '/'
376385 }
377- return base + projectPublicId
386+ return base + this . # projectPublicId
378387 } ,
379388 } )
380389
@@ -384,6 +393,24 @@ export class MapeoProject extends TypedEmitter {
384393 roles : this . #roles,
385394 blobDownloadFilter : null ,
386395 logger : this . #l,
396+ getServerWebsocketUrls : async ( ) => {
397+ const members = await this . #memberApi. getMany ( )
398+ /** @type {string[] } */
399+ const serverWebsocketUrls = [ ]
400+ for ( const member of members ) {
401+ if (
402+ member . deviceType === 'selfHostedServer' &&
403+ member . selfHostedServerDetails
404+ ) {
405+ const { baseUrl } = member . selfHostedServerDetails
406+ const wsUrl = new URL ( `/sync/${ this . #projectPublicId} ` , baseUrl )
407+ wsUrl . protocol = wsUrl . protocol === 'http:' ? 'ws:' : 'wss:'
408+ serverWebsocketUrls . push ( wsUrl . href )
409+ }
410+ }
411+ return serverWebsocketUrls
412+ } ,
413+ getReplicationStream,
387414 } )
388415
389416 this . #translationApi = new TranslationApi ( {
@@ -458,6 +485,14 @@ export class MapeoProject extends TypedEmitter {
458485 return this . #deviceId
459486 }
460487
488+ get #projectId( ) {
489+ return projectKeyToId ( this . #projectKey)
490+ }
491+
492+ get #projectPublicId( ) {
493+ return projectKeyToPublicId ( this . #projectKey)
494+ }
495+
461496 /**
462497 * Resolves when hypercores have all loaded
463498 *
@@ -603,6 +638,13 @@ export class MapeoProject extends TypedEmitter {
603638 }
604639 }
605640
641+ /**
642+ * @returns {Promise<undefined | string> }
643+ */
644+ async #getProjectName( ) {
645+ return ( await this . $getProjectSettings ( ) ) . name
646+ }
647+
606648 async $getOwnRole ( ) {
607649 return this . #roles. getRole ( this . #deviceId)
608650 }
@@ -640,6 +682,7 @@ export class MapeoProject extends TypedEmitter {
640682 * Hypercore types need updating.
641683 * @type {any }
642684 */ ( {
685+ keyPair : this . #identityKeypair,
643686 /** @param {Buffer } discoveryKey */
644687 ondiscoverykey : async ( discoveryKey ) => {
645688 const protomux =
0 commit comments