@comapeo/core 6.0.2 → 7.0.1

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 (43) hide show
  1. package/dist/blob-store/downloader.d.ts +4 -9
  2. package/dist/blob-store/downloader.d.ts.map +1 -1
  3. package/dist/blob-store/hyperdrive-index.d.ts +4 -5
  4. package/dist/blob-store/hyperdrive-index.d.ts.map +1 -1
  5. package/dist/blob-store/index.d.ts +4 -5
  6. package/dist/blob-store/index.d.ts.map +1 -1
  7. package/dist/core-manager/index.d.ts +4 -23
  8. package/dist/core-manager/index.d.ts.map +1 -1
  9. package/dist/datastore/index.d.ts +1 -1
  10. package/dist/generated/extensions.d.ts +0 -30
  11. package/dist/generated/extensions.d.ts.map +1 -1
  12. package/dist/generated/rpc.d.ts +30 -0
  13. package/dist/generated/rpc.d.ts.map +1 -1
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/local-peers.d.ts +12 -0
  17. package/dist/local-peers.d.ts.map +1 -1
  18. package/dist/mapeo-manager.d.ts +41 -3
  19. package/dist/mapeo-manager.d.ts.map +1 -1
  20. package/dist/mapeo-project.d.ts +3 -76
  21. package/dist/mapeo-project.d.ts.map +1 -1
  22. package/dist/schema/project.d.ts +1 -1
  23. package/dist/sync/namespace-sync-state.d.ts +1 -1
  24. package/dist/sync/peer-sync-controller.d.ts +1 -1
  25. package/dist/sync/sync-api.d.ts.map +1 -1
  26. package/dist/utils.d.ts +3 -3
  27. package/dist/utils.d.ts.map +1 -1
  28. package/package.json +2 -1
  29. package/src/blob-store/downloader.js +12 -4
  30. package/src/blob-store/hyperdrive-index.js +22 -3
  31. package/src/blob-store/index.js +18 -7
  32. package/src/core-manager/index.js +16 -70
  33. package/src/generated/extensions.d.ts +0 -30
  34. package/src/generated/extensions.js +0 -165
  35. package/src/generated/extensions.ts +0 -204
  36. package/src/generated/rpc.d.ts +30 -0
  37. package/src/generated/rpc.js +191 -0
  38. package/src/generated/rpc.ts +236 -0
  39. package/src/index.js +2 -2
  40. package/src/local-peers.js +33 -0
  41. package/src/mapeo-manager.js +93 -35
  42. package/src/mapeo-project.js +18 -106
  43. package/src/utils.js +2 -2
@@ -3,7 +3,6 @@ import Database from 'better-sqlite3'
3
3
  import { decodeBlockPrefix, decode, parseVersionId } from '@comapeo/schema'
4
4
  import { drizzle } from 'drizzle-orm/better-sqlite3'
5
5
  import { sql, count, eq } from 'drizzle-orm'
6
- import { TypedEmitter } from 'tiny-typed-emitter'
7
6
  import ZipArchive from 'zip-stream-promise'
8
7
  import * as b4a from 'b4a'
9
8
  import mime from 'mime/lite'
@@ -39,18 +38,13 @@ import {
39
38
  getWinner,
40
39
  mapAndValidateCoreOwnership,
41
40
  } from './core-ownership.js'
42
- import {
43
- BLOCKED_ROLE_ID,
44
- Roles,
45
- LEFT_ROLE_ID,
46
- INACTIVE_MEMBER_ROLE_IDS,
47
- } from './roles.js'
41
+ import { BLOCKED_ROLE_ID, Roles, LEFT_ROLE_ID } from './roles.js'
48
42
  import {
49
43
  buildBlobId,
50
44
  getDeviceId,
45
+ noop,
51
46
  projectKeyToId,
52
47
  projectKeyToPublicId,
53
- validateMapShareExtension,
54
48
  valueOf,
55
49
  } from './utils.js'
56
50
  import { migrate } from './lib/drizzle-helpers.js'
@@ -73,7 +67,6 @@ import {
73
67
  ExhaustivenessError,
74
68
  nullIfNotFound,
75
69
  GeoJSONExportError,
76
- InvalidMapShareError,
77
70
  MultipleCategoryImportsError,
78
71
  UnexpectedDocSchemaError,
79
72
  } from './errors.js'
@@ -81,10 +74,14 @@ import { WebSocket } from 'ws'
81
74
  import fs from 'node:fs'
82
75
 
83
76
  import ensureError from 'ensure-error'
77
+ import ReadyResource from 'ready-resource'
78
+
84
79
  /** @import { MapShareExtension } from './generated/extensions.js' */
