libp2r2p 0.7.0 → 0.9.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 (50) hide show
  1. package/README.md +112 -8
  2. package/base16/index.js +6 -3
  3. package/base36/index.js +12 -8
  4. package/base62/index.js +15 -11
  5. package/base64/index.js +18 -2
  6. package/base93/index.js +19 -7
  7. package/content-key/event/index.js +40 -12
  8. package/double-dh/index.js +21 -6
  9. package/ecdh/index.js +12 -1
  10. package/error/index.js +32 -0
  11. package/event/helpers/serialize.js +31 -0
  12. package/event/index.js +116 -0
  13. package/i18n/index.js +15 -13
  14. package/idb/index.js +5 -3
  15. package/idb-queue/index.js +21 -20
  16. package/index.js +10 -0
  17. package/key/index.js +31 -18
  18. package/kind/index.js +244 -0
  19. package/nip04/index.js +47 -0
  20. package/nip05/index.js +61 -0
  21. package/nip19/index.js +176 -43
  22. package/nip44/helpers.js +95 -0
  23. package/nip44/index.js +14 -0
  24. package/nip44-v3/index.js +35 -16
  25. package/nip46/helpers/frame.js +6 -6
  26. package/nip46/helpers/url.js +8 -6
  27. package/nip46/services/bunker-signer.js +7 -6
  28. package/nip46/services/client.js +8 -7
  29. package/nip46/services/server-session.js +8 -7
  30. package/nip46/services/transport.js +9 -8
  31. package/nip96/index.js +285 -0
  32. package/nip98/index.js +56 -0
  33. package/nwt/index.js +241 -0
  34. package/package.json +22 -3
  35. package/private-channel/helpers/chunks.js +7 -6
  36. package/private-channel/helpers/event.js +5 -4
  37. package/private-channel/index.js +63 -61
  38. package/private-channel/services/received-chunks.js +4 -3
  39. package/private-message/index.js +32 -31
  40. package/private-messenger/index.js +313 -54
  41. package/private-messenger/recovery/index.js +15 -14
  42. package/private-messenger/services/channel-state.js +28 -7
  43. package/private-messenger/services/storage-maintenance.js +142 -46
  44. package/relay/helpers/hll.js +3 -1
  45. package/relay/services/query.js +3 -3
  46. package/relay/services/relay-connection.js +222 -121
  47. package/relay/services/relay-pool.js +13 -10
  48. package/temporary-storage/index.js +3 -1
  49. package/url/index.js +131 -0
  50. package/web-storage-queue/index.js +8 -6
@@ -1,8 +1,10 @@
1
- import { generateSecretKey, getPublicKey, finalizeEvent, getEventHash, validateEvent, verifyEvent } from 'nostr-tools'
1
+ import { finalizeEvent, getEventHash, isSerializableEvent, isValidEvent } from '../event/index.js'
2
+ import { generateSecretKey, getPublicKey } from '../key/index.js'
2
3
  import { bytesToBase64, base64ToBytes } from '../base64/index.js'
3
4
  import { hexToBytes } from '../base16/index.js'
4
- import { makeContentKeyEventForPubkey, parseContentKeyEvent, verifyContentKeyProof, verifyIykcProof } from '../content-key/event/index.js'
5
+ import { isValidContentKeyProof, isValidIykcProof, makeContentKeyEventForPubkey, parseContentKeyEvent } from '../content-key/event/index.js'
5
6
  import { getIykcProofs } from '../content-key/index.js'
7
+ import { ValidationError } from '../error/index.js'
6
8
  import * as nip44v3 from '../nip44-v3/index.js'
7
9
  import { relayPool } from '../relay/index.js'
8
10
  import { JSONL_CHUNK_BYTES, NYM_CARRIER_CHUNK_CHARS } from './helpers/chunk-size.js'
