@bsv/message-box-client 2.0.4 → 2.0.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/message-box-client",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -83,6 +83,6 @@
83
83
  },
84
84
  "dependencies": {
85
85
  "@bsv/authsocket-client": "^2.0.2",
86
- "@bsv/sdk": "^2.0.4"
86
+ "@bsv/sdk": "^2.0.11"
87
87
  }
88
88
  }
@@ -38,8 +38,8 @@ import {
38
38
  ProtoWallet,
39
39
  InternalizeOutput,
40
40
  Random,
41
- OriginatorDomainNameStringUnder250Bytes
42
-
41
+ OriginatorDomainNameStringUnder250Bytes,
42
+ Beef,
43
43
  } from '@bsv/sdk'
44
44
  import { AuthSocketClient } from '@bsv/authsocket-client'
45
45
  import * as Logger from './Utils/logger.js'
@@ -123,7 +123,7 @@ export class MessageBoxClient {
123
123
  * })
124
124
  * await client.init()
125
125
  */
126
- constructor (options: MessageBoxClientOptions = {}) {
126
+ constructor(options: MessageBoxClientOptions = {}) {
127
127
  const {
128
128
  host,
129
129
  walletClient,
@@ -175,7 +175,7 @@ export class MessageBoxClient {
175
175
  * await client.init()
176
176
  * await client.sendMessage({ recipient, messageBox: 'inbox', body: 'Hello' })
177
177
  */
178
- async init (targetHost: string = this.host): Promise<void> {
178
+ async init(targetHost: string = this.host): Promise<void> {
179
179
  const normalizedHost = targetHost?.trim()
180
180
  if (normalizedHost === '') {
181
181
  throw new Error('Cannot anoint host: No valid host provided')
@@ -220,7 +220,7 @@ export class MessageBoxClient {
220
220
  *
221
221
  * Used automatically by all public methods that require initialization.
222
222
  */
223
- private async assertInitialized (): Promise<void> {
223
+ private async assertInitialized(): Promise<void> {
224
224
  if (!this.initialized || this.host == null || this.host.trim() === '') {
225
225
  await this.init()
226
226
  }
@@ -233,7 +233,7 @@ export class MessageBoxClient {
233
233
  * Returns a live list of WebSocket rooms the client is subscribed to.
234
234
  * Useful for inspecting state or ensuring no duplicates are joined.
235
235
  */
236
- public getJoinedRooms (): Set<string> {
236
+ public getJoinedRooms(): Set<string> {
237
237
  return this.joinedRooms
238
238
  }
239
239
 
@@ -245,7 +245,7 @@ export class MessageBoxClient {
245
245
  * Returns the client's identity key, used for signing, encryption, and addressing.
246
246
  * If not already loaded, it will fetch and cache it.
247
247
  */
248
- public async getIdentityKey (): Promise<string> {
248
+ public async getIdentityKey(): Promise<string> {
249
249
  if (this.myIdentityKey != null && this.myIdentityKey.trim() !== '') {
250
250
  return this.myIdentityKey
251
251
  }
@@ -273,7 +273,7 @@ export class MessageBoxClient {
273
273
  * Note: Do not interact with the socket directly unless necessary.
274
274
  * Use the provided `sendLiveMessage`, `listenForLiveMessages`, and related methods.
275
275
  */
276
- public get testSocket (): ReturnType<typeof AuthSocketClient> | undefined {
276
+ public get testSocket(): ReturnType<typeof AuthSocketClient> | undefined {
277
277
  return this.socket
278
278
  }
279
279
 
@@ -301,7 +301,7 @@ export class MessageBoxClient {
301
301
  * await mb.initializeConnection()
302
302
  * // WebSocket is now ready for use
303
303
  */
304
- async initializeConnection (overrideHost?: string): Promise<void> {
304
+ async initializeConnection(overrideHost?: string): Promise<void> {
305
305
  Logger.log('[MB CLIENT] initializeConnection() STARTED')
306
306
 
307
307
  if (this.myIdentityKey == null || this.myIdentityKey.trim() === '') {
@@ -461,7 +461,7 @@ export class MessageBoxClient {
461
461
  * @example
462
462
  * const host = await resolveHostForRecipient('028d...') // → returns either overlay host or this.host
463
463
  */
464
- async resolveHostForRecipient (identityKey: string): Promise<string> {
464
+ async resolveHostForRecipient(identityKey: string): Promise<string> {
465
465
  const advertisementTokens = await this.queryAdvertisements(identityKey, undefined)
466
466
  if (advertisementTokens.length === 0) {
467
467
  Logger.warn(`[MB CLIENT] No advertisements for ${identityKey}, using default host ${this.host}`)
@@ -479,7 +479,7 @@ export class MessageBoxClient {
479
479
  * @param host? if passed, only look for adverts anointed at that host
480
480
  * @returns 0-length array if nothing valid was found
481
481
  */
482
- async queryAdvertisements (
482
+ async queryAdvertisements(
483
483
  identityKey?: string,
484
484
  host?: string
485
485
  ): Promise<AdvertisementToken[]> {
@@ -565,7 +565,7 @@ export class MessageBoxClient {
565
565
  * await client.joinRoom('payment_inbox')
566
566
  * // Now listening for real-time messages in room '028d...-payment_inbox'
567
567
  */
568
- async joinRoom (messageBox: string, overrideHost?: string): Promise<void> {
568
+ async joinRoom(messageBox: string, overrideHost?: string): Promise<void> {
569
569
  Logger.log(`[MB CLIENT] Attempting to join WebSocket room: ${messageBox}`)
570
570
 
571
571
  // Ensure WebSocket connection is established first
@@ -623,7 +623,7 @@ export class MessageBoxClient {
623
623
  * onMessage: (msg) => console.log('Received live message:', msg)
624
624
  * })
625
625
  */
626
- async listenForLiveMessages ({
626
+ async listenForLiveMessages({
627
627
  onMessage,
628
628
  messageBox,
629
629
  overrideHost
@@ -726,7 +726,7 @@ export class MessageBoxClient {
726
726
  * body: { amount: 1000 }
727
727
  * })
728
728
  */
729
- async sendLiveMessage ({
729
+ async sendLiveMessage({
730
730
  recipient,
731
731
  messageBox,
732
732
  body,
@@ -888,7 +888,7 @@ export class MessageBoxClient {
888
888
  * @example
889
889
  * await client.leaveRoom('payment_inbox')
890
890
  */
891
- async leaveRoom (messageBox: string): Promise<void> {
891
+ async leaveRoom(messageBox: string): Promise<void> {
892
892
  await this.assertInitialized()
893
893
  if (this.socket == null) {
894
894
  Logger.warn('[MB CLIENT] Attempted to leave a room but WebSocket is not connected.')
@@ -920,7 +920,7 @@ export class MessageBoxClient {
920
920
  * @example
921
921
  * await client.disconnectWebSocket()
922
922
  */
923
- async disconnectWebSocket (): Promise<void> {
923
+ async disconnectWebSocket(): Promise<void> {
924
924
  await this.assertInitialized()
925
925
  if (this.socket != null) {
926
926
  Logger.log('[MB CLIENT] Closing WebSocket connection...')
@@ -958,7 +958,7 @@ export class MessageBoxClient {
958
958
  * body: { type: 'ping' }
959
959
  * })
960
960
  */
961
- async sendMessage (
961
+ async sendMessage(
962
962
  message: SendMessageParams,
963
963
  overrideHost?: string
964
964
  ): Promise<SendMessageResponse> {
@@ -1104,7 +1104,7 @@ export class MessageBoxClient {
1104
1104
  * - compute per-recipient payment
1105
1105
  * Then sends to the allowed recipients with payment attached.
1106
1106
  */
1107
- async sendMesagetoRecepients (
1107
+ async sendMesagetoRecepients(
1108
1108
  params: SendListParams,
1109
1109
  overrideHost?: string
1110
1110
  ): Promise<SendListResult> {
@@ -1289,41 +1289,65 @@ export class MessageBoxClient {
1289
1289
  * @example
1290
1290
  * const { txid } = await client.anointHost('https://my-messagebox.io')
1291
1291
  */
1292
- async anointHost (host: string): Promise<{ txid: string }> {
1292
+ async anointHost(host: string): Promise<{ txid: string }> {
1293
1293
  Logger.log('[MB CLIENT] Starting anointHost...')
1294
- try {
1295
- if (!host.startsWith('http')) {
1296
- throw new Error('Invalid host URL')
1297
- }
1298
-
1299
- const identityKey = await this.getIdentityKey()
1294
+ if (!host.startsWith('http')) throw new Error('Invalid host URL')
1300
1295
 
1301
- Logger.log('[MB CLIENT] Fields - Identity:', identityKey, 'Host:', host)
1302
-
1303
- const fields: number[][] = [
1304
- Utils.toArray(identityKey, 'hex'),
1305
- Utils.toArray(host, 'utf8')
1306
- ]
1307
-
1308
- const pushdrop = new PushDrop(this.walletClient, this.originator)
1309
- Logger.log('Fields:', fields.map(a => Utils.toHex(a)))
1310
- Logger.log('ProtocolID:', [1, 'messagebox advertisement'])
1311
- Logger.log('KeyID:', '1')
1312
- Logger.log('SignAs:', 'self')
1313
- Logger.log('anyoneCanSpend:', false)
1314
- Logger.log('forSelf:', true)
1315
- const script = await pushdrop.lock(
1316
- fields,
1317
- [1, 'messagebox advertisement'],
1318
- '1',
1319
- 'anyone',
1320
- true
1321
- )
1296
+ const identityKey = await this.getIdentityKey()
1297
+ const overlayTokens = await this.queryAdvertisements(identityKey)
1298
+ Logger.log(`[MB CLIENT] Found ${overlayTokens.length} existing advertisement(s) on overlay`)
1299
+
1300
+ // Fetch ALL spendable wallet basket outputs and cross-reference with overlay tokens.
1301
+ // Only overlay tokens the wallet considers spendable are safe to spend as inputs.
1302
+ // This prevents stale overlay tokens (spent externally) from breaking the combined tx.
1303
+ const basketResult = await this.walletClient.listOutputs({
1304
+ basket: 'overlay advertisements',
1305
+ limit: 10000
1306
+ }, this.originator)
1307
+ const spendableOutpoints = new Set(
1308
+ basketResult.outputs.filter(o => o.spendable).map(o => o.outpoint)
1309
+ )
1310
+ const tokensToSpend = overlayTokens.filter(t => spendableOutpoints.has(`${t.txid}.${t.outputIndex}`))
1311
+ const skipped = overlayTokens.length - tokensToSpend.length
1312
+ if (skipped > 0) {
1313
+ Logger.log(`[MB CLIENT] Skipping ${skipped} overlay token(s) not in spendable wallet basket`)
1314
+ }
1315
+ Logger.log(`[MB CLIENT] Revoking ${tokensToSpend.length} spendable token(s) in combined tx`)
1316
+
1317
+ const fields: number[][] = [
1318
+ Utils.toArray(identityKey, 'hex'),
1319
+ Utils.toArray(host, 'utf8')
1320
+ ]
1321
+ const pushdrop = new PushDrop(this.walletClient, this.originator)
1322
+ const script = await pushdrop.lock(
1323
+ fields,
1324
+ [1, 'messagebox advertisement'],
1325
+ '1',
1326
+ 'anyone',
1327
+ true
1328
+ )
1329
+ Logger.log('[MB CLIENT] PushDrop script:', script.toASM())
1322
1330
 
1323
- Logger.log('[MB CLIENT] PushDrop script:', script.toASM())
1331
+ try {
1332
+ let inputBEEF: number[] | undefined
1333
+ if (tokensToSpend.length > 0) {
1334
+ const mergedBeef = Beef.fromBinary(tokensToSpend[0].beef)
1335
+ for (let i = 1; i < tokensToSpend.length; i++) {
1336
+ mergedBeef.mergeBeef(Beef.fromBinary(tokensToSpend[i].beef))
1337
+ }
1338
+ inputBEEF = mergedBeef.toBinary()
1339
+ }
1324
1340
 
1325
- const { tx, txid } = await this.walletClient.createAction({
1341
+ const { signableTransaction, tx: directTx, txid: directTxid } = await this.walletClient.createAction({
1326
1342
  description: 'Anoint host for overlay routing',
1343
+ ...(inputBEEF !== undefined && {
1344
+ inputBEEF,
1345
+ inputs: tokensToSpend.map(token => ({
1346
+ outpoint: `${token.txid}.${token.outputIndex}`,
1347
+ unlockingScriptLength: 73,
1348
+ inputDescription: `Revoking advertisement for ${token.host}`
1349
+ }))
1350
+ }),
1327
1351
  outputs: [{
1328
1352
  basket: 'overlay advertisements',
1329
1353
  lockingScript: script.toHex(),
@@ -1333,24 +1357,51 @@ export class MessageBoxClient {
1333
1357
  options: { randomizeOutputs: false, acceptDelayedBroadcast: false }
1334
1358
  }, this.originator)
1335
1359
 
1336
- Logger.log('[MB CLIENT] Transaction created:', txid)
1360
+ if (signableTransaction === undefined) {
1361
+ if (directTx === undefined) throw new Error('Anoint failed: no transaction returned')
1362
+ Logger.log('[MB CLIENT] Transaction created (no inputs to sign):', directTxid)
1363
+ const broadcaster = new TopicBroadcaster(['tm_messagebox'], { networkPreset: this.networkPreset })
1364
+ const result = await broadcaster.broadcast(Transaction.fromAtomicBEEF(directTx))
1365
+ Logger.log('[MB CLIENT] Advertisement broadcast succeeded. TXID:', result.txid)
1366
+ if (typeof result.txid !== 'string') throw new Error('Anoint failed: broadcast did not return a txid')
1367
+ return { txid: result.txid }
1368
+ }
1337
1369
 
1338
- if (tx !== undefined) {
1339
- const broadcaster = new TopicBroadcaster(['tm_messagebox'], {
1340
- networkPreset: this.networkPreset
1341
- })
1370
+ const partialTx = Transaction.fromAtomicBEEF(signableTransaction.tx)
1371
+ const spends: Record<number, { unlockingScript: string }> = {}
1372
+
1373
+ for (let i = 0; i < tokensToSpend.length; i++) {
1374
+ const token = tokensToSpend[i]
1375
+ const sourceTx = Transaction.fromBEEF(token.beef)
1376
+ const sourceSatoshis = sourceTx.outputs[token.outputIndex]?.satoshis ?? 1
1377
+ const unlocker = pushdrop.unlock(
1378
+ [1, 'messagebox advertisement'],
1379
+ '1',
1380
+ 'anyone',
1381
+ 'all',
1382
+ false,
1383
+ sourceSatoshis,
1384
+ token.lockingScript
1385
+ )
1386
+ const finalUnlockScript = await unlocker.sign(partialTx, i)
1387
+ spends[i] = { unlockingScript: finalUnlockScript.toHex() }
1388
+ }
1342
1389
 
1343
- const result = await broadcaster.broadcast(Transaction.fromAtomicBEEF(tx))
1344
- Logger.log('[MB CLIENT] Advertisement broadcast succeeded. TXID:', result.txid)
1390
+ const { tx: signedTx, txid: signedTxid } = await this.walletClient.signAction({
1391
+ reference: signableTransaction.reference,
1392
+ spends,
1393
+ options: { acceptDelayedBroadcast: false }
1394
+ }, this.originator)
1345
1395
 
1346
- if (typeof result.txid !== 'string') {
1347
- throw new Error('Anoint failed: broadcast did not return a txid')
1348
- }
1396
+ if (signedTx === undefined) throw new Error('Anoint failed: signing did not return a transaction')
1397
+ Logger.log('[MB CLIENT] Transaction created:', signedTxid)
1349
1398
 
1350
- return { txid: result.txid }
1351
- }
1399
+ const broadcaster = new TopicBroadcaster(['tm_messagebox'], { networkPreset: this.networkPreset })
1400
+ const result = await broadcaster.broadcast(Transaction.fromAtomicBEEF(signedTx))
1401
+ Logger.log('[MB CLIENT] Advertisement broadcast succeeded. TXID:', result.txid)
1352
1402
 
1353
- throw new Error('Anoint failed: failed to create action!')
1403
+ if (typeof result.txid !== 'string') throw new Error('Anoint failed: broadcast did not return a txid')
1404
+ return { txid: result.txid }
1354
1405
  } catch (err) {
1355
1406
  Logger.error('[MB CLIENT ERROR] anointHost threw:', err)
1356
1407
  throw err
@@ -1371,7 +1422,7 @@ export class MessageBoxClient {
1371
1422
  * @example
1372
1423
  * const { txid } = await client.revokeHost('https://my-messagebox.io')
1373
1424
  */
1374
- async revokeHostAdvertisement (advertisementToken: AdvertisementToken): Promise<{ txid: string }> {
1425
+ async revokeHostAdvertisement(advertisementToken: AdvertisementToken): Promise<{ txid: string }> {
1375
1426
  Logger.log('[MB CLIENT] Starting revokeHost...')
1376
1427
  const outpoint = `${advertisementToken.txid}.${advertisementToken.outputIndex}`
1377
1428
  try {
@@ -1391,28 +1442,32 @@ export class MessageBoxClient {
1391
1442
  throw new Error('Failed to create signable transaction.')
1392
1443
  }
1393
1444
 
1394
- const partialTx = Transaction.fromBEEF(signableTransaction.tx)
1445
+ const partialTx = Transaction.fromAtomicBEEF(signableTransaction.tx)
1446
+
1447
+ // Get the source satoshis from the BEEF so the sighash preimage is correct
1448
+ const sourceTx = Transaction.fromBEEF(advertisementToken.beef)
1449
+ const sourceSatoshis = sourceTx.outputs[advertisementToken.outputIndex]?.satoshis ?? 1
1395
1450
 
1396
1451
  // Prepare the unlocker
1397
1452
  const pushdrop = new PushDrop(this.walletClient, this.originator)
1398
- const unlocker = await pushdrop.unlock(
1453
+ const unlocker = pushdrop.unlock(
1399
1454
  [1, 'messagebox advertisement'],
1400
1455
  '1',
1401
1456
  'anyone',
1402
1457
  'all',
1403
1458
  false,
1404
- advertisementToken.outputIndex,
1459
+ sourceSatoshis,
1405
1460
  advertisementToken.lockingScript
1406
1461
  )
1407
1462
 
1408
1463
  // Convert to Transaction, apply signature
1409
- const finalUnlockScript = await unlocker.sign(partialTx, advertisementToken.outputIndex)
1464
+ const finalUnlockScript = await unlocker.sign(partialTx, 0)
1410
1465
 
1411
1466
  // Complete signing with the final unlock script
1412
1467
  const { tx: signedTx } = await this.walletClient.signAction({
1413
1468
  reference: signableTransaction.reference,
1414
1469
  spends: {
1415
- [advertisementToken.outputIndex]: {
1470
+ 0: {
1416
1471
  unlockingScript: finalUnlockScript.toHex()
1417
1472
  }
1418
1473
  },
@@ -1474,7 +1529,7 @@ export class MessageBoxClient {
1474
1529
  * messages.forEach(msg => console.log(msg.sender, msg.body))
1475
1530
  * // Payments included with messages are automatically received
1476
1531
  */
1477
- async listMessages ({ messageBox, host, acceptPayments }: ListMessagesParams): Promise<PeerMessage[]> {
1532
+ async listMessages({ messageBox, host, acceptPayments }: ListMessagesParams): Promise<PeerMessage[]> {
1478
1533
  if (typeof acceptPayments !== 'boolean') {
1479
1534
  acceptPayments = true
1480
1535
  }
@@ -1689,7 +1744,7 @@ export class MessageBoxClient {
1689
1744
  * })
1690
1745
  * console.log(messages)
1691
1746
  */
1692
- async listMessagesLite ({ messageBox, host }: ListMessagesParams): Promise<PeerMessage[]> {
1747
+ async listMessagesLite({ messageBox, host }: ListMessagesParams): Promise<PeerMessage[]> {
1693
1748
  const res = await this.authFetch.fetch(`${host as string}/listMessages`, {
1694
1749
  method: 'POST',
1695
1750
  headers: { 'Content-Type': 'application/json' },
@@ -1769,7 +1824,7 @@ export class MessageBoxClient {
1769
1824
  * tryParse('{"hello":"world"}') // → { hello: "world" }
1770
1825
  * tryParse('plain text') // → "plain text"
1771
1826
  */
1772
- tryParse (raw: string): any {
1827
+ tryParse(raw: string): any {
1773
1828
  try {
1774
1829
  return JSON.parse(raw)
1775
1830
  } catch {
@@ -1826,7 +1881,7 @@ export class MessageBoxClient {
1826
1881
  * const success = await client.acknowledgeNotification(message)
1827
1882
  * console.log(success ? 'Payment received' : 'No payment or failed')
1828
1883
  */
1829
- async acknowledgeNotification (message: PeerMessage): Promise<boolean> {
1884
+ async acknowledgeNotification(message: PeerMessage): Promise<boolean> {
1830
1885
  await this.acknowledgeMessage({ messageIds: [message.messageId] })
1831
1886
 
1832
1887
  const parsedBody: unknown =
@@ -1915,7 +1970,7 @@ export class MessageBoxClient {
1915
1970
  * @example
1916
1971
  * await client.acknowledgeMessage({ messageIds: ['msg123', 'msg456'] })
1917
1972
  */
1918
- async acknowledgeMessage ({ messageIds, host }: AcknowledgeMessageParams): Promise<string> {
1973
+ async acknowledgeMessage({ messageIds, host }: AcknowledgeMessageParams): Promise<string> {
1919
1974
  if (!Array.isArray(messageIds) || messageIds.length === 0) {
1920
1975
  throw new Error('Message IDs array cannot be empty')
1921
1976
  }
@@ -1997,7 +2052,7 @@ export class MessageBoxClient {
1997
2052
  * recipientFee: -1
1998
2053
  * })
1999
2054
  */
2000
- async setMessageBoxPermission (
2055
+ async setMessageBoxPermission(
2001
2056
  params: SetMessageBoxPermissionParams,
2002
2057
  overrideHost?: string
2003
2058
  ): Promise<void> {
@@ -2044,7 +2099,7 @@ export class MessageBoxClient {
2044
2099
  * sender: '03abc123...'
2045
2100
  * })
2046
2101
  */
2047
- async getMessageBoxPermission (
2102
+ async getMessageBoxPermission(
2048
2103
  params: GetMessageBoxPermissionParams,
2049
2104
  overrideHost?: string
2050
2105
  ): Promise<MessageBoxPermission | null> {
@@ -2089,7 +2144,7 @@ export class MessageBoxClient {
2089
2144
  * messageBox: 'notifications'
2090
2145
  * })
2091
2146
  */
2092
- async getMessageBoxQuote (
2147
+ async getMessageBoxQuote(
2093
2148
  params: GetQuoteParams,
2094
2149
  overrideHost?: string
2095
2150
  ): Promise<MessageBoxQuote | MessageBoxMultiQuote> {
@@ -2282,7 +2337,7 @@ export class MessageBoxClient {
2282
2337
  * offset: 0
2283
2338
  * })
2284
2339
  */
2285
- async listMessageBoxPermissions (params?: ListPermissionsParams, overrideHost?: string): Promise<MessageBoxPermission[]> {
2340
+ async listMessageBoxPermissions(params?: ListPermissionsParams, overrideHost?: string): Promise<MessageBoxPermission[]> {
2286
2341
  const finalHost = overrideHost ?? this.host
2287
2342
  const queryParams = new URLSearchParams()
2288
2343
 
@@ -2341,7 +2396,7 @@ export class MessageBoxClient {
2341
2396
  * await client.allowNotificationsFromPeer('03abc123...') // Always allow
2342
2397
  * await client.allowNotificationsFromPeer('03def456...', 5) // Allow for 5 sats
2343
2398
  */
2344
- async allowNotificationsFromPeer (identityKey: PubKeyHex, recipientFee: number = 0, overrideHost?: string): Promise<void> {
2399
+ async allowNotificationsFromPeer(identityKey: PubKeyHex, recipientFee: number = 0, overrideHost?: string): Promise<void> {
2345
2400
  await this.setMessageBoxPermission({
2346
2401
  messageBox: 'notifications',
2347
2402
  sender: identityKey,
@@ -2361,7 +2416,7 @@ export class MessageBoxClient {
2361
2416
  * @example
2362
2417
  * await client.denyNotificationsFromPeer('03spam123...')
2363
2418
  */
2364
- async denyNotificationsFromPeer (identityKey: PubKeyHex, overrideHost?: string): Promise<void> {
2419
+ async denyNotificationsFromPeer(identityKey: PubKeyHex, overrideHost?: string): Promise<void> {
2365
2420
  await this.setMessageBoxPermission({
2366
2421
  messageBox: 'notifications',
2367
2422
  sender: identityKey,
@@ -2382,7 +2437,7 @@ export class MessageBoxClient {
2382
2437
  * const status = await client.checkPeerNotificationStatus('03abc123...')
2383
2438
  * console.log(status.allowed) // true/false
2384
2439
  */
2385
- async checkPeerNotificationStatus (identityKey: PubKeyHex, overrideHost?: string): Promise<MessageBoxPermission | null> {
2440
+ async checkPeerNotificationStatus(identityKey: PubKeyHex, overrideHost?: string): Promise<MessageBoxPermission | null> {
2386
2441
  const myIdentityKey = await this.getIdentityKey()
2387
2442
  return await this.getMessageBoxPermission({
2388
2443
  recipient: myIdentityKey,
@@ -2402,7 +2457,7 @@ export class MessageBoxClient {
2402
2457
  * @example
2403
2458
  * const notifications = await client.listPeerNotifications()
2404
2459
  */
2405
- async listPeerNotifications (overrideHost?: string): Promise<MessageBoxPermission[]> {
2460
+ async listPeerNotifications(overrideHost?: string): Promise<MessageBoxPermission[]> {
2406
2461
  return await this.listMessageBoxPermissions({ messageBox: 'notifications' }, overrideHost)
2407
2462
  }
2408
2463
 
@@ -2425,7 +2480,7 @@ export class MessageBoxClient {
2425
2480
  * // Send with maximum payment limit for safety
2426
2481
  * await client.sendNotification('03def456...', { title: 'Alert', body: 'Important update' }, 50)
2427
2482
  */
2428
- async sendNotification (
2483
+ async sendNotification(
2429
2484
  recipient: PubKeyHex | PubKeyHex[],
2430
2485
  body: string | object,
2431
2486
  overrideHost?: string
@@ -2469,7 +2524,7 @@ export class MessageBoxClient {
2469
2524
  * deviceId: 'iPhone15Pro'
2470
2525
  * })
2471
2526
  */
2472
- async registerDevice (
2527
+ async registerDevice(
2473
2528
  params: DeviceRegistrationParams,
2474
2529
  overrideHost?: string
2475
2530
  ): Promise<DeviceRegistrationResponse> {
@@ -2534,7 +2589,7 @@ export class MessageBoxClient {
2534
2589
  * console.log(`Device: ${device.platform} - ${device.fcmToken}`)
2535
2590
  * })
2536
2591
  */
2537
- async listRegisteredDevices (
2592
+ async listRegisteredDevices(
2538
2593
  overrideHost?: string
2539
2594
  ): Promise<RegisteredDevice[]> {
2540
2595
  const finalHost = overrideHost ?? this.host
@@ -2564,7 +2619,7 @@ export class MessageBoxClient {
2564
2619
  // PRIVATE HELPER METHODS
2565
2620
  // ===========================
2566
2621
 
2567
- private static getStatusFromFee (fee: number): 'always_allow' | 'blocked' | 'payment_required' {
2622
+ private static getStatusFromFee(fee: number): 'always_allow' | 'blocked' | 'payment_required' {
2568
2623
  if (fee === -1) return 'blocked'
2569
2624
  if (fee === 0) return 'always_allow'
2570
2625
  return 'payment_required'
@@ -2596,7 +2651,7 @@ export class MessageBoxClient {
2596
2651
  * const payment = await client.createMessagePayment(recipientKey, quote)
2597
2652
  * await client.sendMessage({ recipient, messageBox, body, payment })
2598
2653
  */
2599
- private async createMessagePayment (
2654
+ private async createMessagePayment(
2600
2655
  recipient: string,
2601
2656
  quote: MessageBoxQuote,
2602
2657
  description: string = 'MessageBox delivery payment'
@@ -2713,7 +2768,7 @@ export class MessageBoxClient {
2713
2768
  }
2714
2769
  }
2715
2770
 
2716
- private async createMessagePaymentBatch (
2771
+ private async createMessagePaymentBatch(
2717
2772
  recipients: string[],
2718
2773
  perRecipientQuotes: Map<string, { recipientFee: number, deliveryFee: number }>,
2719
2774
  // server (delivery agent) identity key to pay the delivery fee to