85
80
  /** @import { ProjectSettingsValue, Observation, Track } from '@comapeo/schema' */
86
81
  /** @import { Attachment, CoreStorage, BlobFilter, BlobId, BlobStoreEntriesStream, KeyPair, Namespace, ReplicationStream, GenericBlobFilter, MapeoValueMap, MapeoDocMap } from './types.js' */
87
82
  /** @import {Role} from './roles.js' */
83
+ /** @import { TypedEmitter } from 'tiny-typed-emitter' */
84
+
88
85
  /** @typedef {Omit<ProjectSettingsValue, 'schemaName'>} EditableProjectSettings */
89
86
  /** @typedef {ProjectSettingsValue['configMetadata']} ConfigMetadata */
90
87
  /** @typedef {Map<string,Attachment>} SeenAttachments*/
@@ -129,36 +126,16 @@ const VARIANT_EXPORT_ORDER = ['original', 'preview', 'thumbnail']
129
126
  * @property {Role & {reason: string | undefined}} role
130
127
  */
131
128
 
132
- /**
133
- * @typedef {object} AugmentedMapShareProperties
134
- * @property {readonly [number, number, number, number]} bounds - Bounding box of the shared map [W, S, E, N].
135
- * @property {readonly [string, ...string[]]} mapShareUrls - URLs associated with the map share.
136
- * @property {number} mapShareReceivedAt - Timestamp when the map share was received.
137
- * @property {string} senderDeviceId - The ID of the device that sent the map share.
138
- * @property {string} [senderDeviceName] - The name of the device that sent the map share.
139
- * @property {string} receiverDeviceId - The deviceId of the peer the map share was sent to
140
- */
141
-
142
- /**
143
- * @typedef {Omit<MapShareExtension, 'bounds' | 'mapShareUrls' | 'receiverDeviceKey'> & AugmentedMapShareProperties} MapShare
144
- */
145
-
146
- /**
147
- * @typedef {Omit<MapShare, 'mapShareReceivedAt' | 'senderDeviceId' | 'senderDeviceName'>} MapShareSend
148
- */
149
-
150
129
  /**
151
130
  * @typedef {object} ProjectEvents
152
131
  * @property {() => void} close Project resources have been cleared up
153
132
  * @property {(changeEvent: RoleChangeEvent) => void} own-role-change
154
- * @property {(e: Error, mapShare: MapShareExtension) => void} map-share-error - Emitted when an incoming map share fails to be recieved due to formatting issues
155
- * @property {(mapShare: MapShare) => void} map-share - Emitted when a map share is recieved from someone on the project
156
133
  */
157
134
 
158
135
  /**
159
- * @extends {TypedEmitter<ProjectEvents>}
136
+ * @type {ReadyResource & TypedEmitter<ProjectEvents>}
160
137
  */
161
- export class MapeoProject extends TypedEmitter {
138
+ export class MapeoProject extends ReadyResource {
162
139
  #projectKey
163
140
  #deviceId
164
141
  #identityKeypair
@@ -563,22 +540,17 @@ export class MapeoProject extends TypedEmitter {
563
540
  }
564
541
  })
565
542
 
566
- this.#coreManager.on('map-share', (mapShareBase, senderDeviceId) =>
567
- this.#handleMapShare(mapShareBase, senderDeviceId).catch((e) => {
568
- this.emit('map-share-error', e, mapShareBase)
569
- this.#l.log(
570
- 'Error: Unable to handle incoming Map Share',
571
- ensureError(e)
572
- )
573
- })
574
- )
575
-
576
543
  this.once('close', () => {
577
544
  localPeers.off('peer-add', onPeerAdd)
578
545
  localPeers.off('discovery-key', onDiscoverykey)
579
546
  })
580
547
 
581
548
  this.#l.log('Created project instance %h, %s', projectKey, isArchiveDevice)
549
+
550
+ // Not necessary, because coreManager and blobStore "auto-open", but leaving
551
+ // this here defensively in case we add additional resources to _open() in
552
+ // the future
553
+ this.ready().catch(noop)
582
554
  }
583
555
 
584
556
  /**
@@ -620,23 +592,23 @@ export class MapeoProject extends TypedEmitter {
620
592
 
621
593
  /**
622
594
  * Resolves when hypercores have all loaded
623
- *
624
595
  * @returns {Promise<void>}
625
596
  */
