@bsv/message-box-client 1.2.4 → 1.2.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 +1 -1
- package/dist/cjs/src/MessageBoxClient.js +29 -28
- package/dist/cjs/src/MessageBoxClient.js.map +1 -1
- package/dist/cjs/src/PeerPayClient.js +14 -9
- package/dist/cjs/src/PeerPayClient.js.map +1 -1
- package/dist/cjs/src/__tests/MessageBoxClient.test.js +0 -15
- package/dist/cjs/src/__tests/MessageBoxClient.test.js.map +1 -1
- package/dist/cjs/src/__tests/PeerPayClientUnit.test.js +3 -3
- package/dist/cjs/src/__tests/PeerPayClientUnit.test.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/MessageBoxClient.js +29 -28
- package/dist/esm/src/MessageBoxClient.js.map +1 -1
- package/dist/esm/src/PeerPayClient.js +14 -9
- package/dist/esm/src/PeerPayClient.js.map +1 -1
- package/dist/esm/src/__tests/MessageBoxClient.test.js +0 -15
- package/dist/esm/src/__tests/MessageBoxClient.test.js.map +1 -1
- package/dist/esm/src/__tests/PeerPayClientUnit.test.js +3 -3
- package/dist/esm/src/__tests/PeerPayClientUnit.test.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/MessageBoxClient.d.ts +5 -4
- package/dist/types/src/MessageBoxClient.d.ts.map +1 -1
- package/dist/types/src/PeerPayClient.d.ts +10 -5
- 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 +1 -1
- package/src/MessageBoxClient.ts +91 -89
- package/src/PeerPayClient.ts +26 -17
- package/src/__tests/MessageBoxClient.test.ts +0 -23
- package/src/__tests/PeerPayClientUnit.test.ts +3 -3
package/package.json
CHANGED
package/src/MessageBoxClient.ts
CHANGED
|
@@ -116,7 +116,7 @@ export class MessageBoxClient {
|
|
|
116
116
|
* })
|
|
117
117
|
* await client.init()
|
|
118
118
|
*/
|
|
119
|
-
constructor(options: MessageBoxClientOptions = {}) {
|
|
119
|
+
constructor (options: MessageBoxClientOptions = {}) {
|
|
120
120
|
const {
|
|
121
121
|
host,
|
|
122
122
|
walletClient,
|
|
@@ -168,7 +168,7 @@ export class MessageBoxClient {
|
|
|
168
168
|
* await client.init()
|
|
169
169
|
* await client.sendMessage({ recipient, messageBox: 'inbox', body: 'Hello' })
|
|
170
170
|
*/
|
|
171
|
-
async init(targetHost: string = this.host, originator?: string): Promise<void> {
|
|
171
|
+
async init (targetHost: string = this.host, originator?: string): Promise<void> {
|
|
172
172
|
const normalizedHost = targetHost?.trim()
|
|
173
173
|
if (normalizedHost === '') {
|
|
174
174
|
throw new Error('Cannot anoint host: No valid host provided')
|
|
@@ -189,9 +189,14 @@ export class MessageBoxClient {
|
|
|
189
189
|
// 3. If none our found, anoint this host
|
|
190
190
|
if (firstAdvertisement == null || firstAdvertisement?.host?.trim() === '' || firstAdvertisement?.host !== normalizedHost) {
|
|
191
191
|
Logger.log('[MB CLIENT] Anointing host:', normalizedHost)
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
192
|
+
try {
|
|
193
|
+
const { txid } = await this.anointHost(normalizedHost, originator)
|
|
194
|
+
if (txid == null || txid.trim() === '') {
|
|
195
|
+
throw new Error('Failed to anoint host: No transaction ID returned')
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
Logger.log('[MB CLIENT] Failed to anoint host, continuing with default functionality:', error)
|
|
199
|
+
// Continue with default host - client can still function for basic operations
|
|
195
200
|
}
|
|
196
201
|
}
|
|
197
202
|
this.initialized = true
|
|
@@ -208,7 +213,7 @@ export class MessageBoxClient {
|
|
|
208
213
|
*
|
|
209
214
|
* Used automatically by all public methods that require initialization.
|
|
210
215
|
*/
|
|
211
|
-
private async assertInitialized(): Promise<void> {
|
|
216
|
+
private async assertInitialized (): Promise<void> {
|
|
212
217
|
if (!this.initialized || this.host == null || this.host.trim() === '') {
|
|
213
218
|
await this.init()
|
|
214
219
|
}
|
|
@@ -221,7 +226,7 @@ export class MessageBoxClient {
|
|
|
221
226
|
* Returns a live list of WebSocket rooms the client is subscribed to.
|
|
222
227
|
* Useful for inspecting state or ensuring no duplicates are joined.
|
|
223
228
|
*/
|
|
224
|
-
public getJoinedRooms(): Set<string> {
|
|
229
|
+
public getJoinedRooms (): Set<string> {
|
|
225
230
|
return this.joinedRooms
|
|
226
231
|
}
|
|
227
232
|
|
|
@@ -233,7 +238,7 @@ export class MessageBoxClient {
|
|
|
233
238
|
* Returns the client's identity key, used for signing, encryption, and addressing.
|
|
234
239
|
* If not already loaded, it will fetch and cache it.
|
|
235
240
|
*/
|
|
236
|
-
public async getIdentityKey(originator?: string): Promise<string> {
|
|
241
|
+
public async getIdentityKey (originator?: string): Promise<string> {
|
|
237
242
|
if (this.myIdentityKey != null && this.myIdentityKey.trim() !== '') {
|
|
238
243
|
return this.myIdentityKey
|
|
239
244
|
}
|
|
@@ -261,7 +266,7 @@ export class MessageBoxClient {
|
|
|
261
266
|
* Note: Do not interact with the socket directly unless necessary.
|
|
262
267
|
* Use the provided `sendLiveMessage`, `listenForLiveMessages`, and related methods.
|
|
263
268
|
*/
|
|
264
|
-
public get testSocket(): ReturnType<typeof AuthSocketClient> | undefined {
|
|
269
|
+
public get testSocket (): ReturnType<typeof AuthSocketClient> | undefined {
|
|
265
270
|
return this.socket
|
|
266
271
|
}
|
|
267
272
|
|
|
@@ -289,8 +294,7 @@ export class MessageBoxClient {
|
|
|
289
294
|
* await mb.initializeConnection()
|
|
290
295
|
* // WebSocket is now ready for use
|
|
291
296
|
*/
|
|
292
|
-
async initializeConnection(originator?: string): Promise<void> {
|
|
293
|
-
await this.assertInitialized()
|
|
297
|
+
async initializeConnection (originator?: string, overrideHost?: string): Promise<void> {
|
|
294
298
|
Logger.log('[MB CLIENT] initializeConnection() STARTED')
|
|
295
299
|
|
|
296
300
|
if (this.myIdentityKey == null || this.myIdentityKey.trim() === '') {
|
|
@@ -305,10 +309,11 @@ export class MessageBoxClient {
|
|
|
305
309
|
Logger.log('[MB CLIENT] Setting up WebSocket connection...')
|
|
306
310
|
|
|
307
311
|
if (this.socket == null) {
|
|
308
|
-
|
|
309
|
-
|
|
312
|
+
const targetHost = overrideHost ?? this.host
|
|
313
|
+
if (typeof targetHost !== 'string' || targetHost.trim() === '') {
|
|
314
|
+
throw new Error('Cannot initialize WebSocket: No valid host provided')
|
|
310
315
|
}
|
|
311
|
-
this.socket = AuthSocketClient(
|
|
316
|
+
this.socket = AuthSocketClient(targetHost, { wallet: this.walletClient })
|
|
312
317
|
|
|
313
318
|
let identitySent = false
|
|
314
319
|
let authenticated = false
|
|
@@ -383,7 +388,7 @@ export class MessageBoxClient {
|
|
|
383
388
|
* @example
|
|
384
389
|
* const host = await resolveHostForRecipient('028d...') // → returns either overlay host or this.host
|
|
385
390
|
*/
|
|
386
|
-
async resolveHostForRecipient(identityKey: string, originator?: string): Promise<string> {
|
|
391
|
+
async resolveHostForRecipient (identityKey: string, originator?: string): Promise<string> {
|
|
387
392
|
const advertisementTokens = await this.queryAdvertisements(identityKey, undefined, originator)
|
|
388
393
|
if (advertisementTokens.length === 0) {
|
|
389
394
|
Logger.warn(`[MB CLIENT] No advertisements for ${identityKey}, using default host ${this.host}`)
|
|
@@ -401,7 +406,7 @@ export class MessageBoxClient {
|
|
|
401
406
|
* @param host? if passed, only look for adverts anointed at that host
|
|
402
407
|
* @returns 0-length array if nothing valid was found
|
|
403
408
|
*/
|
|
404
|
-
async queryAdvertisements(
|
|
409
|
+
async queryAdvertisements (
|
|
405
410
|
identityKey?: string,
|
|
406
411
|
host?: string,
|
|
407
412
|
originator?: string
|
|
@@ -466,14 +471,13 @@ export class MessageBoxClient {
|
|
|
466
471
|
* await client.joinRoom('payment_inbox')
|
|
467
472
|
* // Now listening for real-time messages in room '028d...-payment_inbox'
|
|
468
473
|
*/
|
|
469
|
-
async joinRoom(messageBox: string): Promise<void> {
|
|
470
|
-
await this.assertInitialized()
|
|
474
|
+
async joinRoom (messageBox: string, originator?: string, overrideHost?: string): Promise<void> {
|
|
471
475
|
Logger.log(`[MB CLIENT] Attempting to join WebSocket room: ${messageBox}`)
|
|
472
476
|
|
|
473
477
|
// Ensure WebSocket connection is established first
|
|
474
478
|
if (this.socket == null) {
|
|
475
479
|
Logger.log('[MB CLIENT] No WebSocket connection. Initializing...')
|
|
476
|
-
await this.initializeConnection()
|
|
480
|
+
await this.initializeConnection(originator, overrideHost)
|
|
477
481
|
}
|
|
478
482
|
|
|
479
483
|
if (this.myIdentityKey == null || this.myIdentityKey.trim() === '') {
|
|
@@ -525,20 +529,27 @@ export class MessageBoxClient {
|
|
|
525
529
|
* onMessage: (msg) => console.log('Received live message:', msg)
|
|
526
530
|
* })
|
|
527
531
|
*/
|
|
528
|
-
async listenForLiveMessages({
|
|
532
|
+
async listenForLiveMessages ({
|
|
529
533
|
onMessage,
|
|
530
534
|
messageBox,
|
|
531
|
-
originator
|
|
535
|
+
originator,
|
|
536
|
+
overrideHost
|
|
532
537
|
}: {
|
|
533
538
|
onMessage: (message: PeerMessage) => void
|
|
534
539
|
messageBox: string
|
|
535
540
|
originator?: string
|
|
541
|
+
overrideHost?: string
|
|
536
542
|
}): Promise<void> {
|
|
537
|
-
await this.assertInitialized()
|
|
538
543
|
Logger.log(`[MB CLIENT] Setting up listener for WebSocket room: ${messageBox}`)
|
|
539
544
|
|
|
540
|
-
// Ensure WebSocket connection
|
|
541
|
-
|
|
545
|
+
// Ensure WebSocket connection is established first
|
|
546
|
+
if (this.socket == null) {
|
|
547
|
+
Logger.log('[MB CLIENT] No WebSocket connection. Initializing...')
|
|
548
|
+
await this.initializeConnection(originator, overrideHost)
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Join the room
|
|
552
|
+
await this.joinRoom(messageBox, originator, overrideHost)
|
|
542
553
|
|
|
543
554
|
// Ensure identity key is available before creating roomId
|
|
544
555
|
if (this.myIdentityKey == null || this.myIdentityKey.trim() === '') {
|
|
@@ -623,7 +634,7 @@ export class MessageBoxClient {
|
|
|
623
634
|
* body: { amount: 1000 }
|
|
624
635
|
* })
|
|
625
636
|
*/
|
|
626
|
-
async sendLiveMessage({
|
|
637
|
+
async sendLiveMessage ({
|
|
627
638
|
recipient,
|
|
628
639
|
messageBox,
|
|
629
640
|
body,
|
|
@@ -631,8 +642,7 @@ export class MessageBoxClient {
|
|
|
631
642
|
skipEncryption,
|
|
632
643
|
checkPermissions,
|
|
633
644
|
originator
|
|
634
|
-
}: SendMessageParams): Promise<SendMessageResponse> {
|
|
635
|
-
await this.assertInitialized()
|
|
645
|
+
}: SendMessageParams, overrideHost?: string): Promise<SendMessageResponse> {
|
|
636
646
|
if (recipient == null || recipient.trim() === '') {
|
|
637
647
|
throw new Error('[MB CLIENT ERROR] Recipient identity key is required')
|
|
638
648
|
}
|
|
@@ -644,12 +654,12 @@ export class MessageBoxClient {
|
|
|
644
654
|
}
|
|
645
655
|
|
|
646
656
|
// Ensure room is joined before sending
|
|
647
|
-
await this.joinRoom(messageBox)
|
|
657
|
+
await this.joinRoom(messageBox, originator, overrideHost)
|
|
648
658
|
|
|
649
659
|
// Fallback to HTTP if WebSocket is not connected
|
|
650
660
|
if (this.socket == null || !this.socket.connected) {
|
|
651
661
|
Logger.warn('[MB CLIENT WARNING] WebSocket not connected, falling back to HTTP')
|
|
652
|
-
const targetHost = await this.resolveHostForRecipient(recipient)
|
|
662
|
+
const targetHost = overrideHost ?? await this.resolveHostForRecipient(recipient)
|
|
653
663
|
return await this.sendMessage({ recipient, messageBox, body }, targetHost)
|
|
654
664
|
}
|
|
655
665
|
|
|
@@ -781,7 +791,7 @@ export class MessageBoxClient {
|
|
|
781
791
|
* @example
|
|
782
792
|
* await client.leaveRoom('payment_inbox')
|
|
783
793
|
*/
|
|
784
|
-
async leaveRoom(messageBox: string): Promise<void> {
|
|
794
|
+
async leaveRoom (messageBox: string): Promise<void> {
|
|
785
795
|
await this.assertInitialized()
|
|
786
796
|
if (this.socket == null) {
|
|
787
797
|
Logger.warn('[MB CLIENT] Attempted to leave a room but WebSocket is not connected.')
|
|
@@ -813,7 +823,7 @@ export class MessageBoxClient {
|
|
|
813
823
|
* @example
|
|
814
824
|
* await client.disconnectWebSocket()
|
|
815
825
|
*/
|
|
816
|
-
async disconnectWebSocket(): Promise<void> {
|
|
826
|
+
async disconnectWebSocket (): Promise<void> {
|
|
817
827
|
await this.assertInitialized()
|
|
818
828
|
if (this.socket != null) {
|
|
819
829
|
Logger.log('[MB CLIENT] Closing WebSocket connection...')
|
|
@@ -851,7 +861,7 @@ export class MessageBoxClient {
|
|
|
851
861
|
* body: { type: 'ping' }
|
|
852
862
|
* })
|
|
853
863
|
*/
|
|
854
|
-
async sendMessage(
|
|
864
|
+
async sendMessage (
|
|
855
865
|
message: SendMessageParams,
|
|
856
866
|
overrideHost?: string,
|
|
857
867
|
originator?: string
|
|
@@ -1015,7 +1025,7 @@ export class MessageBoxClient {
|
|
|
1015
1025
|
* @example
|
|
1016
1026
|
* const { txid } = await client.anointHost('https://my-messagebox.io')
|
|
1017
1027
|
*/
|
|
1018
|
-
async anointHost(host: string, originator?: string): Promise<{ txid: string }> {
|
|
1028
|
+
async anointHost (host: string, originator?: string): Promise<{ txid: string }> {
|
|
1019
1029
|
Logger.log('[MB CLIENT] Starting anointHost...')
|
|
1020
1030
|
try {
|
|
1021
1031
|
if (!host.startsWith('http')) {
|
|
@@ -1097,7 +1107,7 @@ export class MessageBoxClient {
|
|
|
1097
1107
|
* @example
|
|
1098
1108
|
* const { txid } = await client.revokeHost('https://my-messagebox.io')
|
|
1099
1109
|
*/
|
|
1100
|
-
async revokeHostAdvertisement(advertisementToken: AdvertisementToken, originator?: string): Promise<{ txid: string }> {
|
|
1110
|
+
async revokeHostAdvertisement (advertisementToken: AdvertisementToken, originator?: string): Promise<{ txid: string }> {
|
|
1101
1111
|
Logger.log('[MB CLIENT] Starting revokeHost...')
|
|
1102
1112
|
const outpoint = `${advertisementToken.txid}.${advertisementToken.outputIndex}`
|
|
1103
1113
|
try {
|
|
@@ -1213,7 +1223,11 @@ export class MessageBoxClient {
|
|
|
1213
1223
|
|
|
1214
1224
|
let hosts: string[] = host != null ? [host] : []
|
|
1215
1225
|
if (hosts.length === 0) {
|
|
1216
|
-
const advertisedHosts = await this.queryAdvertisements(
|
|
1226
|
+
const advertisedHosts = await this.queryAdvertisements(
|
|
1227
|
+
await this.getIdentityKey(originator),
|
|
1228
|
+
undefined,
|
|
1229
|
+
originator
|
|
1230
|
+
)
|
|
1217
1231
|
hosts = Array.from(new Set([this.host, ...advertisedHosts.map(h => h.host)]))
|
|
1218
1232
|
}
|
|
1219
1233
|
|
|
@@ -1340,7 +1354,7 @@ export class MessageBoxClient {
|
|
|
1340
1354
|
if (
|
|
1341
1355
|
messageContent != null &&
|
|
1342
1356
|
typeof messageContent === 'object' &&
|
|
1343
|
-
typeof (messageContent
|
|
1357
|
+
typeof (messageContent).encryptedMessage === 'string'
|
|
1344
1358
|
) {
|
|
1345
1359
|
Logger.log(
|
|
1346
1360
|
`[MB CLIENT] Decrypting message from ${String(message.sender)}…`
|
|
@@ -1522,7 +1536,7 @@ export class MessageBoxClient {
|
|
|
1522
1536
|
* const success = await client.acknowledgeNotification(message)
|
|
1523
1537
|
* console.log(success ? 'Payment received' : 'No payment or failed')
|
|
1524
1538
|
*/
|
|
1525
|
-
async acknowledgeNotification(message: PeerMessage): Promise<boolean> {
|
|
1539
|
+
async acknowledgeNotification (message: PeerMessage): Promise<boolean> {
|
|
1526
1540
|
await this.acknowledgeMessage({ messageIds: [message.messageId] })
|
|
1527
1541
|
|
|
1528
1542
|
const parsedBody: unknown =
|
|
@@ -1611,8 +1625,7 @@ export class MessageBoxClient {
|
|
|
1611
1625
|
* @example
|
|
1612
1626
|
* await client.acknowledgeMessage({ messageIds: ['msg123', 'msg456'] })
|
|
1613
1627
|
*/
|
|
1614
|
-
async acknowledgeMessage({ messageIds, host, originator }: AcknowledgeMessageParams): Promise<string> {
|
|
1615
|
-
await this.assertInitialized()
|
|
1628
|
+
async acknowledgeMessage ({ messageIds, host, originator }: AcknowledgeMessageParams): Promise<string> {
|
|
1616
1629
|
if (!Array.isArray(messageIds) || messageIds.length === 0) {
|
|
1617
1630
|
throw new Error('Message IDs array cannot be empty')
|
|
1618
1631
|
}
|
|
@@ -1694,11 +1707,10 @@ export class MessageBoxClient {
|
|
|
1694
1707
|
* recipientFee: -1
|
|
1695
1708
|
* })
|
|
1696
1709
|
*/
|
|
1697
|
-
async setMessageBoxPermission(
|
|
1710
|
+
async setMessageBoxPermission (
|
|
1698
1711
|
params: SetMessageBoxPermissionParams,
|
|
1699
1712
|
overrideHost?: string
|
|
1700
1713
|
): Promise<void> {
|
|
1701
|
-
await this.assertInitialized()
|
|
1702
1714
|
const finalHost = overrideHost ?? this.host
|
|
1703
1715
|
|
|
1704
1716
|
Logger.log('[MB CLIENT] Setting messageBox permission...')
|
|
@@ -1742,12 +1754,10 @@ export class MessageBoxClient {
|
|
|
1742
1754
|
* sender: '03abc123...'
|
|
1743
1755
|
* })
|
|
1744
1756
|
*/
|
|
1745
|
-
async getMessageBoxPermission(
|
|
1757
|
+
async getMessageBoxPermission (
|
|
1746
1758
|
params: GetMessageBoxPermissionParams,
|
|
1747
1759
|
overrideHost?: string
|
|
1748
1760
|
): Promise<MessageBoxPermission | null> {
|
|
1749
|
-
await this.assertInitialized()
|
|
1750
|
-
|
|
1751
1761
|
const finalHost = overrideHost ?? await this.resolveHostForRecipient(params.recipient)
|
|
1752
1762
|
const queryParams = new URLSearchParams({
|
|
1753
1763
|
recipient: params.recipient,
|
|
@@ -1789,9 +1799,7 @@ export class MessageBoxClient {
|
|
|
1789
1799
|
* messageBox: 'notifications'
|
|
1790
1800
|
* })
|
|
1791
1801
|
*/
|
|
1792
|
-
async getMessageBoxQuote(params: GetQuoteParams, overrideHost?: string): Promise<MessageBoxQuote> {
|
|
1793
|
-
await this.assertInitialized()
|
|
1794
|
-
|
|
1802
|
+
async getMessageBoxQuote (params: GetQuoteParams, overrideHost?: string): Promise<MessageBoxQuote> {
|
|
1795
1803
|
const finalHost = overrideHost ?? await this.resolveHostForRecipient(params.recipient)
|
|
1796
1804
|
const queryParams = new URLSearchParams({
|
|
1797
1805
|
recipient: params.recipient,
|
|
@@ -1847,9 +1855,7 @@ export class MessageBoxClient {
|
|
|
1847
1855
|
* offset: 0
|
|
1848
1856
|
* })
|
|
1849
1857
|
*/
|
|
1850
|
-
async listMessageBoxPermissions(params?: ListPermissionsParams, overrideHost?: string): Promise<MessageBoxPermission[]> {
|
|
1851
|
-
await this.assertInitialized()
|
|
1852
|
-
|
|
1858
|
+
async listMessageBoxPermissions (params?: ListPermissionsParams, overrideHost?: string): Promise<MessageBoxPermission[]> {
|
|
1853
1859
|
const finalHost = overrideHost ?? this.host
|
|
1854
1860
|
const queryParams = new URLSearchParams()
|
|
1855
1861
|
|
|
@@ -1908,7 +1914,7 @@ export class MessageBoxClient {
|
|
|
1908
1914
|
* await client.allowNotificationsFromPeer('03abc123...') // Always allow
|
|
1909
1915
|
* await client.allowNotificationsFromPeer('03def456...', 5) // Allow for 5 sats
|
|
1910
1916
|
*/
|
|
1911
|
-
async allowNotificationsFromPeer(identityKey: PubKeyHex, recipientFee: number = 0, overrideHost?: string): Promise<void> {
|
|
1917
|
+
async allowNotificationsFromPeer (identityKey: PubKeyHex, recipientFee: number = 0, overrideHost?: string): Promise<void> {
|
|
1912
1918
|
await this.setMessageBoxPermission({
|
|
1913
1919
|
messageBox: 'notifications',
|
|
1914
1920
|
sender: identityKey,
|
|
@@ -1928,7 +1934,7 @@ export class MessageBoxClient {
|
|
|
1928
1934
|
* @example
|
|
1929
1935
|
* await client.denyNotificationsFromPeer('03spam123...')
|
|
1930
1936
|
*/
|
|
1931
|
-
async denyNotificationsFromPeer(identityKey: PubKeyHex, overrideHost?: string): Promise<void> {
|
|
1937
|
+
async denyNotificationsFromPeer (identityKey: PubKeyHex, overrideHost?: string): Promise<void> {
|
|
1932
1938
|
await this.setMessageBoxPermission({
|
|
1933
1939
|
messageBox: 'notifications',
|
|
1934
1940
|
sender: identityKey,
|
|
@@ -1949,7 +1955,7 @@ export class MessageBoxClient {
|
|
|
1949
1955
|
* const status = await client.checkPeerNotificationStatus('03abc123...')
|
|
1950
1956
|
* console.log(status.allowed) // true/false
|
|
1951
1957
|
*/
|
|
1952
|
-
async checkPeerNotificationStatus(identityKey: PubKeyHex, overrideHost?: string): Promise<MessageBoxPermission | null> {
|
|
1958
|
+
async checkPeerNotificationStatus (identityKey: PubKeyHex, overrideHost?: string): Promise<MessageBoxPermission | null> {
|
|
1953
1959
|
const myIdentityKey = await this.getIdentityKey()
|
|
1954
1960
|
return await this.getMessageBoxPermission({
|
|
1955
1961
|
recipient: myIdentityKey,
|
|
@@ -1969,7 +1975,7 @@ export class MessageBoxClient {
|
|
|
1969
1975
|
* @example
|
|
1970
1976
|
* const notifications = await client.listPeerNotifications()
|
|
1971
1977
|
*/
|
|
1972
|
-
async listPeerNotifications(overrideHost?: string): Promise<MessageBoxPermission[]> {
|
|
1978
|
+
async listPeerNotifications (overrideHost?: string): Promise<MessageBoxPermission[]> {
|
|
1973
1979
|
return await this.listMessageBoxPermissions({ messageBox: 'notifications' }, overrideHost)
|
|
1974
1980
|
}
|
|
1975
1981
|
|
|
@@ -1992,7 +1998,7 @@ export class MessageBoxClient {
|
|
|
1992
1998
|
* // Send with maximum payment limit for safety
|
|
1993
1999
|
* await client.sendNotification('03def456...', { title: 'Alert', body: 'Important update' }, 50)
|
|
1994
2000
|
*/
|
|
1995
|
-
async sendNotification(
|
|
2001
|
+
async sendNotification (
|
|
1996
2002
|
recipient: PubKeyHex,
|
|
1997
2003
|
body: string | object,
|
|
1998
2004
|
overrideHost?: string
|
|
@@ -2028,12 +2034,10 @@ export class MessageBoxClient {
|
|
|
2028
2034
|
* deviceId: 'iPhone15Pro'
|
|
2029
2035
|
* })
|
|
2030
2036
|
*/
|
|
2031
|
-
async registerDevice(
|
|
2037
|
+
async registerDevice (
|
|
2032
2038
|
params: DeviceRegistrationParams,
|
|
2033
2039
|
overrideHost?: string
|
|
2034
2040
|
): Promise<DeviceRegistrationResponse> {
|
|
2035
|
-
await this.assertInitialized()
|
|
2036
|
-
|
|
2037
2041
|
if (params.fcmToken == null || params.fcmToken.trim() === '') {
|
|
2038
2042
|
throw new Error('fcmToken is required and must be a non-empty string')
|
|
2039
2043
|
}
|
|
@@ -2095,11 +2099,9 @@ export class MessageBoxClient {
|
|
|
2095
2099
|
* console.log(`Device: ${device.platform} - ${device.fcmToken}`)
|
|
2096
2100
|
* })
|
|
2097
2101
|
*/
|
|
2098
|
-
async listRegisteredDevices(
|
|
2102
|
+
async listRegisteredDevices (
|
|
2099
2103
|
overrideHost?: string
|
|
2100
2104
|
): Promise<RegisteredDevice[]> {
|
|
2101
|
-
await this.assertInitialized()
|
|
2102
|
-
|
|
2103
2105
|
const finalHost = overrideHost ?? this.host
|
|
2104
2106
|
|
|
2105
2107
|
Logger.log('[MB CLIENT] Listing registered devices...')
|
|
@@ -2127,39 +2129,39 @@ export class MessageBoxClient {
|
|
|
2127
2129
|
// PRIVATE HELPER METHODS
|
|
2128
2130
|
// ===========================
|
|
2129
2131
|
|
|
2130
|
-
private static getStatusFromFee(fee: number): 'always_allow' | 'blocked' | 'payment_required' {
|
|
2132
|
+
private static getStatusFromFee (fee: number): 'always_allow' | 'blocked' | 'payment_required' {
|
|
2131
2133
|
if (fee === -1) return 'blocked'
|
|
2132
2134
|
if (fee === 0) return 'always_allow'
|
|
2133
2135
|
return 'payment_required'
|
|
2134
2136
|
}
|
|
2135
2137
|
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
private async createMessagePayment(
|
|
2138
|
+
/**
|
|
2139
|
+
* @method createMessagePayment
|
|
2140
|
+
* @private
|
|
2141
|
+
* @param {string} recipient - Recipient's identity key.
|
|
2142
|
+
* @param {MessageBoxQuote} quote - Quote object containing recipient and delivery fees.
|
|
2143
|
+
* @param {string} [description='MessageBox delivery payment'] - Description for the payment action.
|
|
2144
|
+
* @param {string} [originator] - Optional originator to use for wallet operations.
|
|
2145
|
+
* @returns {Promise<Payment>} - Payment data including the transaction and remittance outputs.
|
|
2146
|
+
*
|
|
2147
|
+
* @description
|
|
2148
|
+
* Constructs and signs a payment transaction covering both delivery and recipient fees for
|
|
2149
|
+
* message delivery, based on a previously obtained quote.
|
|
2150
|
+
*
|
|
2151
|
+
* The transaction includes:
|
|
2152
|
+
* - An optional delivery fee output for the MessageBox server.
|
|
2153
|
+
* - An optional recipient fee output for the message recipient.
|
|
2154
|
+
*
|
|
2155
|
+
* Payment remittance metadata (derivation prefix/suffix, sender identity) is embedded to allow
|
|
2156
|
+
* the payee to derive their private key and spend the output.
|
|
2157
|
+
*
|
|
2158
|
+
* @throws {Error} If no payment is required, key derivation fails, or the action creation fails.
|
|
2159
|
+
*
|
|
2160
|
+
* @example
|
|
2161
|
+
* const payment = await client.createMessagePayment(recipientKey, quote)
|
|
2162
|
+
* await client.sendMessage({ recipient, messageBox, body, payment })
|
|
2163
|
+
*/
|
|
2164
|
+
private async createMessagePayment (
|
|
2163
2165
|
recipient: string,
|
|
2164
2166
|
quote: MessageBoxQuote,
|
|
2165
2167
|
description: string = 'MessageBox delivery payment',
|
package/src/PeerPayClient.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { PeerMessage } from './types.js'
|
|
|
15
15
|
import { WalletClient, P2PKH, PublicKey, createNonce, AtomicBEEF, AuthFetch, Base64String } from '@bsv/sdk'
|
|
16
16
|
import * as Logger from './Utils/logger.js'
|
|
17
17
|
|
|
18
|
-
function safeParse<T>(input: any): T {
|
|
18
|
+
function safeParse<T> (input: any): T {
|
|
19
19
|
try {
|
|
20
20
|
return typeof input === 'string' ? JSON.parse(input) : input
|
|
21
21
|
} catch (e) {
|
|
@@ -74,7 +74,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
74
74
|
private readonly peerPayWalletClient: WalletClient
|
|
75
75
|
private _authFetchInstance?: AuthFetch
|
|
76
76
|
|
|
77
|
-
constructor(config: PeerPayClientConfig) {
|
|
77
|
+
constructor (config: PeerPayClientConfig) {
|
|
78
78
|
const { messageBoxHost = 'https://messagebox.babbage.systems', walletClient, enableLogging = false } = config
|
|
79
79
|
|
|
80
80
|
// 🔹 Pass enableLogging to MessageBoxClient
|
|
@@ -83,7 +83,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
83
83
|
this.peerPayWalletClient = walletClient
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
private get authFetchInstance(): AuthFetch {
|
|
86
|
+
private get authFetchInstance (): AuthFetch {
|
|
87
87
|
if (this._authFetchInstance === null || this._authFetchInstance === undefined) {
|
|
88
88
|
this._authFetchInstance = new AuthFetch(this.peerPayWalletClient)
|
|
89
89
|
}
|
|
@@ -102,7 +102,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
102
102
|
* @returns {Promise<PaymentToken>} A valid payment token containing transaction details.
|
|
103
103
|
* @throws {Error} If the recipient's public key cannot be derived.
|
|
104
104
|
*/
|
|
105
|
-
async createPaymentToken(payment: PaymentParams): Promise<PaymentToken> {
|
|
105
|
+
async createPaymentToken (payment: PaymentParams): Promise<PaymentToken> {
|
|
106
106
|
if (payment.amount <= 0) {
|
|
107
107
|
throw new Error('Invalid payment details: recipient and valid amount are required')
|
|
108
108
|
};
|
|
@@ -175,10 +175,11 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
175
175
|
* @param {PaymentParams} payment - The payment details.
|
|
176
176
|
* @param {string} payment.recipient - The recipient's identity key.
|
|
177
177
|
* @param {number} payment.amount - The amount in satoshis to send.
|
|
178
|
+
* @param {string} [hostOverride] - Optional host override for the message box server.
|
|
178
179
|
* @returns {Promise<any>} Resolves with the payment result.
|
|
179
180
|
* @throws {Error} If the recipient is missing or the amount is invalid.
|
|
180
181
|
*/
|
|
181
|
-
async sendPayment(payment: PaymentParams): Promise<any> {
|
|
182
|
+
async sendPayment (payment: PaymentParams, hostOverride?: string): Promise<any> {
|
|
182
183
|
if (payment.recipient == null || payment.recipient.trim() === '' || payment.amount <= 0) {
|
|
183
184
|
throw new Error('Invalid payment details: recipient and valid amount are required')
|
|
184
185
|
}
|
|
@@ -190,23 +191,24 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
190
191
|
recipient: payment.recipient,
|
|
191
192
|
messageBox: STANDARD_PAYMENT_MESSAGEBOX,
|
|
192
193
|
body: JSON.stringify(paymentToken)
|
|
193
|
-
})
|
|
194
|
+
}, hostOverride)
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
/**
|
|
197
198
|
* Sends Bitcoin to a PeerPay recipient over WebSockets.
|
|
198
199
|
*
|
|
199
200
|
* This function generates a payment token and transmits it over WebSockets
|
|
200
|
-
* using `sendLiveMessage`. The recipient
|
|
201
|
+
* using `sendLiveMessage`. The recipient's identity key is explicitly included
|
|
201
202
|
* to ensure proper message routing.
|
|
202
203
|
*
|
|
203
204
|
* @param {PaymentParams} payment - The payment details.
|
|
204
205
|
* @param {string} payment.recipient - The recipient's identity key.
|
|
205
206
|
* @param {number} payment.amount - The amount in satoshis to send.
|
|
207
|
+
* @param {string} [overrideHost] - Optional host override for WebSocket connection.
|
|
206
208
|
* @returns {Promise<void>} Resolves when the payment has been sent.
|
|
207
209
|
* @throws {Error} If payment token generation fails.
|
|
208
210
|
*/
|
|
209
|
-
async sendLivePayment(payment: PaymentParams): Promise<void> {
|
|
211
|
+
async sendLivePayment (payment: PaymentParams, overrideHost?: string): Promise<void> {
|
|
210
212
|
const paymentToken = await this.createPaymentToken(payment)
|
|
211
213
|
|
|
212
214
|
try {
|
|
@@ -215,7 +217,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
215
217
|
recipient: payment.recipient,
|
|
216
218
|
messageBox: STANDARD_PAYMENT_MESSAGEBOX,
|
|
217
219
|
body: JSON.stringify(paymentToken)
|
|
218
|
-
})
|
|
220
|
+
}, overrideHost)
|
|
219
221
|
} catch (err) {
|
|
220
222
|
Logger.warn('[PP CLIENT] sendLiveMessage failed, falling back to HTTP:', err)
|
|
221
223
|
|
|
@@ -224,7 +226,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
224
226
|
recipient: payment.recipient,
|
|
225
227
|
messageBox: STANDARD_PAYMENT_MESSAGEBOX,
|
|
226
228
|
body: JSON.stringify(paymentToken)
|
|
227
|
-
})
|
|
229
|
+
}, overrideHost)
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
|
|
@@ -237,13 +239,19 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
237
239
|
*
|
|
238
240
|
* @param {Object} obj - The configuration object.
|
|
239
241
|
* @param {Function} obj.onPayment - Callback function triggered when a payment is received.
|
|
242
|
+
* @param {string} [obj.overrideHost] - Optional host override for WebSocket connection.
|
|
240
243
|
* @returns {Promise<void>} Resolves when the listener is successfully set up.
|
|
241
244
|
*/
|
|
242
|
-
async listenForLivePayments({
|
|
243
|
-
onPayment
|
|
244
|
-
|
|
245
|
+
async listenForLivePayments ({
|
|
246
|
+
onPayment,
|
|
247
|
+
overrideHost
|
|
248
|
+
}: {
|
|
249
|
+
onPayment: (payment: IncomingPayment) => void
|
|
250
|
+
overrideHost?: string
|
|
251
|
+
}): Promise<void> {
|
|
245
252
|
await this.listenForLiveMessages({
|
|
246
253
|
messageBox: STANDARD_PAYMENT_MESSAGEBOX,
|
|
254
|
+
overrideHost,
|
|
247
255
|
|
|
248
256
|
// Convert PeerMessage → IncomingPayment before calling onPayment
|
|
249
257
|
onMessage: (message: PeerMessage) => {
|
|
@@ -270,7 +278,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
270
278
|
* @returns {Promise<any>} Resolves with the payment result if successful.
|
|
271
279
|
* @throws {Error} If payment processing fails.
|
|
272
280
|
*/
|
|
273
|
-
async acceptPayment(payment: IncomingPayment): Promise<any> {
|
|
281
|
+
async acceptPayment (payment: IncomingPayment): Promise<any> {
|
|
274
282
|
try {
|
|
275
283
|
Logger.log(`[PP CLIENT] Processing payment: ${JSON.stringify(payment, null, 2)}`)
|
|
276
284
|
|
|
@@ -310,7 +318,7 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
310
318
|
* @param {IncomingPayment} payment - The payment object containing transaction details.
|
|
311
319
|
* @returns {Promise<void>} Resolves when the payment is either acknowledged or refunded.
|
|
312
320
|
*/
|
|
313
|
-
async rejectPayment(payment: IncomingPayment): Promise<void> {
|
|
321
|
+
async rejectPayment (payment: IncomingPayment): Promise<void> {
|
|
314
322
|
Logger.log(`[PP CLIENT] Rejecting payment: ${JSON.stringify(payment, null, 2)}`)
|
|
315
323
|
|
|
316
324
|
if (payment.token.amount - 1000 < 1000) {
|
|
@@ -368,10 +376,11 @@ export class PeerPayClient extends MessageBoxClient {
|
|
|
368
376
|
* This function queries the message box for new messages and transforms
|
|
369
377
|
* them into `IncomingPayment` objects by extracting relevant fields.
|
|
370
378
|
*
|
|
379
|
+
* @param {string} [overrideHost] - Optional host override to list payments from
|
|
371
380
|
* @returns {Promise<IncomingPayment[]>} Resolves with an array of pending payments.
|
|
372
381
|
*/
|
|
373
|
-
async listIncomingPayments(): Promise<IncomingPayment[]> {
|
|
374
|
-
const messages = await this.listMessages({ messageBox: STANDARD_PAYMENT_MESSAGEBOX })
|
|
382
|
+
async listIncomingPayments (overrideHost?: string): Promise<IncomingPayment[]> {
|
|
383
|
+
const messages = await this.listMessages({ messageBox: STANDARD_PAYMENT_MESSAGEBOX, host: overrideHost })
|
|
375
384
|
|
|
376
385
|
return messages.map((msg: any) => {
|
|
377
386
|
const parsedToken = safeParse<PaymentToken>(msg.body)
|
|
@@ -320,7 +320,6 @@ describe('MessageBoxClient', () => {
|
|
|
320
320
|
|
|
321
321
|
const result = await messageBoxClient.listMessages({ messageBox: 'test_inbox' })
|
|
322
322
|
|
|
323
|
-
|
|
324
323
|
expect(result).toEqual(JSON.parse(VALID_LIST_AND_READ_RESULT.body).messages)
|
|
325
324
|
})
|
|
326
325
|
|
|
@@ -438,28 +437,6 @@ describe('MessageBoxClient', () => {
|
|
|
438
437
|
.rejects.toThrow('Failed to acknowledge messages')
|
|
439
438
|
})
|
|
440
439
|
|
|
441
|
-
it('Throws an error when WebSocket is not initialized before listening for messages', async () => {
|
|
442
|
-
const messageBoxClient = new MessageBoxClient({
|
|
443
|
-
walletClient: mockWalletClient,
|
|
444
|
-
host: 'https://messagebox.babbage.systems',
|
|
445
|
-
enableLogging: true
|
|
446
|
-
})
|
|
447
|
-
await messageBoxClient.init()
|
|
448
|
-
|
|
449
|
-
// Stub out the identity key to pass that check
|
|
450
|
-
; (messageBoxClient as any).myIdentityKey = '02b463b8ef7f03c47fba2679c7334d13e4939b8ca30dbb6bbd22e34ea3e9b1b0e4'
|
|
451
|
-
|
|
452
|
-
// Stub out joinRoom to throw like the real one might
|
|
453
|
-
jest.spyOn(messageBoxClient, 'joinRoom').mockRejectedValue(new Error('WebSocket connection not initialized'))
|
|
454
|
-
|
|
455
|
-
await expect(
|
|
456
|
-
messageBoxClient.listenForLiveMessages({
|
|
457
|
-
onMessage: jest.fn(),
|
|
458
|
-
messageBox: 'test_inbox'
|
|
459
|
-
})
|
|
460
|
-
).rejects.toThrow('WebSocket connection not initialized')
|
|
461
|
-
})
|
|
462
|
-
|
|
463
440
|
it('Emits joinRoom event and listens for incoming messages', async () => {
|
|
464
441
|
const messageBoxClient = new MessageBoxClient({
|
|
465
442
|
walletClient: mockWalletClient,
|