+
-
-
- Received Data:
-
-
-
-
+
+
+
+
+
+{{ testData.sentData }}
+
+
+
+
+
+
+
+
+{{ testData.receivedData }}
+
+
+
+
+
+ How to verify: Check your Nostr client (Damus,
+ Amethyst, etc.) for the test message in your DMs.
-
-
+
+
@@ -418,13 +426,15 @@
Nostrclient Extension
},
testData: {
show: false,
+ sending: false,
wsConnection: null,
senderPrivateKey: null,
senderPublicKey: null,
recieverPublicKey: null,
message: null,
sentData: '',
- receivedData: ''
+ receivedData: '',
+ connectionStatus: null
},
relayTable: {
columns: [
@@ -570,42 +580,44 @@ Nostrclient Extension
}
this.config.showDialog = false
},
- toggleTestPanel: async function () {
- if (this.testData.show) {
- await this.hideTestPannel()
- } else {
- await this.showTestPanel()
- }
- },
- showTestPanel: async function () {
+ openTestDialog: async function () {
+ // Refresh config to get latest private_ws_endpoint
+ await this.getConfig()
this.testData = {
show: true,
+ sending: false,
wsConnection: null,
senderPrivateKey:
this.$q.localStorage.getItem(
'lnbits.nostrclient.senderPrivateKey'
) || '',
+ senderPublicKey: null,
recieverPublicKey: null,
message: null,
sentData: '',
- receivedData: ''
+ receivedData: '',
+ connectionStatus: null
}
await this.closeWebsocket()
this.connectToWebsocket()
},
- hideTestPannel: async function () {
+ closeTestDialog: async function () {
await this.closeWebsocket()
this.testData = {
show: false,
+ sending: false,
wsConnection: null,
senderPrivateKey: null,
+ senderPublicKey: null,
recieverPublicKey: null,
message: null,
sentData: '',
- receivedData: ''
+ receivedData: '',
+ connectionStatus: null
}
},
sendTestMessage: async function () {
+ this.testData.sending = true
try {
const {data} = await LNbits.api.request(
'PUT',
@@ -631,8 +643,14 @@ Nostrclient Extension
{kinds: [4], '#p': [event.pubkey]}
])
this.testData.wsConnection.send(subscription)
+ this.$q.notify({
+ type: 'positive',
+ message: 'Test message sent successfully'
+ })
} catch (error) {
LNbits.utils.notifyApiError(error)
+ } finally {
+ this.testData.sending = false
}
},
@@ -643,9 +661,13 @@ Nostrclient Extension
await this.sleep(500)
}
this.testData.wsConnection.send(data)
- const separator = '='.repeat(80)
- this.testData.sentData =
- data + `\n\n${separator}\n` + this.testData.sentData
+ try {
+ const parsed = JSON.parse(data)
+ const formatted = JSON.stringify(parsed, null, 2)
+ this.testData.sentData += formatted + '\n\n'
+ } catch {
+ this.testData.sentData += data + '\n\n'
+ }
} catch (error) {
this.$q.notify({
timeout: 5000,
@@ -658,17 +680,45 @@ Nostrclient Extension
connectToWebsocket: function () {
const scheme = location.protocol === 'http:' ? 'ws' : 'wss'
const port = location.port ? `:${location.port}` : ''
- const wsUrl = `${scheme}://${document.domain}${port}/nostrclient/api/v1/relay`
+ // Use private endpoint if available, otherwise fall back to public
+ const endpoint =
+ this.config.data.private_ws && this.config.data.private_ws_endpoint
+ ? this.config.data.private_ws_endpoint
+ : 'relay'
+ const wsUrl = `${scheme}://${document.domain}${port}/nostrclient/api/v1/${endpoint}`
this.testData.wsConnection = new WebSocket(wsUrl)
- const updateReciveData = async e => {
- const separator = '='.repeat(80)
- this.testData.receivedData =
- e.data + `\n\n${separator}\n` + this.testData.receivedData
+
+ this.testData.wsConnection.onopen = () => {
+ this.testData.receivedData = '[Connected to WebSocket]\n'
+ this.testData.connectionStatus = 'connected'
+ }
+
+ this.testData.wsConnection.onmessage = e => {
+ if (e.data) {
+ try {
+ const parsed = JSON.parse(e.data)
+ const formatted = JSON.stringify(parsed, null, 2)
+ this.testData.receivedData += formatted + '\n\n'
+ } catch {
+ this.testData.receivedData += e.data + '\n'
+ }
+ }
+ }
+
+ this.testData.wsConnection.onerror = () => {
+ this.testData.receivedData +=
+ '[WebSocket error - check Settings to enable Private or Public WebSocket]\n'
+ this.testData.connectionStatus = 'error'
}
- this.testData.wsConnection.onmessage = updateReciveData
- this.testData.wsConnection.onerror = updateReciveData
- this.testData.wsConnection.onclose = updateReciveData
+ this.testData.wsConnection.onclose = e => {
+ const reason =
+ e.reason || (e.code === 1006 ? 'Connection refused (403)' : '')
+ this.testData.receivedData += `[WebSocket closed${reason ? ': ' + reason : ''}]\n`
+ if (this.testData.connectionStatus !== 'connected') {
+ this.testData.connectionStatus = 'error'
+ }
+ }
},
closeWebsocket: async function () {
try {
diff --git a/views_api.py b/views_api.py
index 4470680..7ce765e 100644
--- a/views_api.py
+++ b/views_api.py
@@ -3,7 +3,11 @@
from fastapi import APIRouter, Depends, HTTPException, WebSocket
from lnbits.decorators import check_admin
-from lnbits.helpers import decrypt_internal_message, urlsafe_short_hash
+from lnbits.helpers import (
+ decrypt_internal_message,
+ encrypt_internal_message,
+ urlsafe_short_hash,
+)
from loguru import logger
from .crud import (
@@ -169,6 +173,8 @@ async def api_get_config() -> Config:
if not config:
config = await create_config(owner_id="admin")
assert config, "Failed to create config"
+ # Add private WebSocket endpoint for admin use
+ config.private_ws_endpoint = encrypt_internal_message("relay", urlsafe=True)
return config