feat(nostr): publish notes with per-relay status (M11.1)

Compose panel in Nostr tab, sign via NIP-07, broadcast to configured
relays with per-relay send status. Character counter (soft 280 limit).
Removed isDark conditionals from NostrGrid (dark-only app).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-04 00:10:53 +00:00
co-authored by Claude Opus 4.6
parent 869db87fd5
commit 9b4980b669
2 changed files with 172 additions and 79 deletions
+52
View File
@@ -175,6 +175,57 @@ function disconnect() {
initialized = false
}
export interface PublishResult {
url: string
success: boolean
message: string
}
function publishEvent(signedEvent: NostrEvent): Promise<PublishResult[]> {
const connectedRelays = relays.filter(r => r.connected && r.ws)
if (connectedRelays.length === 0) {
return Promise.resolve([])
}
const results = connectedRelays.map(relay => {
return new Promise<PublishResult>((resolve) => {
const timer = setTimeout(() => {
resolve({ url: relay.url, success: false, message: 'Timeout' })
}, 5000)
const handler = (msg: MessageEvent) => {
try {
const data = JSON.parse(msg.data)
// NIP-01: ["OK", <event_id>, <accepted>, <message>]
if (Array.isArray(data) && data[0] === 'OK' && data[1] === signedEvent.id) {
clearTimeout(timer)
relay.ws?.removeEventListener('message', handler)
resolve({
url: relay.url,
success: !!data[2],
message: data[3] ?? (data[2] ? 'Published' : 'Rejected'),
})
}
} catch { /* skip */ }
}
relay.ws!.addEventListener('message', handler)
try {
relay.ws!.send(JSON.stringify(['EVENT', signedEvent]))
} catch {
clearTimeout(timer)
relay.ws?.removeEventListener('message', handler)
resolve({ url: relay.url, success: false, message: 'Send failed' })
}
})
})
// Also add to our local feed
addEvent(signedEvent)
return Promise.all(results)
}
function fetchNote(hexId: string, timeoutMs = 5000): Promise<NostrNote | null> {
// Check if already cached
const cached = events.value.find(e => e.id === hexId)
@@ -237,5 +288,6 @@ export function useNostr() {
connect,
disconnect,
fetchNote,
publishEvent,
}
}