@comapeo/core 3.0.0-0 → 3.1.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 (53) hide show
  1. package/dist/generated/rpc.d.ts +47 -0
  2. package/dist/generated/rpc.d.ts.map +1 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/invite/invite-api.d.ts +4 -5
  5. package/dist/invite/invite-api.d.ts.map +1 -1
  6. package/dist/local-peers.d.ts +31 -0
  7. package/dist/local-peers.d.ts.map +1 -1
  8. package/dist/mapeo-manager.d.ts +30 -22
  9. package/dist/mapeo-manager.d.ts.map +1 -1
  10. package/dist/mapeo-project.d.ts +39 -1
  11. package/dist/mapeo-project.d.ts.map +1 -1
  12. package/dist/member-api.d.ts +15 -1
  13. package/dist/member-api.d.ts.map +1 -1
  14. package/dist/schema/client.d.ts +26 -3
  15. package/dist/schema/client.d.ts.map +1 -1
  16. package/dist/sync/sync-api.d.ts +4 -1
  17. package/dist/sync/sync-api.d.ts.map +1 -1
  18. package/drizzle/client/0002_brief_demogoblin.sql +2 -0
  19. package/drizzle/client/meta/0002_snapshot.json +220 -0
  20. package/drizzle/client/meta/_journal.json +7 -0
  21. package/package.json +3 -3
  22. package/src/generated/rpc.d.ts +47 -0
  23. package/src/generated/rpc.js +241 -3
  24. package/src/generated/rpc.ts +280 -1
  25. package/src/invite/invite-api.js +15 -3
  26. package/src/local-peers.js +258 -21
  27. package/src/mapeo-manager.js +60 -20
  28. package/src/mapeo-project.js +21 -3
  29. package/src/member-api.js +67 -10
  30. package/src/schema/client.js +3 -2
  31. package/src/sync/sync-api.js +6 -2
  32. package/dist/blob-store/live-download.d.ts +0 -107
  33. package/dist/blob-store/live-download.d.ts.map +0 -1
  34. package/dist/capabilities.d.ts +0 -121
  35. package/dist/capabilities.d.ts.map +0 -1
  36. package/dist/core-manager/compat.d.ts +0 -4
  37. package/dist/core-manager/compat.d.ts.map +0 -1
  38. package/dist/discovery/dns-sd.d.ts +0 -54
  39. package/dist/discovery/dns-sd.d.ts.map +0 -1
  40. package/dist/fastify-plugins/maps/index.d.ts +0 -11
  41. package/dist/fastify-plugins/maps/index.d.ts.map +0 -1
  42. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts +0 -12
  43. package/dist/fastify-plugins/maps/offline-fallback-map.d.ts.map +0 -1
  44. package/dist/fastify-plugins/maps/static-maps.d.ts +0 -11
  45. package/dist/fastify-plugins/maps/static-maps.d.ts.map +0 -1
  46. package/dist/invite-api.d.ts +0 -70
  47. package/dist/invite-api.d.ts.map +0 -1
  48. package/dist/lib/timing-safe-equal.d.ts +0 -15
  49. package/dist/lib/timing-safe-equal.d.ts.map +0 -1
  50. package/dist/media-server.d.ts +0 -36
  51. package/dist/media-server.d.ts.map +0 -1
  52. package/dist/server/ws-core-replicator.d.ts +0 -6
  53. package/dist/server/ws-core-replicator.d.ts.map +0 -1
@@ -57,6 +57,7 @@ import { IconApi } from './icon-api.js'
57
57
  import { readConfig } from './config-import.js'
58
58
  import TranslationApi from './translation-api.js'
59
59
  import { NotFoundError, nullIfNotFound } from './errors.js'
60
+ import { WebSocket } from 'ws'
60
61
  /** @import { ProjectSettingsValue } from '@comapeo/schema' */
61
62
  /** @import { CoreStorage, BlobFilter, BlobStoreEntriesStream, KeyPair, Namespace, ReplicationStream, GenericBlobFilter } from './types.js' */
62
63
 
