@comapeo/core 5.5.0 → 6.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 (94) hide show
  1. package/dist/blob-api.d.ts.map +1 -1
  2. package/dist/blob-store/downloader.d.ts.map +1 -1
  3. package/dist/blob-store/hyperdrive-index.d.ts.map +1 -1
  4. package/dist/blob-store/index.d.ts.map +1 -1
  5. package/dist/core-manager/bitfield-rle.d.ts.map +1 -1
  6. package/dist/core-manager/core-index.d.ts.map +1 -1
  7. package/dist/core-manager/index.d.ts.map +1 -1
  8. package/dist/core-ownership.d.ts.map +1 -1
  9. package/dist/datastore/index.d.ts.map +1 -1
  10. package/dist/datatype/index.d.ts +7 -0
  11. package/dist/datatype/index.d.ts.map +1 -1
  12. package/dist/discovery/local-discovery.d.ts.map +1 -1
  13. package/dist/errors.d.ts +437 -35
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/fastify-plugins/blobs.d.ts.map +1 -1
  16. package/dist/fastify-plugins/icons.d.ts.map +1 -1
  17. package/dist/fastify-plugins/maps.d.ts.map +1 -1
  18. package/dist/generated/rpc.d.ts +1 -0
  19. package/dist/generated/rpc.d.ts.map +1 -1
  20. package/dist/icon-api.d.ts +0 -1
  21. package/dist/icon-api.d.ts.map +1 -1
  22. package/dist/import-categories.d.ts.map +1 -1
  23. package/dist/index-writer/index.d.ts.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/intl/parse-bcp-47.d.ts.map +1 -1
  27. package/dist/invite/invite-api.d.ts.map +1 -1
  28. package/dist/lib/drizzle-helpers.d.ts.map +1 -1
  29. package/dist/lib/hypercore-helpers.d.ts.map +1 -1
  30. package/dist/lib/key-by.d.ts.map +1 -1
  31. package/dist/local-peers.d.ts +0 -14
  32. package/dist/local-peers.d.ts.map +1 -1
  33. package/dist/logger.d.ts.map +1 -1
  34. package/dist/mapeo-manager.d.ts +2 -1
  35. package/dist/mapeo-manager.d.ts.map +1 -1
  36. package/dist/mapeo-project.d.ts +1 -3
  37. package/dist/mapeo-project.d.ts.map +1 -1
  38. package/dist/member-api.d.ts +42 -7
  39. package/dist/member-api.d.ts.map +1 -1
  40. package/dist/roles.d.ts.map +1 -1
  41. package/dist/schema/json-schema-to-drizzle.d.ts.map +1 -1
  42. package/dist/schema.d.ts +2 -0
  43. package/dist/schema.d.ts.map +1 -0
  44. package/dist/sync/core-sync-state.d.ts.map +1 -1
  45. package/dist/sync/peer-sync-controller.d.ts.map +1 -1
  46. package/dist/sync/sync-api.d.ts.map +1 -1
  47. package/dist/utils.d.ts +8 -10
  48. package/dist/utils.d.ts.map +1 -1
  49. package/package.json +18 -2
  50. package/src/blob-api.js +24 -4
  51. package/src/blob-store/downloader.js +7 -6
  52. package/src/blob-store/entries-stream.js +1 -1
  53. package/src/blob-store/hyperdrive-index.js +3 -5
  54. package/src/blob-store/index.js +15 -20
  55. package/src/core-manager/bitfield-rle.js +2 -1
  56. package/src/core-manager/core-index.js +2 -1
  57. package/src/core-manager/index.js +9 -10
  58. package/src/core-ownership.js +7 -3
  59. package/src/datastore/index.js +13 -9
  60. package/src/datatype/index.js +28 -5
  61. package/src/discovery/local-discovery.js +8 -7
  62. package/src/errors.js +530 -62
  63. package/src/fastify-controller.js +3 -3
  64. package/src/fastify-plugins/blobs.js +21 -14
  65. package/src/fastify-plugins/icons.js +18 -9
  66. package/src/fastify-plugins/maps.js +6 -5
  67. package/src/generated/rpc.d.ts +1 -0
  68. package/src/generated/rpc.js +12 -1
  69. package/src/generated/rpc.ts +13 -0
  70. package/src/icon-api.js +15 -7
  71. package/src/import-categories.js +6 -7
  72. package/src/index-writer/index.js +3 -2
  73. package/src/index.js +1 -0
  74. package/src/intl/parse-bcp-47.js +2 -1
  75. package/src/invite/invite-api.js +26 -20
  76. package/src/lib/drizzle-helpers.js +54 -39
  77. package/src/lib/hypercore-helpers.js +4 -2
  78. package/src/lib/key-by.js +3 -1
  79. package/src/local-peers.js +39 -46
  80. package/src/logger.js +2 -1
  81. package/src/mapeo-manager.js +36 -23
  82. package/src/mapeo-project.js +68 -61
  83. package/src/member-api.js +177 -96
  84. package/src/roles.js +11 -10
  85. package/src/schema/json-schema-to-drizzle.js +13 -4
  86. package/src/schema.js +1 -0
  87. package/src/sync/core-sync-state.js +2 -1
  88. package/src/sync/peer-sync-controller.js +4 -3
  89. package/src/sync/sync-api.js +9 -9
  90. package/src/translation-api.js +2 -2
  91. package/src/utils.js +56 -41
  92. package/dist/lib/error.d.ts +0 -51
  93. package/dist/lib/error.d.ts.map +0 -1
  94. package/src/lib/error.js +0 -71
