@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.
@@ -1 +1 @@
1
- {"version":3,"file":"mapeo-manager.d.ts","sourceRoot":"","sources":["../src/mapeo-manager.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mapeo-manager.d.ts","sourceRoot":"","sources":["../src/mapeo-manager.js"],"names":[],"mappings":"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"}
@@ -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): Promise<void>;
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;;;OAGG;IACH,kBAHW,QAAQ,GACN,OAAO,CAAC,IAAI,CAAC,CAazB;oFAPa,2BACE;IApChB;;OAEG;IACH,2BAGC;IAED;;OAEG;IACH,kCAGC;IA8BD;;;;OAIG;IACH,wCAJW,MAAM,eACN,WAAW,GACT,OAAO,CAAC,IAAI,CAAC,CA6BzB;IApWC,wBAME;;CA6eL;uBA5lBY,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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comapeo/core",
3
- "version": "5.1.3",
3
+ "version": "5.1.5",
4
4
  "description": "Offline p2p mapping library",
5
5
  "main": "src/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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 for an active project
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 this.#waitForInitialSync(project)
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 this.#waitForInitialSync(project)
1003
+ await project.$sync.waitForSync('initial', {
1004
+ timeoutMs: INITIAL_SYNC_TIMEOUT_MS,
1005
+ })
1075
1006
  }
1076
1007
 
1077
1008
  async getMapStyleJsonUrl() {
@@ -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
- const state = this[kSyncState].getState()
448
- if (isSynced(state, type, this.#peerSyncControllers)) return
449
- return new Promise((res) => {
450
- const _this = this
451
- this[kSyncState].on('state', function onState(state) {
452
- if (!isSynced(state, type, _this.#peerSyncControllers)) return
453
- _this[kSyncState].off('state', onState)
454
- res()
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