@@ -43,7 +45,7 @@ function uniq (values) {
43
45
  function normalizeDeletionPubkey (deletionPubkey) {
44
46
  if (deletionPubkey === undefined) return undefined
45
47
  if (typeof deletionPubkey !== 'string' || !HEX_PUBKEY.test(deletionPubkey)) {
46
- throw new Error('INVALID_DELETION_PUBKEY')
48
+ throw new ValidationError('INVALID_DELETION_PUBKEY')
47
49
  }
48
50
  return deletionPubkey.toLowerCase()
49
51
  }
@@ -79,7 +81,7 @@ async function nip44v3DecryptText (signer, peerPubkey, kind, ciphertext) {
79
81
  return base64ToText(await signer.nip44v3Decrypt(peerPubkey, kind, NIP44_V3_SCOPE, ciphertext))
80
82
  }
81
83
 
82
- function storesRecoverySeeds (mode) {
84
+ function doesModeStoreRecoverySeeds (mode) {
83
85
  return mode === 'seeder' || mode === 'watchtower'
84
86
  }
85
87
 
@@ -89,16 +91,16 @@ async function makeImkcProof ({ senderSigner, senderPubkey, imkcPubkey }) {
89
91
  if (
90
92
  event.pubkey !== senderPubkey ||
91
93
  parsed?.iykcPubkey !== imkcPubkey ||
92
- !verifyContentKeyProof({ ownerPubkey: senderPubkey, contentPubkey: imkcPubkey, proof: parsed?.iykcProof })
93
- ) throw new Error('INVALID_IMKC_PROOF')
94
+ !isValidContentKeyProof({ ownerPubkey: senderPubkey, contentPubkey: imkcPubkey, proof: parsed?.iykcProof })
95
+ ) throw new ValidationError('INVALID_IMKC_PROOF')
94
96
  return parsed.iykcProof
95
97
  }
96
98
 
97
99
  async function prepareRoutedMessage ({ senderSigner, imkcSigner, privateChannelSigner = senderSigner, privateChannelReaderPubkey, receivers, event, temporaryStorageArea, _getIykcProofs = getIykcProofs }) {
98
- if (!senderSigner?.getPublicKey) throw new Error('SENDER_SIGNER_REQUIRED')
99
- if (!senderSigner?.nip44EncryptDoubleDH && !senderSigner?.nip44v3Encrypt) throw new Error('SIGNER_NIP44V3_ENCRYPT_UNSUPPORTED')
100
- if (!privateChannelSigner?.getPublicKey || !privateChannelSigner?.nip44v3Encrypt || !privateChannelSigner?.signEvent) throw new Error('PRIVATE_CHANNEL_SIGNER_REQUIRED')
101
- if (!Array.isArray(receivers) || !receivers.length) throw new Error('NO_RECEIVERS')
100
+ if (!senderSigner?.getPublicKey) throw new ValidationError('SENDER_SIGNER_REQUIRED')
101
+ if (!senderSigner?.nip44EncryptDoubleDH && !senderSigner?.nip44v3Encrypt) throw new ValidationError('SIGNER_NIP44V3_ENCRYPT_UNSUPPORTED')
102
+ if (!privateChannelSigner?.getPublicKey || !privateChannelSigner?.nip44v3Encrypt || !privateChannelSigner?.signEvent) throw new ValidationError('PRIVATE_CHANNEL_SIGNER_REQUIRED')
103
+ if (!Array.isArray(receivers) || !receivers.length) throw new ValidationError('NO_RECEIVERS')
102
104
 
103
105
  const senderPubkey = await senderSigner.getPublicKey()
104
106
  const useDoubleDh = typeof senderSigner.nip44EncryptDoubleDH === 'function'
@@ -158,7 +160,7 @@ async function * wrapPreparedEvents ({ privateChannelSigner, receivers, receiver
158
160
  tags: privateBroadcastTags({ deletionPubkey, createdAt, expirationSeconds }),
159
161
  content: await nip44v3EncryptText(privateChannelSigner, context.channelReaderPubkey, PRIVATE_BROADCAST_KIND, JSON.stringify(router))
160
162
  })
161
- if (eventByteLength(outer) > MAX_EVENT_BYTES) throw new Error('EVENT_TOO_LARGE')
163
+ if (eventByteLength(outer) > MAX_EVENT_BYTES) throw new ValidationError('EVENT_TOO_LARGE')
162
164
  yield outer
163
165
  }
164
166
  } finally {
@@ -193,17 +195,17 @@ export async function wrapEvent (options) {
193
195
  }
194
196
 
195
197
  export async function * wrapNymEvents ({ nymSigner, privateChannelSigner, privateChannelReaderPubkey, deletionPubkey, event, expirationSeconds = EXPIRATION_SECONDS }) {
196
- if (!nymSigner?.getPublicKey || !nymSigner?.signEvent) throw new Error('NYM_SIGNER_REQUIRED')
197
- if (!privateChannelSigner?.getPublicKey || !privateChannelSigner?.nip44v3Encrypt || !privateChannelSigner?.signEvent) throw new Error('PRIVATE_CHANNEL_SIGNER_REQUIRED')
198
+ if (!nymSigner?.getPublicKey || !nymSigner?.signEvent) throw new ValidationError('NYM_SIGNER_REQUIRED')
199
+ if (!privateChannelSigner?.getPublicKey || !privateChannelSigner?.nip44v3Encrypt || !privateChannelSigner?.signEvent) throw new ValidationError('PRIVATE_CHANNEL_SIGNER_REQUIRED')
198
200
  const normalizedDeletionPubkey = normalizeDeletionPubkey(deletionPubkey)
199
201
 
200
202
  const nymPubkey = await nymSigner.getPublicKey()
201
203
  const channelPubkey = await privateChannelSigner.getPublicKey()
202
204
  const channelReaderPubkey = privateChannelReaderPubkey || channelPubkey
203
- const wireEvent = isSignedEvent(event)
205
+ const wireEvent = hasEventSignature(event)
204
206
  ? assertValidSignedInnerEvent(event)
205
207
  : wireNymRumor({ ...event, created_at: event?.created_at !== undefined ? event.created_at : nowSeconds() })
206
- const innerEvent = isSignedEvent(wireEvent) ? wireEvent : normalizeNymRumor(wireEvent, nymPubkey)
208
+ const innerEvent = hasEventSignature(wireEvent) ? wireEvent : normalizeNymRumor(wireEvent, nymPubkey)
207
209
  const encoded = bytesToBase64(encoder.encode(JSON.stringify(wireEvent)))
208
210
  const total = Math.max(1, Math.ceil(encoded.length / NYM_CARRIER_CHUNK_CHARS))
209
211
  const carrierCreatedAt = nowSeconds()
@@ -223,7 +225,7 @@ export async function * wrapNymEvents ({ nymSigner, privateChannelSigner, privat
223
225
  tags: privateBroadcastTags({ deletionPubkey: normalizedDeletionPubkey, createdAt, expirationSeconds }),
224
226
  content: await nip44v3EncryptText(privateChannelSigner, channelReaderPubkey, PRIVATE_BROADCAST_KIND, JSON.stringify(carrier))
225
227
  })
226
- if (eventByteLength(outer) > MAX_EVENT_BYTES) throw new Error('EVENT_TOO_LARGE')
228
+ if (eventByteLength(outer) > MAX_EVENT_BYTES) throw new ValidationError('EVENT_TOO_LARGE')
227
229
  yield outer
228
230
  }
229
231
  }