package/src/errors.js CHANGED
@@ -1,73 +1,506 @@
1
- export class NotFoundError extends Error {
2
- constructor(message = 'Not found') {
3
- super(message)
4
- this.name = 'NotFoundError'
5
- }
6
- }
1
+ import { createErrorClass } from 'custom-error-creator'
7
2
 
8
- export class AlreadyJoinedError extends Error {
9
- /** @param {string} [message] */
10
- constructor(message = 'AlreadyJoinedError') {
11
- super(message)
12
- this.name = 'AlreadyJoinedError'
13
- }
14
- }
3
+ export const NotFoundError = createErrorClass({
4
+ code: 'NOT_FOUND_ERROR',
5
+ message: 'Not found',
6
+ status: 404,
7
+ })
15
8
 
16
- export class InviteSendError extends Error {
17
- /** @param {string} [message] */
18
- constructor(message = 'Invite Send Error') {
19
- super(message)
20
- this.name = 'InviteSendError'
21
- }
22
- }
9
+ export const AlreadyJoinedError = createErrorClass({
10
+ code: 'ALREADY_JOINED_ERROR',
11
+ message: 'Already joined a project',
12
+ status: 409,
13
+ })
23
14
 
24
- export class InviteAbortedError extends Error {
25
- /** @param {string} [message] */
26
- constructor(message = 'Invite Aborted') {
27
- super(message)
28
- this.name = 'InviteAbortedError'
29
- }
30
- }
15
+ export const InviteSendError = createErrorClass({
16
+ code: 'INVITE_SEND_ERROR',
17
+ message: 'Failed to send invite',
18
+ status: 500,
19
+ })
31
20
 
32
- export class ProjectDetailsSendFailError extends Error {
33
- /** @param {string} [message] */
34
- constructor(message = 'Project details failed to send') {
35
- super(message)
36
- this.name = 'ProjectDetailsSendFailError'
37
- }
38
- }
21
+ export const InviteAbortedError = createErrorClass({
22
+ code: 'INVITE_ABORTED_ERROR',
23
+ message: 'Invite aborted',
24
+ status: 499,
25
+ })
39
26
 
40
- export class RPCDisconnectBeforeSendingError extends Error {
41
- /** @param {string} [message] */
42
- constructor(message = 'RPC disconnected before sending') {
43
- super(message)
44
- this.name = 'RPCDisconnectBeforeSendingError'
45
- }
46
- }
27
+ export const ProjectDetailsSendFailError = createErrorClass({
28
+ code: 'PROJECT_DETAILS_SEND_FAIL_ERROR',
29
+ message: 'Failed to send project details',
30
+ status: 500,
31
+ })
47
32
 
48
- export class RPCDisconnectBeforeAckError extends Error {
49
- /** @param {string} [message] */
50
- constructor(message = 'RPC disconnected before receiving acknowledgement') {
51
- super(message)
52
- this.name = 'RPCDisconnectBeforeAckError'
53
- }
54
- }
33
+ export const RPCDisconnectBeforeSendingError = createErrorClass({
34
+ code: 'RPC_DISCONNECT_BEFORE_SENDING_ERROR',
35
+ message: 'RPC disconnected before sending request',
36
+ status: 499,
37
+ })
55
38
 
