@comapeo/core 6.0.2 → 7.0.0

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 -4
  2. package/dist/blob-store/downloader.d.ts.map +1 -1
  3. package/dist/blob-store/hyperdrive-index.d.ts +5 -3
  4. package/dist/blob-store/hyperdrive-index.d.ts.map +1 -1
  5. package/dist/blob-store/index.d.ts +6 -5
  6. package/dist/blob-store/index.d.ts.map +1 -1
  7. package/dist/core-manager/index.d.ts +6 -19
  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 +5 -70
  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 +11 -4
  30. package/src/blob-store/hyperdrive-index.js +20 -3
  31. package/src/blob-store/index.js +17 -7
  32. package/src/core-manager/index.js +15 -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 +16 -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,6 +74,8 @@ 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' */
@@ -129,36 +124,16 @@ const VARIANT_EXPORT_ORDER = ['original', 'preview', 'thumbnail']
129
124
  * @property {Role & {reason: string | undefined}} role
130
125
  */
131
126
 
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
127
  /**
151
128
  * @typedef {object} ProjectEvents
152
129
  * @property {() => void} close Project resources have been cleared up
153
130
  * @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
131
  */
157
132
 
158
133
  /**
159
- * @extends {TypedEmitter<ProjectEvents>}
134
+ * @extends {ReadyResource<ProjectEvents>}
160
135
  */
161
- export class MapeoProject extends TypedEmitter {
136
+ export class MapeoProject extends ReadyResource {
162
137
  #projectKey
163
138
  #deviceId
164
139
  #identityKeypair
@@ -563,22 +538,17 @@ export class MapeoProject extends TypedEmitter {
563
538
  }
564
539
  })
565
540
 
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
541
  this.once('close', () => {
577
542
  localPeers.off('peer-add', onPeerAdd)
578
543
  localPeers.off('discovery-key', onDiscoverykey)
579
544
  })
580
545
 
581
546
  this.#l.log('Created project instance %h, %s', projectKey, isArchiveDevice)
547
+
548
+ // Not necessary, because coreManager and blobStore "auto-open", but leaving
549
+ // this here defensively in case we add additional resources to _open() in
550
+ // the future
551
+ this.ready().catch(noop)
582
552
  }
583
553
 
584
554
  /**
@@ -620,23 +590,23 @@ export class MapeoProject extends TypedEmitter {
620
590
 
621
591
  /**
622
592
  * Resolves when hypercores have all loaded
623
- *
624
593
  * @returns {Promise<void>}
625
594
  */
626
- ready() {
627
- return this.#coreManager.ready()
595
+ async _open() {
596
+ await this.#coreManager.ready()
597
+ await this.#blobStore.ready()
628
598
  }
629
599
 
630
600
  /**
631
601
  */
632
- async close() {
602
+ async _close() {
633
603
  this.#l.log('closing project %h', this.#projectId)
634
- this.#blobStore.close()
635
604
  const dataStorePromises = []
636
605
  for (const dataStore of Object.values(this.#dataStores)) {
637
606
  dataStorePromises.push(dataStore.close())
638
607
  }
639
608
  await Promise.all(dataStorePromises)
609
+ await this.#blobStore.close()
640
610
  await this.#coreManager.close()
641
611
 
642
612
  this.#sqlite.close()
@@ -805,43 +775,6 @@ export class MapeoProject extends TypedEmitter {
805
775
  this.emit('own-role-change', { role })
806
776
  }
807
777
 
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
778
  /**
846
779
  * @deprecated
847
780
  * @param {string} originalVersionId The `originalVersionId` from a document.
@@ -1490,29 +1423,6 @@ export class MapeoProject extends TypedEmitter {
1490
1423
  this.#importingCategories = false
1491
1424
  }
1492
1425
  }
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
1426
  }
1517
1427
 
1518
1428
  /**
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 {