@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/dist/cjs/package.json +2 -2
- package/dist/cjs/src/MessageBoxClient.js +82 -31
- package/dist/cjs/src/MessageBoxClient.js.map +1 -1
- package/dist/cjs/src/PeerPayClient.js +58 -57
- package/dist/cjs/src/PeerPayClient.js.map +1 -1
- package/dist/cjs/src/__tests/MessageBoxClient.test.js +90 -0
- package/dist/cjs/src/__tests/MessageBoxClient.test.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/MessageBoxClient.js +81 -32
- package/dist/esm/src/MessageBoxClient.js.map +1 -1
- package/dist/esm/src/PeerPayClient.js +59 -57
- package/dist/esm/src/PeerPayClient.js.map +1 -1
- package/dist/esm/src/__tests/MessageBoxClient.test.js +91 -1
- package/dist/esm/src/__tests/MessageBoxClient.test.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/MessageBoxClient.d.ts.map +1 -1
- package/dist/types/src/PeerPayClient.d.ts +1 -0
- package/dist/types/src/PeerPayClient.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +1 -1
- package/package.json +2 -2
- package/src/MessageBoxClient.ts +141 -86
- package/src/PeerPayClient.ts +69 -63
- package/src/__tests/MessageBoxClient.test.ts +129 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bsv/message-box-client",
|
|
3
|
-
"version": "2.0.
|
|
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.
|
|
86
|
+
"@bsv/sdk": "^2.0.11"
|
|
87
87
|
}
|
|
88
88
|
}
|
package/src/MessageBoxClient.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1292
|
+
async anointHost(host: string): Promise<{ txid: string }> {
|
|
1293
1293
|
Logger.log('[MB CLIENT] Starting anointHost...')
|
|
1294
|
-
|
|
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
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
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
|
-
|
|
1344
|
-
|
|
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
|
-
|
|
1347
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
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.
|
|
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 =
|
|
1453
|
+
const unlocker = pushdrop.unlock(
|
|
1399
1454
|
[1, 'messagebox advertisement'],
|
|
1400
1455
|
'1',
|
|
1401
1456
|
'anyone',
|
|
1402
1457
|
'all',
|
|
1403
1458
|
false,
|
|
1404
|
-
|
|
1459
|
+
sourceSatoshis,
|
|
1405
1460
|
advertisementToken.lockingScript
|
|
1406
1461
|
)
|
|
1407
1462
|
|
|
1408
1463
|
// Convert to Transaction, apply signature
|
|
1409
|
-
const finalUnlockScript = await unlocker.sign(partialTx,
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|