56
- export class TimeoutError extends Error {
57
- /** @param {string} [message] */
58
- constructor(message = 'TimeoutError') {
59
- super(message)
60
- this.name = 'TimeoutError'
61
- }
62
- }
39
+ export const RPCDisconnectBeforeAckError = createErrorClass({
40
+ code: 'RPC_DISCONNECT_BEFORE_ACK_ERROR',
41
+ message: 'RPC disconnected before receiving acknowledgement',
42
+ status: 499,
43
+ })
63
44
 
64
- export class PeerNotFoundError extends Error {
65
- /** @param {string} [message] */
66
- constructor(message = 'PeerNotFoundError: Peer not found') {
67
- super(message)
68
- this.name = 'PeerNotFoundError'
69
- }
70
- }
45
+ export const TimeoutError = createErrorClass({
46
+ code: 'TIMEOUT_ERROR',
47
+ message: 'Operation timed out',
48
+ status: 504,
49
+ })
50
+
51
+ export const UnsupportedMimeTypeError = createErrorClass({
52
+ code: 'UNSUPPORTED_MIME_TYPE_ERROR',
53
+ message: 'Unsupported mimeType: {mimeType}',
54
+ status: 415,
55
+ })
56
+
57
+ export const InvalidCoreOwnershipError = createErrorClass({
58
+ code: 'INVALID_CORE_OWNERSHIP_ERROR',
59
+ message: 'Invalid coreOwnership record',
60
+ status: 400,
61
+ })
62
+
63
+ export const EmptyVariantsArrayError = createErrorClass({
64
+ code: 'EMPTY_VARIANTS_ARRAY_ERROR',
65
+ message: 'Empty variants array',
66
+ status: 400,
67
+ })
68
+
69
+ export const NoVariantsExistError = createErrorClass({
70
+ code: 'NO_VARIANTS_EXIST_ERROR',
71
+ message: 'No variants exist',
72
+ status: 404,
73
+ })
74
+
75
+ export const NoVariantsForMimeTypeError = createErrorClass({
76
+ code: 'NO_VARIANTS_FOR_MIME_TYPE_ERROR',
77
+ message: 'No variants with desired mime type {wantedMimeType} exist',
78
+ status: 404,
79
+ })
80
+
81
+ export const EmptyIconPathError = createErrorClass({
82
+ code: 'EMPTY_ICON_PATH_ERROR',
83
+ message: 'IconId, size, and extension cannot be empty strings',
84
+ status: 400,
85
+ })
86
+
87
+ export const InvalidPixelDensityError = createErrorClass({
88
+ code: 'INVALID_PIXEL_DENSITY_ERROR',
89
+ message: 'Invalid pixel density: {pixelDensity}',
90
+ status: 400,
91
+ })
92
+
93
+ export const IconNotFoundError = createErrorClass({
94
+ code: 'ICON_NOT_FOUND_ERROR',
95
+ message: 'Icon {iconName} not found in import file',
96
+ status: 404,
97
+ })
98
+
99
+ export const KeyNotFoundError = createErrorClass({
100
+ code: 'KEY_NOT_FOUND_ERROR',
101
+ message: 'Key {key} not found in map',
102
+ status: 404,
103
+ })
104
+
105
+ export const ProjectExistsError = createErrorClass({
106
+ code: 'PROJECT_EXISTS_ERROR',
107
+ message: 'Project with ID {projectPublicId} already exists',
108
+ status: 409,
109
+ })
110
+
111
+ export const FailedToSetIsArchiveDeviceError = createErrorClass({
112
+ code: 'FAILED_TO_SET_IS_ARCHIVE_DEVICE_ERROR',
113
+ message: 'Failed to set isArchiveDevice',
114
+ status: 500,
115
+ })
116
+
117
+ export const EncryptionKeysNotFoundError = createErrorClass({
118
+ code: 'ENCRYPTION_KEYS_NOT_FOUND_ERROR',
119
+ message: 'EncryptionKeys should not be undefined',
120
+ status: 400,
121
+ })
122
+
123
+ export const RoleAssignError = createErrorClass({
124
+ code: 'ROLE_ASSIGN_ERROR',
125
+ message: '{message}',
126
+ status: 403,
127
+ })
128
+
129
+ export const UnsupportedAttachmentTypeError = createErrorClass({
130
+ code: 'UNSUPPORTED_ATTACHMENT_TYPE_ERROR',
131
+ message: 'Cannot fetch URL for attachment type "{attachmentType}"',
132
+ status: 415,
133
+ })
134
+
135
+ export const UnexpectedEndOfStreamError = createErrorClass({
136
+ code: 'UNEXPECTED_END_OF_STREAM_ERROR',
137
+ message: 'Entries stream ended unexpectedly',
138
+ status: 499,
139
+ })
140
+
141
+ export const DriveNotFoundError = createErrorClass({
142
+ code: 'DRIVE_NOT_FOUND_ERROR',
143
+ message: 'Drive not found: {driveId}',
144
+ status: 404,
145
+ })
146
+
147
+ export const BlobsNotFoundError = createErrorClass({
148
+ code: 'BLOBS_NOT_FOUND_ERROR',
149
+ message: 'HyperBlobs not found for drive: {driveId}',
150
+ status: 404,
151
+ })
152
+
153
+ export const BlobReadError = createErrorClass({
154
+ code: 'BLOB_READ_ERROR',
155
+ message: 'Unable to find blob data at {path}',
156
+ status: 404,
157
+ })
158
+
159
+ export const MigrationError = createErrorClass({
160
+ code: 'MIGRATION_ERROR',
161
+ message: 'Unable to complete Drizzle Database migration',
162
+ status: 500,
163
+ })
164
+
165
+ export const GeoJSONExportError = createErrorClass({
166
+ code: 'GEOJSON_EXPORT_ERROR',
167
+ message: 'Unable to export GeoJSON file',
168
+ status: 500,
169
+ })
170
+
171
+ export const MissingWriterError = createErrorClass({
172
+ code: 'MISSING_WRITER_ERROR',
173
+ message: 'Could not find a writer for the {namespace} namespace',
174
+ status: 404,
175
+ })
176
+
177
+ export const UnsupportedCorestoreOptsError = createErrorClass({
178
+ code: 'UNSUPPORTED_CORESTORE_OPTS_ERROR',
179
+ message: 'Unsupported corestore.get() with opts: {opts}',
180
+ status: 400,
181
+ })
182
+
183
+ export const InvalidBitfieldError = createErrorClass({
184
+ code: 'INVALID_BITFIELD_ERROR',
185
+ message: 'Invalid RLE bitfield',
186
+ status: 400,
187
+ })
188
+
189
+ export const InvalidDocSchemaError = createErrorClass({
190
+ code: 'INVALID_DOC_SCHEMA_ERROR',
191
+ message: "Schema '{schemaName}' is not allowed in namespace '{namespace}'",
192
+ status: 403,
193
+ })
194
+
195
+ export const UnexpectedDocSchemaError = createErrorClass({
196
+ code: 'UNEXPECTED_DOC_SCHEMA_ERROR',
197
+ message: 'Expected {expectedSchema} but got {gotSchema}',
198
+ status: 403,
199
+ })
200
+
201
+ export const WriterCoreNotReadyError = createErrorClass({
202
+ code: 'WRITER_CORE_NOT_READY_ERROR',
203
+ message: 'Writer core is not ready',
204
+ status: 503,
205
+ })
206
+
207
+ export const InvalidVersionIdError = createErrorClass({
208
+ code: 'INVALID_VERSION_ID_ERROR',
209
+ message: 'Invalid versionId',
210
+ status: 404,
211
+ })
212
+
213
+ export const InvalidDocFormatError = createErrorClass({
214
+ code: 'INVALID_DOC_FORMAT_ERROR',
215
+ message: 'Invalid value: {value}',
216
+ status: 400,
217
+ })
218
+
219
+ export const DocAlreadyExistsError = createErrorClass({
220
+ code: 'DOC_ALREADY_EXISTS_ERROR',
221
+ message: 'Doc with docId {docId} already exists',
222
+ status: 409,
223
+ })
224
+
225
+ export const DocAlreadyDeletedError = createErrorClass({
226
+ code: 'DOC_ALREADY_DELETED_ERROR',
227
+ message: 'Doc already deleted',
228
+ status: 409,
229
+ })
230
+
231
+ export const InvalidDocError = createErrorClass({
232
+ code: 'INVALID_DOC_ERROR',
233
+ message: 'Updated docs must have the same docId and schemaName',
234
+ status: 400,
235
+ })
236
+
237
+ export const ServerNotListeningError = createErrorClass({
238
+ code: 'SERVER_NOT_LISTENING_ERROR',
239
+ message: 'Server is not listening on a port',
240
+ status: 503,
241
+ })
242
+
243
+ export const UnsupportedVariantError = createErrorClass({
244
+ code: 'UNSUPPORTED_VARIANT_ERROR',
245
+ message: 'Unsupported variant "{variant}" for {type}',
246
+ status: 400,
247
+ })
248
+
249
+ export const BlobStoreEntryNotFoundError = createErrorClass({
250
+ code: 'BLOB_STORE_ENTRY_NOT_FOUND_ERROR',
251
+ message: 'Blob store entry not found',
252
+ status: 404,
253
+ })
254
+
255
+ export const BlobNotFoundError = createErrorClass({
256
+ code: 'BLOB_NOT_FOUND_ERROR',
257
+ message: 'Blob not found',
258
+ status: 404,
259
+ })
260
+
261
+ export const InvalidIconSizeError = createErrorClass({
262
+ code: 'INVALID_ICON_SIZE_ERROR',
263
+ message: '{value} is not a valid icon size',
264
+ status: 400,
265
+ })
266
+
267
+ export const InvalidIconPixelDensityError = createErrorClass({
268
+ code: 'INVALID_ICON_PIXEL_DENSITY_ERROR',
269
+ message: 'Invalid icon pixel density: {density}',
270
+ status: 400,
271
+ })
272
+
273
+ export const FailedToGetStyleError = createErrorClass({
274
+ code: 'FAILED_TO_GET_STYLE_ERROR',
275
+ message: 'Failed to get style from {href}',
276
+ status: 500,
277
+ })
278
+
279
+ export const UnknownSchemaError = createErrorClass({
280
+ code: 'UNKNOWN_SCHEMA_ERROR',
281
+ message: 'IndexWriter doesn\'t know a schema named "{schemaName}"',
282
+ status: 400,
283
+ })
284
+
285
+ export const InvalidLanguageTagError = createErrorClass({
286
+ code: 'INVALID_LANGUAGE_TAG_ERROR',
287
+ message: 'Invalid BCP 47 language tag: {languageTag}',
288
+ status: 400,
289
+ })
290
+
291
+ export const DuplicateKeyError = createErrorClass({
292
+ code: 'DUPLICATE_KEY_ERROR',
293
+ message: 'Duplicate key: {key}',
294
+ status: 409,
295
+ })
296
+
297
+ export const InvalidComapeoSchemaFormatError = createErrorClass({
298
+ code: 'INVALID_COMAPEO_SCHEMA_FORMAT_ERROR',
299
+ message:
300
+ 'Cannot process JSONSchema from @comapeo/schema for {tableName} SQL table: {reason}',
301
+ status: 400,
302
+ })
303
+
304
+ export const InvalidBitfieldIndexError = createErrorClass({
305
+ code: 'INVALID_BITFIELD_INDEX_ERROR',
306
+ message: 'Index is not a multiple of 32',
307
+ status: 400,
308
+ })
309
+
310
+ export const InvalidUrlError = createErrorClass({
311
+ code: 'INVALID_URL',
312
+ message: 'Invalid URL provided',
313
+ status: 400,
314
+ })
315
+
316
+ export const AlreadyBlockedError = createErrorClass({
317
+ code: 'ALREADY_BLOCKED_ERROR',
318
+ message: 'Member already blocked',
319
+ status: 403,
320
+ })
321
+
322
+ export const DeviceIdNotForServerError = createErrorClass({
323
+ code: 'DEVICE_ID_NOT_FOR_SERVER_ERROR',
324
+ message: 'DeviceId {deviceId} is not for a server peer',
325
+ status: 403,
326
+ })
327
+
328
+ export const IncompleteProjectDataError = createErrorClass({
329
+ code: 'INCOMPLETE_PROJECT_DATA_ERROR',
330
+ message: 'Project must have name to add server peer',
331
+ status: 400,
332
+ })
333
+
334
+ export const NetworkError = createErrorClass({
335
+ code: 'NETWORK_ERROR',
336
+ message: 'Network error',
337
+ status: 502,
338
+ })
339
+
340
+ export const InvalidServerResponseError = createErrorClass({
341
+ code: 'INVALID_SERVER_RESPONSE',
342
+ message: 'Invalid Server Response',
343
+ status: 502,
344
+ })
345
+
346
+ export const ProjectNotInAllowlistError = createErrorClass({
347
+ code: 'PROJECT_NOT_IN_SERVER_ALLOWLIST',
348
+ message:
349
+ "The server only allows specific projects to be added, and this isn't one of them",
350
+ status: 403,
351
+ })
352
+
353
+ export const ServerTooManyProjectsError = createErrorClass({
354
+ code: 'SERVER_HAS_TOO_MANY_PROJECTS',
355
+ message:
356
+ "The server limits the number of projects it can have and it's at the limit",
357
+ status: 429,
358
+ })
359
+
360
+ export const MissingOwnDeviceInfoError = createErrorClass({
361
+ code: 'MISSING_OWN_DEVICE_INFO_ERROR',
362
+ message: 'Own device information is missing',
363
+ status: 400,
364
+ })
365
+
366
+ export const CategoryFileNotFoundError = createErrorClass({
367
+ code: 'CATEGORY_FILE_NOT_FOUND_ERROR',
368
+ message: 'Category file not found at {filePath}',
369
+ status: 404,
370
+ })
371
+
372
+ export const MultipleCategoryImportsError = createErrorClass({
373
+ code: 'MULTIPLE_CATEGORY_IMPORTS_ERROR',
374
+ message: 'Cannot run multiple category imports at the same time',
375
+ status: 409,
376
+ })
377
+
378
+ export const UnknownPeerError = createErrorClass({
379
+ code: 'UNKNOWN_PEER_ERROR',
380
+ message: 'Unknown peer {deviceId}',
381
+ status: 404,
382
+ })
383
+
384
+ export const PeerDisconnectedError = createErrorClass({
385
+ code: 'PEER_DISCONNECTED_ERROR',
386
+ message: 'Peer disconnected',
387
+ status: 504,
388
+ })
389
+
390
+ export const PeerFailedConnectionError = createErrorClass({
391
+ code: 'PEER_FAILED_CONNECTION_ERROR',
392
+ message: 'Peer failed to connect before disconnect was called',
393
+ status: 408,
394
+ })
395
+
396
+ export const UnknownError = createErrorClass({
397
+ code: 'UNKNOWN_ERROR',
398
+ message: 'An unexpected error type occurred: {err}',
399
+ status: 500,
400
+ })
401
+
402
+ export const ExhaustivenessError = createErrorClass({
403
+ code: 'EXHAUSTIVENESS_ERROR',
404
+ message: 'Exhaustiveness check failed. {value} should be impossible',
405
+ status: 500,
406
+ })
407
+
408
+ export const PeerNotFoundError = createErrorClass({
409
+ code: 'PEER_NOT_FOUND_ERROR',
410
+ message: 'Peer not found',
411
+ status: 404,
412
+ })
413
+
414
+ export const InvalidMapShareError = createErrorClass({
415
+ code: 'INVALID_MAP_SHARE_ERROR',
416
+ message: '{message}',
417
+ status: 400,
418
+ })
419
+
420
+ export const InvalidResponseBodyError = createErrorClass({
421
+ code: 'INVALID_RESPONSE_BODY_ERROR',
422
+ message: 'Response body is not valid',
423
+ status: 400,
424
+ })
425
+
426
+ export const InvalidInviteError = createErrorClass({
427
+ code: 'INVALID_INVITE_ERROR',
428
+ message: '{message}',
429
+ status: 400,
430
+ })
431
+
432
+ export const InviteNotFoundError = createErrorClass({
433
+ code: 'INVITE_NOT_FOUND_ERROR',
434
+ message: 'Cannot find invite {inviteId}',
435
+ status: 404,
436
+ })
437
+
438
+ export const AlreadyInvitingError = createErrorClass({
439
+ code: 'ALREADY_INVITING_ERROR',
440
+ message: 'Already invited this device ID',
441
+ status: 409,
442
+ })
443
+
444
+ export const InvalidRoleIDForNewInviteError = createErrorClass({
445
+ code: 'INVALID_ROLE_ID_FOR_NEW_INVITE_ERROR',
446
+ message: 'Invalid role ID for new invite: {roleId}',
447
+ status: 400,
448
+ })
449
+
450
+ export const InvalidProjectNameError = createErrorClass({
451
+ code: 'INVALID_PROJECT_NAME_ERROR',
452
+ message: 'Project must have a name to invite people',
453
+ status: 400,
454
+ })
455
+
456
+ export const InvalidProjectKeyError = createErrorClass({
457
+ code: 'INVALID_PROJECT_KEY_ERROR',
458
+ message: 'Project owner core public key must be 32-byte buffer',
459
+ status: 400,
460
+ })
461
+
462
+ export const InvalidProjectSecretKeyError = createErrorClass({
463
+ code: 'INVALID_PROJECT_SECRET_KEY_ERROR',
464
+ message: 'Project owner core secret key must be 64-byte buffer',
465
+ status: 400,
466
+ })
467
+
468
+ export const InvalidProjectJoinDetailsError = createErrorClass({
469
+ code: 'INVALID_PROJECT_JOIN_DETAILS_ERROR',
470
+ message: '{message}',
471
+ status: 400,
472
+ })
473
+
474
+ export const UnexpectedError = createErrorClass({
475
+ code: 'UNEXPECTED_ERROR',
476
+ message: 'An unexpected error occurred',
477
+ status: 500,
478
+ })
479
+
480
+ export const AutoStopTimeoutError = createErrorClass({
481
+ code: 'AUTO_STOP_TIMEOUT_ERROR',
482
+ message:
483
+ 'Auto-stop timeout must be Infinity or a positive integer between 0 and the largest 32-bit signed integer',
484
+ status: 400,
485
+ })
486
+
487
+ export const MissingDiscoveryKeyError = createErrorClass({
488
+ code: 'MISSING_DISCOVERY_KEY_ERROR',
489
+ message: 'Core should have a discovery key',
490
+ status: 400,
491
+ })
492
+
493
+ export const InvalidDrizzleQueryResultError = createErrorClass({
494
+ code: 'INVALID_DRIZZLE_QUERY_RESULT_ERROR',
495
+ message: 'Expected query to return proper result',
496
+ status: 400,
497
+ })
498
+
499
+ export const InvalidDrizzleJournalError = createErrorClass({
500
+ code: 'INVALID_DRIZZLE_JOURNAL_ERROR',
501
+ message: 'Invalid journal',
502
+ status: 400,
503
+ })
71
504
 