@@ -116,6 +117,7 @@ export class MapeoProject extends TypedEmitter {
116
117
  * @param {IndexWriter} opts.sharedIndexWriter
117
118
  * @param {CoreStorage} opts.coreStorage Folder to store all hypercore data
118
119
  * @param {(mediaType: 'blobs' | 'icons') => Promise<string>} opts.getMediaBaseUrl
120
+ * @param {(url: string) => WebSocket} [opts.makeWebsocket]
119
121
  * @param {import('./local-peers.js').LocalPeers} opts.localPeers
120
122
  * @param {boolean} opts.isArchiveDevice Whether this device is an archive device
121
123
  * @param {Logger} [opts.logger]
@@ -132,6 +134,7 @@ export class MapeoProject extends TypedEmitter {
132
134
  projectSecretKey,
133
135
  encryptionKeys,
134
136
  getMediaBaseUrl,
137
+ makeWebsocket = (url) => new WebSocket(url),
135
138
  localPeers,
136
139
  logger,
137
140
  isArchiveDevice,
@@ -350,6 +353,7 @@ export class MapeoProject extends TypedEmitter {
350
353
  getProjectName: this.#getProjectName.bind(this),
351
354
  projectKey,
352
355
  rpc: localPeers,
356
+ makeWebsocket,
353
357
  getReplicationStream,
354
358
  waitForInitialSyncWithPeer: (deviceId, abortSignal) =>
355
359
  this.$sync[kWaitForInitialSyncWithPeer](deviceId, abortSignal),
@@ -400,6 +404,7 @@ export class MapeoProject extends TypedEmitter {
400
404
  roles: this.#roles,
401
405
  blobStore: this.#blobStore,
402
406
  logger: this.#l,
407
+ makeWebsocket,
403
408
  getServerWebsocketUrls: async () => {
404
409
  const members = await this.#memberApi.getMany()
405
410
  /** @type {string[]} */
@@ -410,9 +415,9 @@ export class MapeoProject extends TypedEmitter {
410
415
  member.selfHostedServerDetails
411
416
  ) {
412
417
  const { baseUrl } = member.selfHostedServerDetails
413
- const wsUrl = new URL(`/sync/${this.#projectPublicId}`, baseUrl)
414
- wsUrl.protocol = wsUrl.protocol === 'http:' ? 'ws:' : 'wss:'
415
- serverWebsocketUrls.push(wsUrl.href)
418
+ serverWebsocketUrls.push(
419
+ baseUrlToWS(baseUrl, this.#projectPublicId)
420
+ )
416
421
  }
417
422
  }
418
423
  return serverWebsocketUrls
@@ -1086,3 +1091,16 @@ function mapAndValidateDeviceInfo(doc, { coreDiscoveryKey }) {
1086
1091
  }
1087
1092
  return doc
1088
1093
  }
1094
+
1095
+ /**
1096
+ *
1097
+ * @param {string} baseUrl
1098
+ * @param {string} projectPublicId
1099
+ * @returns {string}
1100
+ */
1101
+ export function baseUrlToWS(baseUrl, projectPublicId) {
1102
+ const wsUrl = new URL(`/sync/${projectPublicId}`, baseUrl)
1103
+ wsUrl.protocol = wsUrl.protocol === 'http:' ? 'ws:' : 'wss:'
1104
+
1105
+ return wsUrl.href
1106
+ }
package/src/member-api.js CHANGED
@@ -19,7 +19,12 @@ import { isHostnameIpAddress } from './lib/is-hostname-ip-address.js'
19
19
  import { ErrorWithCode, getErrorMessage } from './lib/error.js'
20
20
  import { InviteAbortedError } from './errors.js'
21
21
  import { wsCoreReplicator } from './lib/ws-core-replicator.js'
22
- import { MEMBER_ROLE_ID, ROLES, isRoleIdForNewInvite } from './roles.js'
22
+ import {
23
+ BLOCKED_ROLE_ID,
24
+ MEMBER_ROLE_ID,
25
+ ROLES,
26
+ isRoleIdForNewInvite,
27
+ } from './roles.js'
23
28
  /**
24
29
  * @import {
25
30
  * DeviceInfo,
@@ -57,6 +62,7 @@ export class MemberApi extends TypedEmitter {
57
62
  #getProjectName
58
63
  #projectKey
59
64
  #rpc
65
+ #makeWebsocket
60
66
  #getReplicationStream
61
67
  #waitForInitialSyncWithPeer
62
68
  #dataTypes
@@ -73,6 +79,7 @@ export class MemberApi extends TypedEmitter {
73
79
  * @param {() => Promisable<undefined | string>} opts.getProjectName
74
80
  * @param {Buffer} opts.projectKey
75
81
  * @param {import('./local-peers.js').LocalPeers} opts.rpc
82
+ * @param {(url: string) => WebSocket} [opts.makeWebsocket]
76
83
  * @param {() => ReplicationStream} opts.getReplicationStream
77
84
  * @param {(deviceId: string, abortSignal: AbortSignal) => Promise<void>} opts.waitForInitialSyncWithPeer
78
85
  * @param {Object} opts.dataTypes
@@ -87,6 +94,7 @@ export class MemberApi extends TypedEmitter {
87
94
  getProjectName,
88
95
  projectKey,
89
96
  rpc,
97
+ makeWebsocket = (url) => new WebSocket(url),
90
98
  getReplicationStream,
91
99
  waitForInitialSyncWithPeer,
92
100
  dataTypes,
@@ -99,6 +107,7 @@ export class MemberApi extends TypedEmitter {
99
107
  this.#getProjectName = getProjectName
100
108
  this.#projectKey = projectKey
101
109
  this.#rpc = rpc
110
+ this.#makeWebsocket = makeWebsocket
102
111
  this.#getReplicationStream = getReplicationStream
103
112
  this.#waitForInitialSyncWithPeer = waitForInitialSyncWithPeer
104
113
  this.#dataTypes = dataTypes
@@ -157,12 +166,17 @@ export class MemberApi extends TypedEmitter {
157
166
  const projectName = project.name
158
167
  assert(projectName, 'Project must have a name to invite people')
159
168
 
169
+ const projectColor = project.projectColor
170
+ const projectDescription = project.projectDescription
171
+
160
172
  abortSignal.throwIfAborted()
161
173
 
162
174
  const invite = {
163
175
  inviteId,
164
176
  projectInviteId,
165
177
  projectName,
178
+ projectColor,
179
+ projectDescription,
166
180
  roleName,
167
181
  roleDescription,
168
182
  invitorName,
@@ -186,18 +200,16 @@ export class MemberApi extends TypedEmitter {
186
200
  case InviteResponse_Decision.DECISION_UNSPECIFIED:
187
201
  return InviteResponse_Decision.REJECT
188
202
  case InviteResponse_Decision.ACCEPT:
189
- // We should assign the role locally *before* sharing the project details
190
- // so that they're part of the project even if they don't receive the
191
- // project details message.
192
-
193
- await this.#roles.assignRole(deviceId, roleId)
194
-
195
203
  await this.#rpc.sendProjectJoinDetails(deviceId, {
196
204
  inviteId,
197
205
  projectKey: this.#projectKey,
198
206
  encryptionKeys: this.#encryptionKeys,
199
207
  })
200
208
 
209
+ // Only add after we know they got the details
210
+ // Otherwise the joiner will be stuck unable to join
211
+ await this.#roles.assignRole(deviceId, roleId)
212
+
201
213
  return inviteResponse.decision
202
214
  default:
203
215
  throw new ExhaustivenessError(inviteResponse.decision)
@@ -314,6 +326,46 @@ export class MemberApi extends TypedEmitter {
314
326
  })
315
327
  }
316
328
 
329
+ /**
330
+ * Remove a server peer. Only works when the peer is reachable
331
+ *
332
+ * @param {string} serverDeviceId
333
+ * @param {object} [options]
334
+ * @param {boolean} [options.dangerouslyAllowInsecureConnections] Allow insecure network connections. Should only be used in tests.
335
+ * @returns {Promise<void>}
336
+ */
337
+ async removeServerPeer(
338
+ serverDeviceId,
339
+ { dangerouslyAllowInsecureConnections = false } = {}
340
+ ) {
341
+ // Get device ID for URL
342
+ // Parse through URL to ensure end pathname if missing
343
+ const member = await this.getById(serverDeviceId)
344
+
345
+ if (!member.selfHostedServerDetails) {
346
+ throw new ErrorWithCode(
347
+ 'DEVICE_ID_NOT_FOR_SERVER',
348
+ 'DeviceId is not for a server peer'
349
+ )
350
+ }
351
+
352
+ if (member.role.roleId === BLOCKED_ROLE_ID) {
353
+ throw new ErrorWithCode('ALREADY_BLOCKED', 'Server peer already blocked')
354
+ }
355
+
356
+ const { baseUrl } = member.selfHostedServerDetails
357
+
358
+ // Add blocked role to project
359
+ await this.#roles.assignRole(serverDeviceId, BLOCKED_ROLE_ID)
360
+
361
+ // TODO: Catch fail and sync with server after
362
+ await this.#waitForInitialSyncWithServer({
363
+ baseUrl,
364
+ serverDeviceId,
365
+ dangerouslyAllowInsecureConnections,
366
+ })
367
+ }
368
+
317
369
  /**
318
370
  * @param {string} baseUrl Server base URL. Should already be validated.
319
371
  * @returns {Promise<{ serverDeviceId: string }>}
@@ -378,7 +430,7 @@ export class MemberApi extends TypedEmitter {
378
430
  ? 'ws:'
379
431
  : 'wss:'
380
432
 
381
- const websocket = new WebSocket(websocketUrl)
433
+ const websocket = this.#makeWebsocket(websocketUrl.href)
382
434
 
383
435
  try {
384
436
  await pEvent(websocket, 'open', { rejectionEvents: ['error'] })
@@ -400,7 +452,7 @@ export class MemberApi extends TypedEmitter {
400
452
  const onErrorPromise = pEvent(websocket, 'error')
401
453
 
402
454
  const replicationStream = this.#getReplicationStream()
403
- wsCoreReplicator(websocket, replicationStream)
455
+ const streamPromise = wsCoreReplicator(websocket, replicationStream)
404
456
 
405
457
  const syncAbortController = new AbortController()
406
458
  const syncPromise = this.#waitForInitialSyncWithPeer(
@@ -408,7 +460,11 @@ export class MemberApi extends TypedEmitter {
408
460
  syncAbortController.signal
409
461
  )
410
462
 
411
- const errorEvent = await Promise.race([onErrorPromise, syncPromise])
463
+ const errorEvent = await Promise.race([
464
+ onErrorPromise,
465
+ syncPromise,
466
+ streamPromise,
467
+ ])
412
468
 
413
469
  if (errorEvent) {
414
470
  syncAbortController.abort()
@@ -445,6 +501,7 @@ export class MemberApi extends TypedEmitter {
445
501
  result.name = deviceInfo.name
446
502
  result.deviceType = deviceInfo.deviceType
447
503
  result.joinedAt = deviceInfo.createdAt
504
+ result.selfHostedServerDetails = deviceInfo.selfHostedServerDetails
448
505
  } catch (err) {
449
506
  // Attempting to get someone else may throw because sync hasn't occurred or completed
450
507
  // Only throw if attempting to get themself since the relevant information should be available
@@ -7,9 +7,10 @@ import { jsonSchemaToDrizzleColumns as toColumns } from './schema-to-drizzle.js'
7
7
  import { backlinkTable, customJson } from './utils.js'
8
8
 
9
9
  /**
10
+ * @import { ProjectSettings } from '@comapeo/schema'
11
+ *
10
12
  * @internal
11
- * @typedef {object} ProjectInfo
12
- * @prop {string} [name]
13
+ * @typedef {Pick<ProjectSettings, 'name' | 'projectColor' | 'projectDescription'>} ProjectInfo
13
14
  */
14
15
 
15
16
  const projectInfoColumn =
@@ -99,12 +99,14 @@ export class SyncApi extends TypedEmitter {
99
99
  #getReplicationStream
100
100
  /** @type {Map<string, WebSocket>} */
101
101
  #serverWebsockets = new Map()
102
+ #makeWebsocket
102
103
 
103
104
  /**
104
105
  * @param {object} opts
105
106
  * @param {import('../core-manager/index.js').CoreManager} opts.coreManager
106
107
  * @param {CoreOwnership} opts.coreOwnership
107
108
  * @param {import('../roles.js').Roles} opts.roles
109
+ * @param {(url: string) => WebSocket} [opts.makeWebsocket]
108
110
  * @param {() => Promise<Iterable<string>>} opts.getServerWebsocketUrls
109
111
  * @param {() => ReplicationStream} opts.getReplicationStream
110
112
  * @param {import('../blob-store/index.js').BlobStore} opts.blobStore
@@ -115,6 +117,7 @@ export class SyncApi extends TypedEmitter {
115
117
  coreManager,
116
118
  throttleMs = 200,
117
119
  roles,
120
+ makeWebsocket = (url) => new WebSocket(url),
118
121
  getServerWebsocketUrls,
119
122
  getReplicationStream,
120
123
  logger,
@@ -126,6 +129,7 @@ export class SyncApi extends TypedEmitter {
126
129
  this.#coreManager = coreManager
127
130
  this.#coreOwnership = coreOwnership
128
131
  this.#roles = roles
132
+ this.#makeWebsocket = makeWebsocket
129
133
  this.#getServerWebsocketUrls = getServerWebsocketUrls
130
134
  this.#getReplicationStream = getReplicationStream
131
135
  this[kSyncState] = new SyncState({
@@ -332,7 +336,7 @@ export class SyncApi extends TypedEmitter {
332
336
  continue
333
337
  }
334
338
 
335
- const websocket = new WebSocket(url)
339
+ const websocket = this.#makeWebsocket(url)
336
340
 
337
341
  /** @param {Error} err */
338
342
  const onWebsocketError = (err) => {
@@ -354,7 +358,7 @@ export class SyncApi extends TypedEmitter {
354
358
  websocket.on('unexpected-response', onWebsocketUnexpectedResponse)
355
359
 
356
360
  const replicationStream = this.#getReplicationStream()
357
- wsCoreReplicator(websocket, replicationStream)
361
+ wsCoreReplicator(websocket, replicationStream).catch(noop)
358
362
 
359
363
  this.#serverWebsockets.set(url, websocket)
360
364
  websocket.once('close', () => {
@@ -1,107 +0,0 @@
1
- /**
2
- * Reduce multiple states into one. Factored out for unit testing because I
3
- * don't trust my coding. Probably a smarter way to do this, but this works.
4
- *
5
- * @param {Iterable<{ state: BlobDownloadState | BlobDownloadStateError }>} liveDownloads
6
- * @param {{ signal?: AbortSignal }} options
7
- * @returns {BlobDownloadState | BlobDownloadStateError}
8
- */
9
- export function combineStates(liveDownloads: Iterable<{
10
- state: BlobDownloadState | BlobDownloadStateError;
11
- }>, { signal }?: {
12
- signal?: AbortSignal;
13
- }): BlobDownloadState | BlobDownloadStateError;
14
- /**
15
- * @typedef {object} BlobDownloadState
16
- * @property {number} haveCount The number of files already downloaded
17
- * @property {number} haveBytes The bytes already downloaded
18
- * @property {number} wantCount The number of files pending download
19
- * @property {number} wantBytes The bytes pending download
20
- * @property {null} error If status = 'error' then this will be an Error object
21
- * @property {'checking' | 'downloading' | 'downloaded' | 'aborted'} status
22
- */
23
- /** @typedef {Omit<BlobDownloadState, 'error' | 'status'> & { status: 'error', error: Error }} BlobDownloadStateError */
24
- /**
25
- * @typedef {object} BlobDownloadEvents
26
- * @property {(state: BlobDownloadState | BlobDownloadStateError ) => void} state Emitted with the current download state whenever it changes (not emitted during initial 'checking' status)
27
- */
28
- /**
29
- * LiveDownload class
30
- * @extends {TypedEmitter<BlobDownloadEvents>}
31
- */
32
- export class LiveDownload extends TypedEmitter<BlobDownloadEvents> {
33
- /**
34
- * Like drive.download() but 'live', and for multiple drives
35
- * @param {Iterable<import('hyperdrive')>} drives
36
- * @param {import('./index.js').InternalDriveEmitter} emitter
37
- * @param {object} options
38
- * @param {import('../types.js').BlobFilter} [options.filter] Filter blobs of specific types and/or sizes to download
39
- * @param {AbortSignal} [options.signal]
40
- */
41
- constructor(drives: Iterable<import("hyperdrive")>, emitter: import("./index.js").InternalDriveEmitter, { filter, signal }: {
42
- filter?: import("../types.js").BlobFilter | undefined;
43
- signal?: AbortSignal | undefined;
44
- });
45
- /**
46
- * @returns {BlobDownloadState | BlobDownloadStateError}
47
- */
48
- get state(): BlobDownloadState | BlobDownloadStateError;
49
- #private;
50
- }
51
- /**
52
- * LiveDownload class
53
- * @extends {TypedEmitter<BlobDownloadEvents>}
54
- */
55
- export class DriveLiveDownload extends TypedEmitter<BlobDownloadEvents> {
56
- /**
57
- * Like drive.download() but 'live',
58
- * @param {import('hyperdrive')} drive
59
- * @param {object} options
60
- * @param {import('../types.js').BlobFilter} [options.filter] Filter blobs of specific types and/or sizes to download
61
- * @param {AbortSignal} [options.signal]
62
- */
63
- constructor(drive: import("hyperdrive"), { filter, signal }?: {
64
- filter?: import("../types.js").BlobFilter | undefined;
65
- signal?: AbortSignal | undefined;
66
- });
67
- /**
68
- * @returns {BlobDownloadState | BlobDownloadStateError}
69
- */
70
- get state(): BlobDownloadState | BlobDownloadStateError;
71
- #private;
72
- }
73
- export type BlobDownloadState = {
74
- /**
75
- * The number of files already downloaded
76
- */
77
- haveCount: number;
78
- /**
79
- * The bytes already downloaded
80
- */
81
- haveBytes: number;
82
- /**
83
- * The number of files pending download
84
- */
85
- wantCount: number;
86
- /**
87
- * The bytes pending download
88
- */
89
- wantBytes: number;
90
- /**
91
- * If status = 'error' then this will be an Error object
92
- */
93
- error: null;
94
- status: "checking" | "downloading" | "downloaded" | "aborted";
95
- };
96
- export type BlobDownloadStateError = Omit<BlobDownloadState, "error" | "status"> & {
97
- status: "error";
98
- error: Error;
99
- };
100
- export type BlobDownloadEvents = {
101
- /**
102
- * Emitted with the current download state whenever it changes (not emitted during initial 'checking' status)
103
- */
104
- state: (state: BlobDownloadState | BlobDownloadStateError) => void;
105
- };
106
- import { TypedEmitter } from 'tiny-typed-emitter';
107
- //# sourceMappingURL=live-download.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"live-download.d.ts","sourceRoot":"","sources":["../../src/blob-store/live-download.js"],"names":[],"mappings":"AA+RA;;;;;;;GAOG;AACH,6CAJW,QAAQ,CAAC;IAAE,KAAK,EAAE,iBAAiB,GAAG,sBAAsB,CAAA;CAAE,CAAC,eAC/D;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GACtB,iBAAiB,GAAG,sBAAsB,CAqCtD;AApUD;;;;;;;;GAQG;AAEH,wHAAwH;AAExH;;;GAGG;AAEH;;;GAGG;AACH;IAKE;;;;;;;OAOG;IACH,oBANW,QAAQ,CAAC,OAAO,YAAY,CAAC,CAAC,WAC9B,OAAO,YAAY,EAAE,oBAAoB,sBAEjD;QAAmD,MAAM;QAC3B,MAAM;KAAC,EAiCvC;IAED;;OAEG;IACH,wDAEC;;CACF;AAED;;;GAGG;AACH;IAaE;;;;;;OAMG;IACH,mBALW,OAAO,YAAY,CAAC,uBAE5B;QAAmD,MAAM;QAC3B,MAAM;KAAC,EAmBvC;IAED;;OAEG;IACH,wDAyBC;;CAqIF;;;;;eArRa,MAAM;;;;eACN,MAAM;;;;eACN,MAAM;;;;eACN,MAAM;;;;WACN,IAAI;YACJ,UAAU,GAAG,aAAa,GAAG,YAAY,GAAG,SAAS;;qCAGrD,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE;;;;;WAI/E,CAAC,KAAK,EAAE,iBAAiB,GAAG,sBAAsB,KAAM,IAAI;;6BApB7C,oBAAoB"}
@@ -1,121 +0,0 @@
1
- export const COORDINATOR_ROLE_ID: "f7c150f5a3a9a855";
2
- export const MEMBER_ROLE_ID: "012fd2d431c0bf60";
3
- export const BLOCKED_ROLE_ID: "9e6d29263cba36c9";
4
- export const LEFT_ROLE_ID: "8ced989b1904606b";
5
- /**
6
- * @typedef {object} DocCapability
7
- * @property {boolean} readOwn - can read own data
8
- * @property {boolean} writeOwn - can write own data
9
- * @property {boolean} readOthers - can read other's data
10
- * @property {boolean} writeOthers - can edit or delete other's data
11
- */
12
- /**
13
- * @typedef {object} Capability
14
- * @property {string} name
15
- * @property {Record<import('@mapeo/schema').MapeoDoc['schemaName'], DocCapability>} docs
16
- * @property {RoleId[]} roleAssignment
17
- * @property {Record<import('./core-manager/core-index.js').Namespace, 'allowed' | 'blocked'>} sync
18
- */
19
- /**
20
- * @typedef {typeof COORDINATOR_ROLE_ID | typeof MEMBER_ROLE_ID | typeof BLOCKED_ROLE_ID | typeof LEFT_ROLE_ID} RoleId
21
- */
22
- /**
23
- * This is currently the same as 'Coordinator' capabilities, but defined
24
- * separately because the creator should always have ALL capabilities, but we
25
- * could edit 'Coordinator' capabilities in the future
26
- *
27
- * @type {Capability}
28
- */
29
- export const CREATOR_CAPABILITIES: Capability;
30
- /**
31
- * These are the capabilities assumed for a device when no capability record can
32
- * be found. This can happen when an invited device did not manage to sync with
33
- * the device that invited them, and they then try to sync with someone else. We
34
- * want them to be able to sync the auth and config store, because that way they
35
- * may be able to receive their role record, and they can get the project config
36
- * so that they can start collecting data.
37
- *
38
- * @type {Capability}
39
- */
40
- export const NO_ROLE_CAPABILITIES: Capability;
41
- /** @type {Record<RoleId, Capability>} */
42
- export const DEFAULT_CAPABILITIES: Record<RoleId, Capability>;
43
- export class Capabilities {
44
- static NO_ROLE_CAPABILITIES: Capability;
45
- /**
46
- *
47
- * @param {object} opts
48
- * @param {import('./datatype/index.js').DataType<
49
- * import('./datastore/index.js').DataStore<'auth'>,
50
- * typeof import('./schema/project.js').roleTable,
51
- * 'role',
52
- * import('@mapeo/schema').Role,
53
- * import('@mapeo/schema').RoleValue
54
- * >} opts.dataType
55
- * @param {import('./core-ownership.js').CoreOwnership} opts.coreOwnership
56
- * @param {import('./core-manager/index.js').CoreManager} opts.coreManager
57
- * @param {Buffer} opts.projectKey
58
- * @param {Buffer} opts.deviceKey public key of this device
59
- */
60
- constructor({ dataType, coreOwnership, coreManager, projectKey, deviceKey }: {
61
- dataType: import('./datatype/index.js').DataType<import('./datastore/index.js').DataStore<'auth'>, typeof import('./schema/project.js').roleTable, 'role', import('@mapeo/schema').Role, import('@mapeo/schema').RoleValue>;
62
- coreOwnership: import('./core-ownership.js').CoreOwnership;
63
- coreManager: import('./core-manager/index.js').CoreManager;
64
- projectKey: Buffer;
65
- deviceKey: Buffer;
66
- });
67
- /**
68
- * Get the capabilities for device `deviceId`.
69
- *
70
- * @param {string} deviceId
71
- * @returns {Promise<Capability>}
72
- */
73
- getCapabilities(deviceId: string): Promise<Capability>;
74
- /**
75
- * Get capabilities of all devices in the project. For your own device, if you
76
- * have not yet synced your own role record, the "no role" capabilties is
77
- * returned. The project creator will have `CREATOR_CAPABILITIES` unless a
78
- * different role has been assigned.
79
- *
80
- * @returns {Promise<Record<string, Capability>>} Map of deviceId to Capability
81
- */
82
- getAll(): Promise<Record<string, Capability>>;
83
- /**
84
- * Assign a role to the specified `deviceId`. Devices without an assigned role
85
- * are unable to sync, except the project creator that defaults to having all
86
- * capabilities. Only the project creator can assign their own role. Will
87
- * throw if the device trying to assign the role lacks the `roleAssignment`
88
- * capability for the given roleId
89
- *
90
- * @param {string} deviceId
91
- * @param {keyof typeof DEFAULT_CAPABILITIES} roleId
92
- */
93
- assignRole(deviceId: string, roleId: keyof typeof DEFAULT_CAPABILITIES): Promise<void>;
94
- #private;
95
- }
96
- export type DocCapability = {
97
- /**
98
- * - can read own data
99
- */
100
- readOwn: boolean;
101
- /**
102
- * - can write own data
103
- */
104
- writeOwn: boolean;
105
- /**
106
- * - can read other's data
107
- */
108
- readOthers: boolean;
109
- /**
110
- * - can edit or delete other's data
111
- */
112
- writeOthers: boolean;
113
- };
114
- export type Capability = {
115
- name: string;
116
- docs: Record<import('@mapeo/schema').MapeoDoc['schemaName'], DocCapability>;
117
- roleAssignment: RoleId[];
118
- sync: Record<import('./core-manager/core-index.js').Namespace, 'allowed' | 'blocked'>;
119
- };
120
- export type RoleId = typeof COORDINATOR_ROLE_ID | typeof MEMBER_ROLE_ID | typeof BLOCKED_ROLE_ID | typeof LEFT_ROLE_ID;
121
- //# sourceMappingURL=capabilities.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.js"],"names":[],"mappings":"AAKA,qDAAqD;AACrD,gDAAgD;AAChD,iDAAiD;AACjD,8CAA8C;AAE9C;;;;;;GAMG;AAEH;;;;;;GAMG;AAEH;;GAEG;AAEH;;;;;;GAMG;AACH,mCAFU,UAAU,CAkBnB;AAED;;;;;;;;;GASG;AACH,mCAFU,UAAU,CAkBnB;AAED,yCAAyC;AACzC,mCADW,OAAO,MAAM,EAAE,UAAU,CAAC,CAgFpC;AAED;IAOE,wCAAkD;IAElD;;;;;;;;;;;;;;OAcG;IACH;QANW,QAAQ,EANR,OAAO,qBAAqB,EAAE,QAAQ,CAChD,OAAW,sBAAsB,EAAE,SAAS,CAAC,MAAM,CAAC,EACpD,cAAkB,qBAAqB,EAAE,SAAS,EAClD,MAAU,EACV,OAAW,eAAe,EAAE,IAAI,EAChC,OAAW,eAAe,EAAE,SAAS,CAClC;QACyD,aAAa,EAA/D,OAAO,qBAAqB,EAAE,aAAa;QACS,WAAW,EAA/D,OAAO,yBAAyB,EAAE,WAAW;QAChC,UAAU,EAAvB,MAAM;QACO,SAAS,EAAtB,MAAM;OAQhB;IAED;;;;;OAKG;IACH,0BAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAuB/B;IAED;;;;;;;OAOG;IACH,UAFa,QAAQ,OAAO,MAAM,EAAE,UAAU,CAAC,CAAC,CAkC/C;IAED;;;;;;;;;OASG;IACH,qBAHW,MAAM,UACN,MAAM,2BAA2B,iBAyD3C;;CAQF;;;;;aAzUa,OAAO;;;;cACP,OAAO;;;;gBACP,OAAO;;;;iBACP,OAAO;;;UAKP,MAAM;UACN,OAAO,OAAO,eAAe,EAAE,QAAQ,CAAC,YAAY,CAAC,EAAE,aAAa,CAAC;oBACrE,MAAM,EAAE;UACR,OAAO,OAAO,8BAA8B,EAAE,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;;qBAIhF,0BAA0B,GAAG,qBAAqB,GAAG,sBAAsB,GAAG,mBAAmB"}
@@ -1,4 +0,0 @@
1
- /// <reference path="../../types/quickbit-universal.d.ts" />
2
- export let quickbit: typeof universal;
3
- import universal = require("quickbit-universal");
4
- //# sourceMappingURL=compat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../src/core-manager/compat.js"],"names":[],"mappings":";AAOA,sCAAwB"}
@@ -1,54 +0,0 @@
1
- /**
2
- * @typedef {object} MapeoService
3
- * @property {string} address IPv4 address of service
4
- * @property {number} port
5
- * @property {string} name Instance name
6
- */
7
- /**
8
- * @typedef {object} DnsSdEvents
9
- * @property {(service: MapeoService) => void} up
10
- * @property {(service: MapeoService) => void} down
11
- */
12
- /**
13
- * @extends {TypedEmitter<DnsSdEvents>}
14
- */
15
- export class DnsSd extends TypedEmitter<DnsSdEvents> {
16
- /**
17
- *
18
- * @param {object} [opts]
19
- * @param {string} [opts.name]
20
- * @param {boolean} [opts.disableIpv6]
21
- * @param {Logger} [opts.logger]
22
- */
23
- constructor({ name, disableIpv6, logger }?: {
24
- name?: string | undefined;
25
- disableIpv6?: boolean | undefined;
26
- logger?: Logger | undefined;
27
- } | undefined);
28
- get name(): string;
29
- /** @param {number} port */
30
- advertise(port: number): Promise<void>;
31
- browse(): void;
32
- stopAdvertising(): Promise<void>;
33
- stopBrowsing(): void;
34
- destroy(): Promise<void>;
35
- #private;
36
- }
37
- export type MapeoService = {
38
- /**
39
- * IPv4 address of service
40
- */
41
- address: string;
42
- port: number;
43
- /**
44
- * Instance name
45
- */
46
- name: string;
47
- };
48
- export type DnsSdEvents = {
49
- up: (service: MapeoService) => void;
50
- down: (service: MapeoService) => void;
51
- };
52
- import { TypedEmitter } from 'tiny-typed-emitter';
53
- import { Logger } from '../logger.js';
54
- //# sourceMappingURL=dns-sd.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dns-sd.d.ts","sourceRoot":"","sources":["../../src/discovery/dns-sd.js"],"names":[],"mappings":"AAUA;;;;;GAKG;AAEH;;;;GAIG;AAEH;;GAEG;AACH;IAoDE;;;;;;OAMG;IACH;;;;mBAMC;IAED,mBAEC;IAED,2BAA2B;IAC3B,gBADY,MAAM,iBA+BjB;IAED,eAiBC;IAED,iCAeC;IAED,qBAKC;IAED,yBA0BC;;CA+BF;;;;;aA1Na,MAAM;UACN,MAAM;;;;UACN,MAAM;;;kBAKI,YAAY,KAAK,IAAI;oBACrB,YAAY,KAAK,IAAI;;6BApBhB,oBAAoB;uBAM1B,cAAc"}
@@ -1,11 +0,0 @@
1
- export const PLUGIN_NAME: "mapeo-maps";
2
- export const DEFAULT_MAPBOX_STYLE_URL: "https://api.mapbox.com/styles/v1/mapbox/outdoors-v12";
3
- export function plugin(instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>, opts: MapsPluginOpts): Promise<void>;
4
- export type MapsPluginOpts = {
5
- prefix?: string | undefined;
6
- defaultOnlineStyleUrl?: string | undefined;
7
- };
8
- export type MapsPluginContext = {
9
- getStyleJsonUrl: () => Promise<string>;
10
- };
11
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/fastify-plugins/maps/index.js"],"names":[],"mappings":"AAYA,uCAAuC;AACvC,8FACwD;;;;;;;qBA8B1C,MAAM,OAAO,CAAC,MAAM,CAAC"}
@@ -1,12 +0,0 @@
1
- export const PLUGIN_NAME: "mapeo-static-maps";
2
- export function plugin(instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>, opts: OfflineFallbackMapPluginOpts): Promise<void>;
3
- export type OfflineFallbackMapPluginOpts = {
4
- prefix?: string | undefined;
5
- styleJsonPath: string;
6
- sourcesDir: string;
7
- };
8
- export type FallbackMapPluginDecorator = {
9
- getResolvedStyleJson: (serverAddress: string) => Promise<any>;
10
- getStyleJsonStats: () => Promise<import("node:fs").Stats>;
11
- };
12
- //# sourceMappingURL=offline-fallback-map.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"offline-fallback-map.d.ts","sourceRoot":"","sources":["../../../src/fastify-plugins/maps/offline-fallback-map.js"],"names":[],"mappings":"AAWA,8CAA8C;;;;mBAUhC,MAAM;gBACN,MAAM;;;0BAKN,CAAC,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC;uBACvC,MAAM,OAAO,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC"}
@@ -1,11 +0,0 @@
1
- export const PLUGIN_NAME: "mapeo-static-maps";
2
- export function plugin(instance: import("fastify").FastifyInstance<import("fastify").RawServerDefault, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>, opts: StaticMapsPluginOpts): Promise<void>;
3
- export type StaticMapsPluginOpts = {
4
- prefix?: string | undefined;
5
- staticRootDir: string;
6
- };
7
- export type StaticMapsPluginDecorator = {
8
- getResolvedStyleJson: (styleId: string, serverAddress: string) => Promise<string>;
9
- getStyleJsonStats: (styleId: string) => Promise<import("node:fs").Stats>;
10
- };
11
- //# sourceMappingURL=static-maps.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"static-maps.d.ts","sourceRoot":"","sources":["../../../src/fastify-plugins/maps/static-maps.js"],"names":[],"mappings":"AAeA,8CAA8C;;;;mBAUhC,MAAM;;;0BAKN,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC;uBAC3D,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC"}