@comapeo/core 5.1.3 → 5.1.5
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.
- package/dist/mapeo-manager.d.ts.map +1 -1
- package/dist/sync/sync-api.d.ts +8 -1
- package/dist/sync/sync-api.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/mapeo-manager.js +21 -90
- package/src/sync/sync-api.js +26 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mapeo-manager.d.ts","sourceRoot":"","sources":["../src/mapeo-manager.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mapeo-manager.d.ts","sourceRoot":"","sources":["../src/mapeo-manager.js"],"names":[],"mappings":"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"}
|
package/dist/sync/sync-api.d.ts
CHANGED
|
@@ -112,9 +112,16 @@ export class SyncApi extends TypedEmitter<SyncEvents> {
|
|
|
112
112
|
setAutostopDataSyncTimeout(autostopDataSyncAfter: null | number): void;
|
|
113
113
|
/**
|
|
114
114
|
* @param {SyncType} type
|
|
115
|
+
* @param {object} [options]
|
|
116
|
+
* @param {number} [options.timeoutMs] Timeout in milliseconds for max time
|
|
117
|
+
* to wait between sync state updates before giving up. As long as syncing is
|
|
118
|
+
* happening, this will never timeout, but if more than timeoutMs passes
|
|
119
|
+
* without any sync activity, then this will reject.
|
|
115
120
|
* @returns {Promise<void>}
|
|
116
121
|
*/
|
|
117
|
-
waitForSync(type: SyncType
|
|
122
|
+
waitForSync(type: SyncType, { timeoutMs }?: {
|
|
123
|
+
timeoutMs?: number | undefined;
|
|
124
|
+
} | undefined): Promise<void>;
|
|
118
125
|
[kHandleDiscoveryKey](discoveryKey: Buffer, protomux: import("protomux")<import("@hyperswarm/secret-stream")>): void;
|
|
119
126
|
/**
|
|
120
127
|
* Request a graceful stop to all sync.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-api.d.ts","sourceRoot":"","sources":["../../src/sync/sync-api.js"],"names":[],"mappings":"AAcA,2EAA2E;AAC3E,yCAAyC;AACzC,4DAA4D;AAC5D,iFAAiF;AACjF,mEAAmE;AAEnE,gDAAiE;AACjE,uCAA8C;AAC9C,6CAAoD;AACpD,oDAA2D;AAC3D,wDAEC;AAED;;GAEG;AAEH;;GAEG;AAEH;;;;;;;GAOG;AAEH;;;;;;GAMG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;GAGG;AAEH;;GAEG;AACH;IA4BE;;;;;;;;;;;OAWG;IACH,gJAVG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC1B,aAAa,EAAjC,aAAa;QACqB,KAAK,EAAvC,OAAO,aAAa,EAAE,KAAK;QACO,aAAa,UAAzC,MAAM,KAAK,SAAS;QACY,sBAAsB,EAA5D,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACD,oBAAoB,EAAlD,MAAM,iBAAiB;QAC0B,SAAS,EAA1D,OAAO,wBAAwB,EAAE,SAAS;QAC5B,UAAU;QACV,MAAM;KAAC,EAkD/B;IA8BD;;;OAGG;IACH,YAFa,KAAK,CAIjB;IAqHD;;OAEG;IACH,kBAFa,IAAI,CAsDhB;IAED;;OAEG;IACH,qBAFa,IAAI,CAQhB;IAED;;;;;;;;;;OAUG;IACH;;yBAOC;IAED;;;;OAIG;IACH,aAGC;IAkBD;;;OAGG;IACH,kDAHW,IAAI,GAAG,MAAM,GACX,IAAI,CAOhB;IAED
|
|
1
|
+
{"version":3,"file":"sync-api.d.ts","sourceRoot":"","sources":["../../src/sync/sync-api.js"],"names":[],"mappings":"AAcA,2EAA2E;AAC3E,yCAAyC;AACzC,4DAA4D;AAC5D,iFAAiF;AACjF,mEAAmE;AAEnE,gDAAiE;AACjE,uCAA8C;AAC9C,6CAAoD;AACpD,oDAA2D;AAC3D,wDAEC;AAED;;GAEG;AAEH;;GAEG;AAEH;;;;;;;GAOG;AAEH;;;;;;GAMG;AAEH;;;;;GAKG;AAEH;;;;;GAKG;AAEH;;;GAGG;AAEH;;GAEG;AACH;IA4BE;;;;;;;;;;;OAWG;IACH,gJAVG;QAA6D,WAAW,EAAhE,OAAO,0BAA0B,EAAE,WAAW;QAC1B,aAAa,EAAjC,aAAa;QACqB,KAAK,EAAvC,OAAO,aAAa,EAAE,KAAK;QACO,aAAa,UAAzC,MAAM,KAAK,SAAS;QACY,sBAAsB,EAA5D,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACD,oBAAoB,EAAlD,MAAM,iBAAiB;QAC0B,SAAS,EAA1D,OAAO,wBAAwB,EAAE,SAAS;QAC5B,UAAU;QACV,MAAM;KAAC,EAkD/B;IA8BD;;;OAGG;IACH,YAFa,KAAK,CAIjB;IAqHD;;OAEG;IACH,kBAFa,IAAI,CAsDhB;IAED;;OAEG;IACH,qBAFa,IAAI,CAQhB;IAED;;;;;;;;;;OAUG;IACH;;yBAOC;IAED;;;;OAIG;IACH,aAGC;IAkBD;;;OAGG;IACH,kDAHW,IAAI,GAAG,MAAM,GACX,IAAI,CAOhB;IAED;;;;;;;;OAQG;IACH,kBARW,QAAQ;;oBAMN,OAAO,CAAC,IAAI,CAAC,CAwBzB;oFA1BiC,2BAA2B;IAhC7D;;OAEG;IACH,2BAGC;IAED;;OAEG;IACH,kCAGC;IA8CD;;;;OAIG;IACH,wCAJW,MAAM,eACN,WAAW,GACT,OAAO,CAAC,IAAI,CAAC,CA6BzB;IApXC,wBAME;;CA6fL;uBA5mBY,SAAS,GAAG,MAAM;+BAIlB,MAAM,GAAG,SAAS,GAAG,KAAK;;WAMzB,MAAM;YACN,MAAM;gBACN,MAAM;YACN,MAAM;;;;;;mBAMN,OAAO;;;;UACP,MAAM;;;;YACN,MAAM;;;;;;;;;aAMN,mCAAmC;;;;UACnC,mCAAmC;;;;;;aAKnC;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE;;;;UAC1B;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE;;;;2BAC1B,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC;;;kBAKrC,CAAC,SAAS,EAAE,KAAK,KAAK,IAAI;;6BArEX,oBAAoB;0BAEvB,iBAAiB;mCAcR,sBAAsB;sBAfnC,IAAI;uCAiByB,aAAa;uBAdzC,cAAc"}
|
package/package.json
CHANGED
package/src/mapeo-manager.js
CHANGED
|
@@ -47,13 +47,8 @@ import { getFastifyServerAddress } from './fastify-plugins/utils.js'
|
|
|
47
47
|
import { LocalPeers } from './local-peers.js'
|
|
48
48
|
import { InviteApi } from './invite/invite-api.js'
|
|
49
49
|
import { LocalDiscovery } from './discovery/local-discovery.js'
|
|
50
|
-
import { Roles } from './roles.js'
|
|
51
50
|
import { Logger } from './logger.js'
|
|
52
|
-
import {
|
|
53
|
-
kSyncState,
|
|
54
|
-
kRequestFullStop,
|
|
55
|
-
kRescindFullStopRequest,
|
|
56
|
-
} from './sync/sync-api.js'
|
|
51
|
+
import { kRequestFullStop, kRescindFullStopRequest } from './sync/sync-api.js'
|
|
57
52
|
import { NotFoundError } from './errors.js'
|
|
58
53
|
import { WebSocket } from 'ws'
|
|
59
54
|
import { excludeKeys } from 'filter-obj'
|
|
@@ -79,6 +74,9 @@ const CLIENT_SQLITE_FILE_NAME = 'client.db'
|
|
|
79
74
|
// other things e.g. SQLite and other parts of the app.
|
|
80
75
|
const MAX_FILE_DESCRIPTORS = 768
|
|
81
76
|
|
|
77
|
+
// This is the timeout for waiting for sync state updates during initial sync (when adding a project or leaving a project)
|
|
78
|
+
const INITIAL_SYNC_TIMEOUT_MS = 45_000 // 45 seconds
|
|
79
|
+
|
|
82
80
|
// Prefix names for routes registered with http server
|
|
83
81
|
const BLOBS_PREFIX = 'blobs'
|
|
84
82
|
const ICONS_PREFIX = 'icons'
|
|
@@ -679,14 +677,7 @@ export class MapeoManager extends TypedEmitter {
|
|
|
679
677
|
) => {
|
|
680
678
|
const projectPublicId = projectKeyToPublicId(projectKey)
|
|
681
679
|
|
|
682
|
-
// 1. Check
|
|
683
|
-
const activeProject = this.#activeProjects.get(projectPublicId)
|
|
684
|
-
|
|
685
|
-
if (activeProject) {
|
|
686
|
-
throw new Error(`Project with ID ${projectPublicId} already exists`)
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
// 2. Check if the project exists in the project keys table
|
|
680
|
+
// 1. Check if the project exists in the project keys table
|
|
690
681
|
// If it does, that means the project has already been either created or added before
|
|
691
682
|
const projectId = projectKeyToId(projectKey)
|
|
692
683
|
const projectInviteId = projectKeyToProjectInviteId(projectKey)
|
|
@@ -706,6 +697,16 @@ export class MapeoManager extends TypedEmitter {
|
|
|
706
697
|
throw new Error(`Project with ID ${projectPublicId} already exists`)
|
|
707
698
|
}
|
|
708
699
|
|
|
700
|
+
// 2. Check for an active project
|
|
701
|
+
const activeProject = this.#activeProjects.get(projectPublicId)
|
|
702
|
+
|
|
703
|
+
// If the project keys don't exist or have left and we have an active project
|
|
704
|
+
// It means we must have left the project and it's still loaded in memory but cleared
|
|
705
|
+
// We should close it so we can open a fresh copy
|
|
706
|
+
if (activeProject) {
|
|
707
|
+
await activeProject.close()
|
|
708
|
+
}
|
|
709
|
+
|
|
709
710
|
// No awaits here - need to update table in same tick as the projectExists check
|
|
710
711
|
|
|
711
712
|
// 3. Update the project keys table
|
|
@@ -764,7 +765,9 @@ export class MapeoManager extends TypedEmitter {
|
|
|
764
765
|
// 5. Wait for initial project sync
|
|
765
766
|
if (waitForSync) {
|
|
766
767
|
try {
|
|
767
|
-
await
|
|
768
|
+
await project.$sync.waitForSync('initial', {
|
|
769
|
+
timeoutMs: INITIAL_SYNC_TIMEOUT_MS,
|
|
770
|
+
})
|
|
768
771
|
} catch (e) {
|
|
769
772
|
this.#l.log('ERROR: could not do initial project sync', e)
|
|
770
773
|
}
|
|
@@ -773,80 +776,6 @@ export class MapeoManager extends TypedEmitter {
|
|
|
773
776
|
return projectPublicId
|
|
774
777
|
}
|
|
775
778
|
|
|
776
|
-
/**
|
|
777
|
-
* Sync initial data: the `auth` cores which contain the role messages,
|
|
778
|
-
* and the `config` cores which contain the project name & custom config (if
|
|
779
|
-
* it exists). The API consumer should await this after `client.addProject()`
|
|
780
|
-
* to ensure that the device is fully added to the project.
|
|
781
|
-
*
|
|
782
|
-
* @param {MapeoProject} project
|
|
783
|
-
* @param {object} [opts]
|
|
784
|
-
* @param {number} [opts.timeoutMs=45_000] Timeout in milliseconds for max time
|
|
785
|
-
* to wait between sync status updates before giving up. As long as syncing is
|
|
786
|
-
* happening, this will never timeout, but if more than timeoutMs passes
|
|
787
|
-
* without any sync activity, then this will resolve `false` e.g. data has not
|
|
788
|
-
* synced
|
|
789
|
-
* @returns {Promise<boolean>}
|
|
790
|
-
*/
|
|
791
|
-
async #waitForInitialSync(project, { timeoutMs = 45_000 } = {}) {
|
|
792
|
-
const [ownRole, isProjectSettingsSynced] = await Promise.all([
|
|
793
|
-
project.$getOwnRole(),
|
|
794
|
-
project.$hasSyncedProjectSettings(),
|
|
795
|
-
])
|
|
796
|
-
const {
|
|
797
|
-
auth: { localState: authState },
|
|
798
|
-
config: { localState: configState },
|
|
799
|
-
} = project.$sync[kSyncState].getState()
|
|
800
|
-
const isRoleSynced = ownRole !== Roles.NO_ROLE
|
|
801
|
-
// Assumes every project that someone is invited to has at least one record
|
|
802
|
-
// in the auth store - the row record for the invited device
|
|
803
|
-
const isAuthSynced = authState.want === 0 && authState.have > 0
|
|
804
|
-
// Assumes every project that someone is invited to has at least one record
|
|
805
|
-
// in the config store - defining the name of the project.
|
|
806
|
-
// TODO: Enforce adding a project name in the invite method
|
|
807
|
-
const isConfigSynced = configState.want === 0 && configState.have > 0
|
|
808
|
-
if (isRoleSynced && ownRole.sync.config === 'blocked' && isAuthSynced) {
|
|
809
|
-
return true
|
|
810
|
-
}
|
|
811
|
-
if (
|
|
812
|
-
isRoleSynced &&
|
|
813
|
-
isProjectSettingsSynced &&
|
|
814
|
-
isAuthSynced &&
|
|
815
|
-
isConfigSynced
|
|
816
|
-
) {
|
|
817
|
-
return true
|
|
818
|
-
} else {
|
|
819
|
-
this.#l.log(
|
|
820
|
-
'Pending initial sync: role %s, projectSettings %o, auth %o, config %o',
|
|
821
|
-
isRoleSynced,
|
|
822
|
-
isProjectSettingsSynced,
|
|
823
|
-
isAuthSynced,
|
|
824
|
-
isConfigSynced
|
|
825
|
-
)
|
|
826
|
-
}
|
|
827
|
-
return new Promise((resolve, reject) => {
|
|
828
|
-
/** @param {import('./sync/sync-state.js').State} syncState */
|
|
829
|
-
const onSyncState = (syncState) => {
|
|
830
|
-
clearTimeout(timeoutId)
|
|
831
|
-
if (
|
|
832
|
-
syncState.auth.dataToSync ||
|
|
833
|
-
(syncState.config.dataToSync && ownRole.sync.config === 'allowed')
|
|
834
|
-
) {
|
|
835
|
-
timeoutId = setTimeout(onTimeout, timeoutMs)
|
|
836
|
-
return
|
|
837
|
-
}
|
|
838
|
-
project.$sync[kSyncState].off('state', onSyncState)
|
|
839
|
-
this.#waitForInitialSync(project, { timeoutMs }).then(resolve, reject)
|
|
840
|
-
}
|
|
841
|
-
const onTimeout = () => {
|
|
842
|
-
project.$sync[kSyncState].off('state', onSyncState)
|
|
843
|
-
reject(new Error('Sync timeout'))
|
|
844
|
-
}
|
|
845
|
-
let timeoutId = setTimeout(onTimeout, timeoutMs)
|
|
846
|
-
project.$sync[kSyncState].on('state', onSyncState)
|
|
847
|
-
})
|
|
848
|
-
}
|
|
849
|
-
|
|
850
779
|
/**
|
|
851
780
|
* @typedef {import('./schema/client.js').DeviceInfoParam['deviceType']} RPCDeviceType
|
|
852
781
|
*/
|
|
@@ -1071,7 +1000,9 @@ export class MapeoManager extends TypedEmitter {
|
|
|
1071
1000
|
await project[kProjectLeave]()
|
|
1072
1001
|
|
|
1073
1002
|
// Sync any role changes from project leave
|
|
1074
|
-
await
|
|
1003
|
+
await project.$sync.waitForSync('initial', {
|
|
1004
|
+
timeoutMs: INITIAL_SYNC_TIMEOUT_MS,
|
|
1005
|
+
})
|
|
1075
1006
|
}
|
|
1076
1007
|
|
|
1077
1008
|
async getMapStyleJsonUrl() {
|
package/src/sync/sync-api.js
CHANGED
|
@@ -441,18 +441,34 @@ export class SyncApi extends TypedEmitter {
|
|
|
441
441
|
|
|
442
442
|
/**
|
|
443
443
|
* @param {SyncType} type
|
|
444
|
+
* @param {object} [options]
|
|
445
|
+
* @param {number} [options.timeoutMs] Timeout in milliseconds for max time
|
|
446
|
+
* to wait between sync state updates before giving up. As long as syncing is
|
|
447
|
+
* happening, this will never timeout, but if more than timeoutMs passes
|
|
448
|
+
* without any sync activity, then this will reject.
|
|
444
449
|
* @returns {Promise<void>}
|
|
445
450
|
*/
|
|
446
|
-
async waitForSync(type) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
const
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
451
|
+
async waitForSync(type, { timeoutMs } = {}) {
|
|
452
|
+
return new Promise((resolve, reject) => {
|
|
453
|
+
/** @type {NodeJS.Timeout | undefined} */
|
|
454
|
+
let timeoutId
|
|
455
|
+
const onTimeout = () => {
|
|
456
|
+
this[kSyncState].off('state', onState)
|
|
457
|
+
reject(new Error('Sync timeout'))
|
|
458
|
+
}
|
|
459
|
+
/** @param {import('./sync-state.js').State} state */
|
|
460
|
+
const onState = (state) => {
|
|
461
|
+
clearTimeout(timeoutId)
|
|
462
|
+
if (typeof timeoutMs === 'number') {
|
|
463
|
+
timeoutId = setTimeout(onTimeout, timeoutMs)
|
|
464
|
+
}
|
|
465
|
+
if (isSynced(state, type, this.#peerSyncControllers)) {
|
|
466
|
+
this[kSyncState].off('state', onState)
|
|
467
|
+
resolve()
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
this[kSyncState].on('state', onState)
|
|
471
|
+
onState(this[kSyncState].getState())
|
|
456
472
|
})
|
|
457
473
|
}
|
|
458
474
|
|