72
505
  /**
73
506
  * @param {unknown} err
@@ -77,3 +510,38 @@ export function nullIfNotFound(err) {
77
510
  if (err instanceof NotFoundError) return null
78
511
  throw err
79
512
  }
513
+
514
+ /**
515
+ * If the argument is an `Error` instance, return its `code` property if it is a string.
516
+ * Otherwise, returns `undefined`.
517
+ *
518
+ * @param {unknown} maybeError
519
+ * @returns {undefined | string}
520
+ * @example
521
+ * try {
522
+ * // do something
523
+ * } catch (err) {
524
+ * console.error(getErrorCode(err))
525
+ * }
526
+ */
527
+ export function getErrorCode(maybeError) {
528
+ if (
529
+ maybeError instanceof Error &&
530
+ 'code' in maybeError &&
531
+ typeof maybeError.code === 'string'
532
+ ) {
533
+ return maybeError.code
534
+ }
535
+ return undefined
536
+ }
537
+
538
+ /**
539
+ * Throw an UnexpectedErrorTypeError if this is not a standard error
540
+ * @param {Error & {status?: number, code?: string} | any} err
541
+ */
542
+ export function ensureKnownError(err) {
543
+ if (typeof err.status !== 'number' || typeof err.code !== 'string') {
544
+ return new UnknownError(err)
545
+ }
546
+ return err
547
+ }
@@ -53,11 +53,11 @@ export class FastifyController {
53
53
  }
54
54
 
55
55
  /**
56
- * @param {Error} err
56
+ * @param {Error} e
57
57
  */
58
- function onError(err) {
58
+ function onError(e) {
59
59
  server.removeListener('listening', onListening)
60
- rej(err)
60
+ rej(e)
61
61
  }
62
62
  })
63
63
  }