@@ -244,31 +246,31 @@ function joinedRouter (router, content = '') {
244
246
 
245
247
  function parsePayloadEnvelope (line, index = 0) {
246
248
  const record = JSON.parse(line)
247
- if (!Array.isArray(record) || record.length !== 1 || typeof record[0] !== 'string') throw new Error('INVALID_PAYLOAD_ENVELOPE')
249
+ if (!Array.isArray(record) || record.length !== 1 || typeof record[0] !== 'string') throw new ValidationError('INVALID_PAYLOAD_ENVELOPE')
248
250
  return { index, type: 'payload', ciphertext: record[0] }
249
251
  }
250
252
 
251
253
  function parseRecipientEnvelope (line, index = 0) {
252
254
  const record = JSON.parse(line)
253
- if (!Array.isArray(record) || (record.length !== 2 && record.length !== 4)) throw new Error('INVALID_RECIPIENT_ENVELOPE')
255
+ if (!Array.isArray(record) || (record.length !== 2 && record.length !== 4)) throw new ValidationError('INVALID_RECIPIENT_ENVELOPE')
254
256
  const [receiverPubkey, ciphertext, iykcPubkey = '', iykcProof = ''] = record
255
257
  return { index, receiverPubkey, ciphertext, iykcPubkey, iykcProof }
256
258
  }
257
259
 
258
- function isSignedEvent (event) {
260
+ function hasEventSignature (event) {
259
261
  return Object.prototype.hasOwnProperty.call(event || {}, 'sig')
260
262
  }
261
263
 
262
264
  function assertValidSignedInnerEvent (event) {
263
- if (!validateEvent(event) || event.id !== getEventHash(event) || !verifyEvent(event)) {
264
- throw new Error('INVALID_SIGNED_INNER_EVENT')
265
+ if (!isValidEvent(event)) {
266
+ throw new ValidationError('INVALID_SIGNED_INNER_EVENT')
265
267
  }
266
268
  return event
267
269
  }
268
270
 
269
271
  function normalizeNymRumor (event, pubkey) {
270
272
  const normalized = { ...event, pubkey }
271
- if (!validateEvent(normalized)) throw new Error('INVALID_NYM_RUMOR')
273
+ if (!isSerializableEvent(normalized)) throw new ValidationError('INVALID_NYM_RUMOR')
272
274
  return { ...normalized, id: getEventHash(normalized) }
273
275
  }
274
276
 
@@ -282,11 +284,11 @@ function wireNymRumor (event = {}) {
282
284
  }
283
285
 
284
286
  function assertValidNymCarrierEvent (carrier) {
285
- if (!validateEvent(carrier) || carrier.id !== getEventHash(carrier) || !verifyEvent(carrier)) {
286
- throw new Error('INVALID_NYM_CARRIER')
287
+ if (!isValidEvent(carrier)) {
288
+ throw new ValidationError('INVALID_NYM_CARRIER')
287
289
  }
288
- if (carrier.kind !== NYM_CARRIER_KIND) throw new Error('INVALID_NYM_CARRIER_KIND')
289
- if (!readIdTag(carrier)) throw new Error('MISSING_NYM_CARRIER_ID')
290
+ if (carrier.kind !== NYM_CARRIER_KIND) throw new ValidationError('INVALID_NYM_CARRIER_KIND')
291
+ if (!readIdTag(carrier)) throw new ValidationError('MISSING_NYM_CARRIER_ID')
290
292
  readChunkTag(carrier)
291
293
  return carrier
292
294
  }
@@ -296,7 +298,7 @@ function nymCarrierGroupId (carrier) {
296
298
  }
297
299
 
298
300
  function validateNymCarriers (carriers) {
299
- if (!Array.isArray(carriers) || !carriers.length) throw new Error('NYM_CARRIERS_REQUIRED')
301
+ if (!Array.isArray(carriers) || !carriers.length) throw new ValidationError('NYM_CARRIERS_REQUIRED')
300
302
  const chunks = []
301
303
  let nymPubkey = ''
302
304
  let innerId = ''
@@ -312,15 +314,15 @@ function validateNymCarriers (carriers) {
312
314
  total = nextTotal
313
315
  }
314
316
  if (carrier.pubkey !== nymPubkey || nextInnerId !== innerId || nextTotal !== total) {
315
- throw new Error('MISMATCHED_NYM_CARRIER_CHUNKS')
317
+ throw new ValidationError('MISMATCHED_NYM_CARRIER_CHUNKS')
316
318
  }
317
- if (chunks[index] !== undefined) throw new Error('DUPLICATE_NYM_CARRIER_CHUNK')
319
+ if (chunks[index] !== undefined) throw new ValidationError('DUPLICATE_NYM_CARRIER_CHUNK')
318
320
  chunks[index] = carrier.content
319
321
  }
320
322
 
321
- if (chunks.length !== total) throw new Error('MISSING_NYM_CARRIER_CHUNK')
323
+ if (chunks.length !== total) throw new ValidationError('MISSING_NYM_CARRIER_CHUNK')
322
324
  for (let index = 0; index < total; index++) {
323
- if (chunks[index] == null) throw new Error('MISSING_NYM_CARRIER_CHUNK')
325
+ if (chunks[index] == null) throw new ValidationError('MISSING_NYM_CARRIER_CHUNK')
324
326
  }
325
327
  return { nymPubkey, innerId, content: chunks.join('') }
326
328
  }
@@ -331,44 +333,44 @@ export function eventFromNymCarriers (carriers) {
331
333
  try {
332
334
  parsed = JSON.parse(decoder.decode(base64ToBytes(content)))
333
335
  } catch {
334
- throw new Error('INVALID_NYM_CARRIER_PAYLOAD')
336
+ throw new ValidationError('INVALID_NYM_CARRIER_PAYLOAD')
335
337
  }
336
338
 
337
- if (isSignedEvent(parsed)) {
339
+ if (hasEventSignature(parsed)) {
338
340
  const event = assertValidSignedInnerEvent(parsed)
339
- if (event.id !== innerId) throw new Error('INVALID_NYM_CARRIER_INNER_ID')
341
+ if (event.id !== innerId) throw new ValidationError('INVALID_NYM_CARRIER_INNER_ID')
340
342
  return event
341
343
  }
342
344
 
343
345
  const event = normalizeNymRumor(parsed, nymPubkey)
344
- if (event.id !== innerId) throw new Error('INVALID_NYM_CARRIER_INNER_ID')
346
+ if (event.id !== innerId) throw new ValidationError('INVALID_NYM_CARRIER_INNER_ID')
345
347
  return event
346
348
  }
347
349
 
348
350
  function assertValidEnvelopeIykcProof (envelope) {
349
351
  if (!envelope.iykcPubkey) return
350
- if (!verifyIykcProof({
352
+ if (!isValidIykcProof({
351
353
  receiverPubkey: envelope.receiverPubkey,
352
354
  iykcPubkey: envelope.iykcPubkey,
353
355
  iykcProof: envelope.iykcProof
354
- })) throw new Error('INVALID_IYKC_PROOF')
356
+ })) throw new ValidationError('INVALID_IYKC_PROOF')
355
357
  }
356
358
 
357
359
  function assertValidRouterImkcProof ({ router, senderPubkey, imkcPubkey, imkcProof }) {
358
360
  if (!hasImkcTag(router)) return
359
- if (!verifyContentKeyProof({
361
+ if (!isValidContentKeyProof({
360
362
  ownerPubkey: senderPubkey,
361
363
  contentPubkey: imkcPubkey,
362
364
  proof: imkcProof
363
- })) throw new Error('INVALID_IMKC_PROOF')
365
+ })) throw new ValidationError('INVALID_IMKC_PROOF')
364
366
  }
365
367
 
366
368
  function eventFromPayload ({ payloadCiphertext, messageSeckey, senderPubkey }) {
367
- if (!HEX_SECKEY.test(messageSeckey || '')) throw new Error('INVALID_MESSAGE_SECKEY')
369
+ if (!HEX_SECKEY.test(messageSeckey || '')) throw new ValidationError('INVALID_MESSAGE_SECKEY')
368
370
  const messageSecretKey = hexToBytes(messageSeckey)
369
371
  const messagePubkey = getPublicKey(messageSecretKey)
370
372
  const decrypted = JSON.parse(nip44v3.decrypt(messageSecretKey, messagePubkey, ROUTER_KIND, NIP44_V3_SCOPE, payloadCiphertext))
371
- if (isSignedEvent(decrypted)) return assertValidSignedInnerEvent(decrypted)
373
+ if (hasEventSignature(decrypted)) return assertValidSignedInnerEvent(decrypted)
372
374
  const normalized = { ...decrypted, pubkey: senderPubkey }
373
375
  return { ...normalized, id: getEventHash(normalized) }
374
376
  }
@@ -377,7 +379,7 @@ async function unwrapRecipientEnvelope ({ payloadCiphertext, envelope, receiverS
377
379
  if (receiverPubkey && envelope.receiverPubkey !== receiverPubkey) return null
378
380
  let messageSeckey
379
381
  if (envelope.iykcPubkey || imkcPubkey) {
380
- if (!receiverSigner?.nip44DecryptDoubleDH) throw new Error('RECEIVER_DOUBLE_DH_UNSUPPORTED')
382
+ if (!receiverSigner?.nip44DecryptDoubleDH) throw new ValidationError('RECEIVER_DOUBLE_DH_UNSUPPORTED')
381
383
  if (envelope.iykcPubkey) {
382
384
  assertValidEnvelopeIykcProof(envelope)
383
385
  }
@@ -390,7 +392,7 @@ async function unwrapRecipientEnvelope ({ payloadCiphertext, envelope, receiverS
390
392
  envelope.iykcPubkey || ''
391
393
  ))
392
394
  } else {
393
- if (!receiverSigner?.nip44v3Decrypt) throw new Error('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
395
+ if (!receiverSigner?.nip44v3Decrypt) throw new ValidationError('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
394
396
  messageSeckey = base64ToText(await receiverSigner.nip44v3Decrypt(senderPubkey, ROUTER_KIND, rowScope, envelope.ciphertext))
395
397
  }
396
398
  return eventFromPayload({ payloadCiphertext, messageSeckey, senderPubkey })
@@ -398,12 +400,12 @@ async function unwrapRecipientEnvelope ({ payloadCiphertext, envelope, receiverS
398
400
 
399
401
  export async function unwrapEvent ({ receiverSigner, privateChannelSigner = receiverSigner, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderPubkey, event, receiverPubkey }) {
400
402
  if (!event || event.kind !== PRIVATE_BROADCAST_KIND) return null
401
- if (!receiverSigner?.nip44DecryptDoubleDH && !receiverSigner?.nip44v3Decrypt) throw new Error('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
403
+ if (!receiverSigner?.nip44DecryptDoubleDH && !receiverSigner?.nip44v3Decrypt) throw new ValidationError('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
402
404
  const channelReaderSigner = privateChannelReaderSigner || privateChannelSigner
403
- if (!channelReaderSigner?.nip44v3Decrypt) throw new Error('PRIVATE_CHANNEL_READER_REQUIRED')
405
+ if (!channelReaderSigner?.nip44v3Decrypt) throw new ValidationError('PRIVATE_CHANNEL_READER_REQUIRED')
404
406
 
405
407
  const channelPubkey = event.pubkey || await privateChannelSigner?.getPublicKey?.()
406
- if (!channelPubkey) throw new Error('PRIVATE_CHANNEL_PUBKEY_REQUIRED')
408
+ if (!channelPubkey) throw new ValidationError('PRIVATE_CHANNEL_PUBKEY_REQUIRED')
407
409
  const router = await decryptRouter({
408
410
  content: event.content,
409
411
  channelPubkey,
@@ -411,14 +413,14 @@ export async function unwrapEvent ({ receiverSigner, privateChannelSigner = rece
411
413
  channelReaderSigner,
412
414
  channelReaderPubkey: privateChannelReaderPubkey
413
415
  })
414
- if (router.kind !== ROUTER_KIND) throw new Error('INVALID_ROUTER_KIND')
416
+ if (router.kind !== ROUTER_KIND) throw new ValidationError('INVALID_ROUTER_KIND')
415
417
  if (receiverPubkey && readReceiverTag(router) && readReceiverTag(router) !== receiverPubkey) return null
416
418
 
417
419
  const senderPubkey = readSenderTag(router)
418
420
  const imkcPubkey = readImkcTag(router)
419
421
  assertValidRouterImkcProof({ router, senderPubkey, imkcPubkey, imkcProof: readImkcProof(router) })
420
422
  const lines = decodeChunkLines(router.content)
421
- if (!lines.length) throw new Error('MISSING_PAYLOAD_ENVELOPE')
423
+ if (!lines.length) throw new ValidationError('MISSING_PAYLOAD_ENVELOPE')
422
424
  const payload = parsePayloadEnvelope(lines[0], 0)
423
425
  for (let index = 1; index < lines.length; index++) {
424
426
  const event = await unwrapRecipientEnvelope({
@@ -443,7 +445,7 @@ function relayReceiverEntries (relayToReceivers) {
443
445
  if (!relayToReceivers) return []
444
446
  if (relayToReceivers instanceof Map) return [...relayToReceivers.entries()]
445
447
  if (typeof relayToReceivers === 'object') return Object.entries(relayToReceivers)
446
- throw new Error('INVALID_RELAY_RECEIVERS')
448
+ throw new ValidationError('INVALID_RELAY_RECEIVERS')
447
449
  }
448
450
 
449
451
  function groupedRelayReceivers ({ relayToReceivers, receivers }) {
@@ -467,7 +469,7 @@ function groupedRelayReceivers ({ relayToReceivers, receivers }) {
467
469
  const pubkeys = uniq(Array.isArray(value) ? value : [value])
468
470
  if (!pubkeys.length) continue
469
471
  for (const pubkey of pubkeys) {
470
- if (!wanted.has(pubkey)) throw new Error('RELAY_RECEIVER_NOT_REQUESTED')
472
+ if (!wanted.has(pubkey)) throw new ValidationError('RELAY_RECEIVER_NOT_REQUESTED')
471
473
  covered.add(pubkey)
472
474
  }
473
475
  const key = [...pubkeys].sort().join(',')
@@ -481,9 +483,9 @@ function groupedRelayReceivers ({ relayToReceivers, receivers }) {
481
483
  groupsByKey.get(key).relays.push(relay)
482
484
  }
483
485
 
484
- if (!groupsByKey.size) throw new Error('NO_RELAYS')
486
+ if (!groupsByKey.size) throw new ValidationError('NO_RELAYS')
485
487
  for (const pubkey of orderedPubkeys) {
486
- if (!covered.has(pubkey)) throw new Error('RELAY_RECEIVER_MISSING')
488
+ if (!covered.has(pubkey)) throw new ValidationError('RELAY_RECEIVER_MISSING')
487
489
  }
488
490
 
489
491
  return [...groupsByKey.values()].map(group => ({
@@ -554,7 +556,7 @@ function readSignerFromMap (signersByPubkey, pubkey) {
554
556
 
555
557
  async function decryptRouter ({ content, channelPubkey, channelSigner, channelReaderSigner, channelReaderPubkey }) {
556
558
  const signer = channelReaderSigner || channelSigner
557
- if (!signer?.nip44v3Decrypt) throw new Error('PRIVATE_CHANNEL_READER_REQUIRED')
559
+ if (!signer?.nip44v3Decrypt) throw new ValidationError('PRIVATE_CHANNEL_READER_REQUIRED')
558
560
 
559
561
  const readerPubkey = channelReaderPubkey || channelPubkey
560
562
  const signerPubkey = await signer.getPublicKey?.()
@@ -697,7 +699,7 @@ function createProcessor ({
697
699
  const channelReaderPubkey = readValueFromMap(privateChannelReaderPubkeysByPubkey, channelPubkey) || privateChannelReaderPubkey || channelPubkey
698
700
  const channelMode = readValueFromMap(modeByPubkey, channelPubkey) || mode
699
701
  const channelReceivedChunkTtlMs = readValueFromMap(receivedChunkTtlMsByPubkey, channelPubkey) ?? receivedChunkTtlMs
700
- if (!channelPubkey) throw new Error('PRIVATE_CHANNEL_PUBKEY_REQUIRED')
702
+ if (!channelPubkey) throw new ValidationError('PRIVATE_CHANNEL_PUBKEY_REQUIRED')
701
703
 
702
704
  const decrypted = await decryptRouter({
703
705
  content: outer.content,
@@ -734,7 +736,7 @@ function createProcessor ({
734
736
 
735
737
  const carriers = (await receivedChunks.readChunkContents(groupKey)).map(raw => JSON.parse(raw))
736
738
  const event = eventFromNymCarriers(carriers)
737
- const shouldSeed = storesRecoverySeeds(channelMode)
739
+ const shouldSeed = doesModeStoreRecoverySeeds(channelMode)
738
740
  if (shouldSeed) {
739
741
  await onSeedEvent?.({
740
742
  recordType: 'nymCarrier_v1',
@@ -782,7 +784,7 @@ function createProcessor ({
782
784
  missing: status.missing
783
785
  })
784
786
 
785
- const shouldSeed = storesRecoverySeeds(channelMode)
787
+ const shouldSeed = doesModeStoreRecoverySeeds(channelMode)
786
788
  const sentByReceiver = receiverPubkey && senderPubkey === receiverPubkey
787
789
  // Recovery seeders and own-sent messages need the full recipient list;
788
790
  // regular leechers can stop as soon as their envelope is decrypted.
@@ -796,7 +798,7 @@ function createProcessor ({
796
798
  helpers.rememberPayloadCiphertext(groupMeta, parsePayloadEnvelope(line, rowIndex).ciphertext)
797
799
  return
798
800
  }
799
- if (!groupMeta.payloadCiphertext) throw new Error('MISSING_PAYLOAD_ENVELOPE')
801
+ if (!groupMeta.payloadCiphertext) throw new ValidationError('MISSING_PAYLOAD_ENVELOPE')
800
802
  const envelope = parseRecipientEnvelope(line, rowIndex)
801
803
  helpers.rememberReceiverPubkey(groupMeta, envelope.receiverPubkey)
802
804
 
@@ -893,7 +895,7 @@ function shouldIgnoreGroupError (err) {
893
895
  }
894
896
 
895
897
  export async function fetch ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since, until, limit, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _getEvents = getEvents }) {
896
- if (!relays?.length) throw new Error('NO_RELAYS')
898
+ if (!relays?.length) throw new ValidationError('NO_RELAYS')
897
899
  const authors = privateChannelPubkeyList({ privateChannelPubkey, privateChannelPubkeys })
898
900
  const filter = { kinds: [PRIVATE_BROADCAST_KIND] }
899
901
  if (authors.length) filter.authors = authors
@@ -916,9 +918,9 @@ export async function fetch ({ receiverSigner, iykcSigner, privateChannelSigner
916
918
  }
917
919
 
918
920
  export function subscribe ({ receiverSigner, iykcSigner, privateChannelSigner = receiverSigner, privateChannelSignersByPubkey, privateChannelReaderSigner = privateChannelSigner, privateChannelReaderSignersByPubkey, privateChannelReaderPubkey, privateChannelReaderPubkeysByPubkey, privateChannelPubkey, privateChannelPubkeys, receiverPubkey, relays, onChunk, onEvent, onNymEvent, onSeedEvent, onContentKeyUsage, onError, since = nowSeconds() - 5, limit, liveOnly = false, mode = 'leecher', modeByPubkey, receivedChunkTtlMs = DEFAULT_RECEIVED_CHUNK_TTL_MS, receivedChunkTtlMsByPubkey, receivedChunkMaxBytes = DEFAULT_RECEIVED_CHUNK_MAX_BYTES, receivedChunkIndexedDB = globalThis.indexedDB, ignoredGroupTtlMs = DEFAULT_IGNORED_GROUP_TTL_MS, ignoredGroupMaxEntries = DEFAULT_IGNORED_GROUP_MAX_ENTRIES, _liveEventsGenerator = getLiveEventsGenerator, _eventsFeedGenerator = getEventsFeedGenerator }) {
919
- if (!relays?.length) throw new Error('NO_RELAYS')
920
- if (receiverSigner && !receiverSigner?.nip44DecryptDoubleDH && !receiverSigner?.nip44v3Decrypt) throw new Error('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
921
- if (!privateChannelReaderSigner && !privateChannelReaderSignersByPubkey && !privateChannelSigner && !privateChannelSignersByPubkey) throw new Error('PRIVATE_CHANNEL_READER_REQUIRED')
921
+ if (!relays?.length) throw new ValidationError('NO_RELAYS')
922
+ if (receiverSigner && !receiverSigner?.nip44DecryptDoubleDH && !receiverSigner?.nip44v3Decrypt) throw new ValidationError('RECEIVER_SIGNER_NIP44V3_DECRYPT_UNSUPPORTED')
923
+ if (!privateChannelReaderSigner && !privateChannelReaderSignersByPubkey && !privateChannelSigner && !privateChannelSignersByPubkey) throw new ValidationError('PRIVATE_CHANNEL_READER_REQUIRED')
922
924
 
923
925
  const authors = privateChannelPubkeyList({ privateChannelPubkey, privateChannelPubkeys })
924
926
  const filter = { kinds: [PRIVATE_BROADCAST_KIND], since }
@@ -1,4 +1,5 @@
1
1
  import { bytesToBase64 } from '../../base64/index.js'
2
+ import { ValidationError } from '../../error/index.js'
2
3
  import { run } from '../../idb/index.js'
3
4
 
4
5
  export const DEFAULT_RECEIVED_CHUNK_TTL_MS = 60 * 60 * 1000 // 1 hour
@@ -106,7 +107,7 @@ function normalizeBytes (value) {
106
107
  if (value instanceof Uint8Array) return new Uint8Array(value)
107
108
  if (value instanceof ArrayBuffer) return new Uint8Array(value)
108
109
  if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength)
109
- throw new Error('RECEIVED_CHUNK_BYTES_REQUIRED')
110
+ throw new ValidationError('RECEIVED_CHUNK_BYTES_REQUIRED')
110
111
  }
111
112
 
112
113
  function uniq (values) {
@@ -362,9 +363,9 @@ export function createReceivedChunkStore ({
362
363
  }
363
364
 
364
365
  async function put ({ channelPubkey, routerPubkey, index, total, contentBytes, ttlMs }) {
365
- if (!channelPubkey || !routerPubkey) throw new Error('RECEIVED_CHUNK_GROUP_REQUIRED')
366
+ if (!channelPubkey || !routerPubkey) throw new ValidationError('RECEIVED_CHUNK_GROUP_REQUIRED')
366
367
  if (!Number.isSafeInteger(index) || !Number.isSafeInteger(total) || index < 0 || total < 1 || index >= total) {
367
- throw new Error('INVALID_RECEIVED_CHUNK_INDEX')
368
+ throw new ValidationError('INVALID_RECEIVED_CHUNK_INDEX')
368
369
  }
369
370
  const bytes = normalizeBytes(contentBytes)
370
371
  await ready()
@@ -1,4 +1,5 @@
1
- import { getEventHash, validateEvent, verifyEvent } from 'nostr-tools'
1
+ import { getEventHash, isSerializableEvent, isValidEvent } from '../event/index.js'
2
+ import { ValidationError } from '../error/index.js'
2
3
  import { generateKeypair } from '../key/index.js'
3
4
  import * as privateChannel from '../private-channel/index.js'
4
5
 
@@ -25,14 +26,14 @@ function uniq (values) {
25
26
  function normalizeDeletionPubkey (deletionPubkey) {
26
27
  if (deletionPubkey === undefined) return undefined
27
28
  if (typeof deletionPubkey !== 'string' || !HEX_PUBKEY.test(deletionPubkey)) {
28
- throw new Error('INVALID_DELETION_PUBKEY')
29
+ throw new ValidationError('INVALID_DELETION_PUBKEY')
29
30
  }
30
31
  return deletionPubkey.toLowerCase()
31
32
  }
32
33
 
33
34
  function resolveDeletionCapability ({ deletionPubkey, deletionSeckey, autoDeletionCapability = true }) {
34
- if (deletionSeckey !== undefined) throw new Error('DELETION_SECKEY_NOT_ACCEPTED')
35
- if (typeof autoDeletionCapability !== 'boolean') throw new Error('AUTO_DELETION_CAPABILITY_BOOLEAN_REQUIRED')
35
+ if (deletionSeckey !== undefined) throw new ValidationError('DELETION_SECKEY_NOT_ACCEPTED')
36
+ if (typeof autoDeletionCapability !== 'boolean') throw new ValidationError('AUTO_DELETION_CAPABILITY_BOOLEAN_REQUIRED')
36
37
 
37
38
  const normalizedDeletionPubkey = normalizeDeletionPubkey(deletionPubkey)
38
39
  if (normalizedDeletionPubkey) return { deletionPubkey: normalizedDeletionPubkey }
@@ -51,7 +52,7 @@ function withDelivery (result, reports, deletionSeckey) {
51
52
  }
52
53
  }
53
54
 
54
- function setEquals (a, b) {
55
+ function areSetsEqual (a, b) {
55
56
  if (a.size !== b.size) return false
56
57
  for (const value of a) if (!b.has(value)) return false
57
58
  return true
@@ -117,7 +118,7 @@ function cloneTags (tags) {
117
118
  }
118
119
 
119
120
  async function makeOutgoingRumor ({ senderSigner, rumor }) {
120
- if (!senderSigner?.getPublicKey) throw new Error('SENDER_SIGNER_REQUIRED')
121
+ if (!senderSigner?.getPublicKey) throw new ValidationError('SENDER_SIGNER_REQUIRED')
121
122
  const senderPubkey = await senderSigner.getPublicKey()
122
123
  // This is what gets sent. Id and pubkey are added later by recipient.
123
124
  const wireEvent = {
@@ -134,13 +135,13 @@ async function makeOutgoingRumor ({ senderSigner, rumor }) {
134
135
 
135
136
  function normalizeRumor (event, pubkey) {
136
137
  const normalized = { ...event, pubkey }
137
- if (!validateEvent(normalized)) throw new Error('INVALID_RUMOR')
138
+ if (!isSerializableEvent(normalized)) throw new ValidationError('INVALID_RUMOR')
138
139
  return { ...normalized, id: getEventHash(normalized) }
139
140
  }
140
141
 
141
142
  function assertValidSignedEvent (event) {
142
- if (!validateEvent(event) || event.id !== getEventHash(event) || !verifyEvent(event)) {
143
- throw new Error('INVALID_SIGNED_EVENT')
143
+ if (!isValidEvent(event)) {
144
+ throw new ValidationError('INVALID_SIGNED_EVENT')
144
145
  }
145
146
  return event
146
147
  }
@@ -150,7 +151,7 @@ function readTag (event, name) {
150
151
  }
151
152
 
152
153
  async function ownPrivateChannelPubkey (signer) {
153
- if (!signer?.getPublicKey) throw new Error('PRIVATE_CHANNEL_SIGNER_REQUIRED')
154
+ if (!signer?.getPublicKey) throw new ValidationError('PRIVATE_CHANNEL_SIGNER_REQUIRED')
154
155
  return signer.getPublicKey()
155
156
  }
156
157
 
@@ -268,8 +269,8 @@ function watchRevisionsForChannels (channels) {
268
269
  return Object.fromEntries(channels.map(channel => [channel, watchesByChannel.get(channel)?.revision || 0]))
269
270
  }
270
271
 
271
- function subscriptionMatches (current, channels) {
272
- if (!current || !setEquals(current.channels, channels)) return false
272
+ function doesSubscriptionMatch (current, channels) {
273
+ if (!current || !areSetsEqual(current.channels, channels)) return false
273
274
  for (const channel of channels) {
274
275
  if (current.revisions?.[channel] !== watchesByChannel.get(channel)?.revision) return false
275
276
  }
@@ -302,7 +303,7 @@ function rebuildSubscriptions ({ _subscribe = privateChannel.subscribe, graceful
302
303
 
303
304
  for (const [relay, current] of subsByRelay) {
304
305
  const nextChannels = desired.get(relay)
305
- if (nextChannels && subscriptionMatches(current, nextChannels)) continue
306
+ if (nextChannels && doesSubscriptionMatch(current, nextChannels)) continue
306
307
  if (!nextChannels) {
307
308
  const close = closeSubscription(current.sub, gracefulClose)
308
309
  if (close) closing.push(close)
@@ -312,7 +313,7 @@ function rebuildSubscriptions ({ _subscribe = privateChannel.subscribe, graceful
312
313
 
313
314
  for (const [relay, channels] of desired) {
314
315
  const current = subsByRelay.get(relay)
315
- if (subscriptionMatches(current, channels)) continue
316
+ if (doesSubscriptionMatch(current, channels)) continue
316
317
 
317
318
  const channelList = [...channels]
318
319
  const firstWatch = watchesByChannel.get(channelList[0])
@@ -394,7 +395,7 @@ export async function watch ({
394
395
  since = nowSeconds(),
395
396
  _subscribe = privateChannel.subscribe
396
397
  }) {
397
- if (!relays?.length) throw new Error('NO_RELAYS')
398
+ if (!relays?.length) throw new ValidationError('NO_RELAYS')
398
399
  const channelList = uniq(channels?.length ? channels : [await ownPrivateChannelPubkey(privateChannelSigner)])
399
400
  const ownPubkey = receiverPubkey || await receiverSigner?.getPublicKey?.()
400
401
  const callbacks = { onAsk, onReply, onTell, onYell, onNym, onMessage, onSeed, onChunk, onContentKeyUsage, onError }
@@ -419,7 +420,7 @@ export async function watch ({
419
420
  since
420
421
  }
421
422
  const current = watchesByChannel.get(channel)
422
- const sameSettings = Boolean(
423
+ const areSettingsEqual = Boolean(
423
424
  current &&
424
425
  current.receiverSigner === next.receiverSigner &&
425
426
  current.iykcSigner === next.iykcSigner &&
@@ -434,8 +435,8 @@ export async function watch ({
434
435
  current.ignoredGroupTtlMs === next.ignoredGroupTtlMs &&
435
436
  current.ignoredGroupMaxEntries === next.ignoredGroupMaxEntries
436
437
  )
437
- next.revision = sameSettings ? current.revision : nextWatchRevision++
438
- if (sameSettings && setEquals(new Set(current.relays), new Set(next.relays))) {
438
+ next.revision = areSettingsEqual ? current.revision : nextWatchRevision++
439
+ if (areSettingsEqual && areSetsEqual(new Set(current.relays), new Set(next.relays))) {
439
440
  current.callbacks = callbacks
440
441
  continue
441
442
  }
@@ -475,7 +476,7 @@ async function sendPrivateMessage ({
475
476
  _getIykcProofs,
476
477
  _publish = privateChannel.publish
477
478
  }) {
478
- if (!privateChannelSigner?.getPublicKey) throw new Error('PRIVATE_CHANNEL_WRITER_REQUIRED')
479
+ if (!privateChannelSigner?.getPublicKey) throw new ValidationError('PRIVATE_CHANNEL_WRITER_REQUIRED')
479
480
  return _publish({ senderSigner, imkcSigner, privateChannelSigner, privateChannelReaderPubkey, receivers, receiverTag, deletionPubkey, event, relays, relayToReceivers, recoveryRelays, expirationSeconds, temporaryStorageArea, _getIykcProofs })
480
481
  }
481
482
 
@@ -491,8 +492,8 @@ async function sendNymMessage ({
491
492
  deletionPubkey,
492
493
  _publish = privateChannel.publishNymEvent
493
494
  }) {
494
- if (!nymSigner?.getPublicKey) throw new Error('NYM_SIGNER_REQUIRED')
495
- if (!privateChannelSigner?.getPublicKey) throw new Error('PRIVATE_CHANNEL_WRITER_REQUIRED')
495
+ if (!nymSigner?.getPublicKey) throw new ValidationError('NYM_SIGNER_REQUIRED')
496
+ if (!privateChannelSigner?.getPublicKey) throw new ValidationError('PRIVATE_CHANNEL_WRITER_REQUIRED')
496
497
  return _publish({ nymSigner, privateChannelSigner, privateChannelReaderPubkey, deletionPubkey, event, relays, relayToReceivers, recoveryRelays, expirationSeconds })
497
498
  }
498
499
 
@@ -518,8 +519,8 @@ export async function ask ({
518
519
  autoDeletionCapability = true,
519
520
  _publish = privateChannel.publish
520
521
  }) {
521
- if (!receiverPubkey) throw new Error('RECEIVER_PUBKEY_REQUIRED')
522
- if (!privateChannelSigner?.getPublicKey) throw new Error('PRIVATE_CHANNEL_WRITER_REQUIRED')
522
+ if (!receiverPubkey) throw new ValidationError('RECEIVER_PUBKEY_REQUIRED')
523
+ if (!privateChannelSigner?.getPublicKey) throw new ValidationError('PRIVATE_CHANNEL_WRITER_REQUIRED')
523
524
  const privateChannelPubkey = await ownPrivateChannelPubkey(privateChannelSigner)
524
525
  assertWatching(privateChannelPubkey)
525
526
 
@@ -560,8 +561,8 @@ export async function reply ({
560
561
  autoDeletionCapability = true,
561
562
  _publish = privateChannel.publish
562
563
  }) {
563
- if (!question?.id) throw new Error('QUESTION_REQUIRED')
564
- if (!receiverPubkey) throw new Error('RECEIVER_PUBKEY_REQUIRED')
564
+ if (!question?.id) throw new ValidationError('QUESTION_REQUIRED')
565
+ if (!receiverPubkey) throw new ValidationError('RECEIVER_PUBKEY_REQUIRED')
565
566
  const { event, wireEvent } = await makeOutgoingRumor({
566
567
  senderSigner,
567
568
  rumor: makeMessageRumor({
@@ -597,7 +598,7 @@ export async function tell ({
597
598
  autoDeletionCapability = true,
598
599
  _publish = privateChannel.publish
599
600
  }) {
600
- if (!receiverPubkey) throw new Error('RECEIVER_PUBKEY_REQUIRED')
601
+ if (!receiverPubkey) throw new ValidationError('RECEIVER_PUBKEY_REQUIRED')
601
602
  const { event, wireEvent } = await makeOutgoingRumor({
602
603
  senderSigner,
603
604
  rumor: makeMessageRumor({
@@ -634,7 +635,7 @@ export async function yell ({
634
635
  _publish = privateChannel.publish
635
636
  }) {
636
637
  const receivers = uniq(receiverPubkeys)
637
- if (!receivers.length) throw new Error('NO_RECEIVERS')
638
+ if (!receivers.length) throw new ValidationError('NO_RECEIVERS')
638
639
  const { event, wireEvent } = await makeOutgoingRumor({
639
640
  senderSigner,
640
641
  rumor: makeMessageRumor({
@@ -667,7 +668,7 @@ export async function broadcastRumor ({
667
668
  _publish = privateChannel.publish
668
669
  }) {
669
670
  const receivers = uniq(receiverPubkeys)
670
- if (!receivers.length) throw new Error('NO_RECEIVERS')
671
+ if (!receivers.length) throw new ValidationError('NO_RECEIVERS')
671
672
  const { event, wireEvent } = await makeOutgoingRumor({ senderSigner, rumor })
672
673
  const deletion = resolveDeletionCapability({ deletionPubkey, deletionSeckey, autoDeletionCapability })
673
674
  const reports = await sendPrivateMessage({ senderSigner, imkcSigner, privateChannelSigner, privateChannelReaderPubkey, receivers, receiverTag: '', deletionPubkey: deletion.deletionPubkey, event: wireEvent, relays, relayToReceivers, recoveryRelays, expirationSeconds, temporaryStorageArea, _getIykcProofs, _publish })
@@ -693,7 +694,7 @@ export async function broadcastEvent ({
693
694
  _publish = privateChannel.publish
694
695
  }) {
695
696
  const receivers = uniq(receiverPubkeys)
696
- if (!receivers.length) throw new Error('NO_RECEIVERS')
697
+ if (!receivers.length) throw new ValidationError('NO_RECEIVERS')
697
698
  const wireEvent = assertValidSignedEvent({ ...event, tags: cloneTags(event?.tags) })
698
699
  const deletion = resolveDeletionCapability({ deletionPubkey, deletionSeckey, autoDeletionCapability })
699
700
  const reports = await sendPrivateMessage({ senderSigner, imkcSigner, privateChannelSigner, privateChannelReaderPubkey, receivers, receiverTag: '', deletionPubkey: deletion.deletionPubkey, event: wireEvent, relays, relayToReceivers, recoveryRelays, expirationSeconds, temporaryStorageArea, _getIykcProofs, _publish })
@@ -714,7 +715,7 @@ export async function broadcastNymRumor ({
714
715
  autoDeletionCapability = true,
715
716
  _publish = privateChannel.publishNymEvent
716
717
  }) {
717
- if (!nymSigner?.getPublicKey) throw new Error('NYM_SIGNER_REQUIRED')
718
+ if (!nymSigner?.getPublicKey) throw new ValidationError('NYM_SIGNER_REQUIRED')
718
719
  const { event, wireEvent } = await makeOutgoingRumor({ senderSigner: nymSigner, rumor })
719
720
  const deletion = resolveDeletionCapability({ deletionPubkey, deletionSeckey, autoDeletionCapability })
720
721
  const reports = await sendNymMessage({ nymSigner, privateChannelSigner, privateChannelReaderPubkey, deletionPubkey: deletion.deletionPubkey, event: wireEvent, relays, relayToReceivers, recoveryRelays, expirationSeconds, _publish })
@@ -735,7 +736,7 @@ export async function broadcastNymEvent ({
735
736
  autoDeletionCapability = true,
736
737
  _publish = privateChannel.publishNymEvent
737
738
  }) {
738
- if (!nymSigner?.getPublicKey) throw new Error('NYM_SIGNER_REQUIRED')
739
+ if (!nymSigner?.getPublicKey) throw new ValidationError('NYM_SIGNER_REQUIRED')
739
740
  const wireEvent = assertValidSignedEvent({ ...event, tags: cloneTags(event?.tags) })
740
741
  const deletion = resolveDeletionCapability({ deletionPubkey, deletionSeckey, autoDeletionCapability })
741
742
  const reports = await sendNymMessage({ nymSigner, privateChannelSigner, privateChannelReaderPubkey, deletionPubkey: deletion.deletionPubkey, event: wireEvent, relays, relayToReceivers, recoveryRelays, expirationSeconds, _publish })