626
- ready() {
627
- return this.#coreManager.ready()
597
+ async _open() {
598
+ await this.#coreManager.ready()
599
+ await this.#blobStore.ready()
628
600
  }
629
601
 
630
602
  /**
631
603
  */
632
- async close() {
604
+ async _close() {
633
605
  this.#l.log('closing project %h', this.#projectId)
634
- this.#blobStore.close()
635
606
  const dataStorePromises = []
636
607
  for (const dataStore of Object.values(this.#dataStores)) {
637
608
  dataStorePromises.push(dataStore.close())
638
609
  }
639
610
  await Promise.all(dataStorePromises)
611
+ await this.#blobStore.close()
640
612
  await this.#coreManager.close()
641
613
 
642
614
  this.#sqlite.close()
@@ -805,43 +777,6 @@ export class MapeoProject extends TypedEmitter {
805
777
  this.emit('own-role-change', { role })
806
778
  }
807
779
 
808
- /**
809
- * @param {MapShareExtension} mapShareBase
810
- * @param {string} senderDeviceId
811
- */
812
- async #handleMapShare(mapShareBase, senderDeviceId) {
813
- const mapShareReceivedAt = Date.now()
814
-
815
- validateMapShareExtension(mapShareBase)
816
-
817
- const sender = await this.$member.getById(senderDeviceId)
818
-
819
- if (INACTIVE_MEMBER_ROLE_IDS.includes(sender.role.roleId)) {
820
- throw new InvalidMapShareError(
821
- `Map Share Sender is not an active member of the project (role: ${sender.role.name})`
822
- )
823
- }
824
-
825
- const { receiverDeviceKey, ...mapShareData } = mapShareBase
826
-
827
- const receiverDeviceId = receiverDeviceKey.toString('hex')
828
-
829
- if (receiverDeviceId !== this.#deviceId) {
830
- throw new Error('Got map share intended for a different peer')
831
- }
832
-
833
- /** @type {MapShare} */
834
- const mapShare = {
835
- ...mapShareData,
836
- senderDeviceId,
837
- senderDeviceName: sender.name,
838
- mapShareReceivedAt,
839
- receiverDeviceId,
840
- }
841
-
842
- this.emit('map-share', mapShare)
843
- }
844
-
845
780
  /**
846
781
  * @deprecated
847
782
  * @param {string} originalVersionId The `originalVersionId` from a document.
@@ -1490,29 +1425,6 @@ export class MapeoProject extends TypedEmitter {
1490
1425
  this.#importingCategories = false
1491
1426
  }
1492
1427
  }
1493
-
1494
- /**
1495
- * Send a map share offer to the peer with device ID `mapShare.receiverDeviceId`
1496
- *
1497
- * @param {MapShareSend} mapShare
1498
- * @param {object} [options]
1499
- * @param {boolean} [options.__testOnlyBypassValidation=false] Warning: Do not use!
1500
- */
1501
- async $sendMapShare(mapShare, { __testOnlyBypassValidation = false } = {}) {
1502
- const { receiverDeviceId, ...mapShareData } = mapShare
1503
- const receiverDeviceKey = Buffer.from(receiverDeviceId, 'hex')
1504
-
1505
- /** @type {MapShareExtension} */
1506
- // @ts-expect-error readonly fields being assigned as mutable
1507
- const shareExtension = {
1508
- ...mapShareData,
1509
- receiverDeviceKey,
1510
- }
1511
- if (!__testOnlyBypassValidation) {
1512
- validateMapShareExtension(shareExtension)
1513
- }
1514
- await this.#coreManager.sendMapShare(shareExtension)
1515
- }
1516
1428
  }
1517
1429
 
1518
1430
  /**
package/src/utils.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  } from './errors.js'
12
12
  import pTimeout, { TimeoutError as pTimeoutError } from 'p-timeout'
13
13
 
14
- /** @import { MapShareExtension } from './generated/extensions.js' */
14
+ /** @import { MapShareExtension } from './generated/rpc.js' */
15
15
  /** @import {Attachment, BlobId} from "./types.js" */
16
16
 
17
17
  const PROJECT_INVITE_ID_SALT = Buffer.from('mapeo project invite id', 'ascii')
@@ -267,7 +267,7 @@ export async function timeoutPromise(promise, opts) {
267
267
  * Does not validate device ID or device name
268
268
  *
269
269
  * @param {MapShareExtension} mapShare
270
- * @returns {asserts mapShare is { [K in keyof MapShareExtension]: import('./mapeo-project.js').MapShare[K] }} - this validates the properties that MapShareExtension and MapShare have in common - bounds tuple and mapShareUrls
270
+ * @returns {asserts mapShare is { [K in keyof MapShareExtension]: import('./mapeo-manager.js').MapShare[K] }} - this validates the properties that MapShareExtension and MapShare have in common - bounds tuple and mapShareUrls
271
271
  */
272
272
  export function validateMapShareExtension(mapShare) {
273
273
  const {