#!/usr/bin/node // publish-10050 — publica el kind 10050 (NIP-65 memento: relays de inbox // para DMs/gift wraps) de Cayce. Autorizado explícitamente por el operador. // Se ejecuta UNA vez (script, no daemon). import { readFileSync } from 'node:fs' import { SimplePool, finalizeEvent, getPublicKey } from 'nostr-tools' const env = Object.fromEntries( readFileSync('/srv/cayce-nostr/.env', 'utf8').split('\n').filter(l => l.includes('=')).map(l => [l.slice(0, l.indexOf('=')), l.slice(l.indexOf('=') + 1)]) ) const skRaw = env.NSEC_HEX const { nsecDeserialize } = await import('nostr-tools') // soporta hex y bech32 vía fallback let sk try { sk = skRaw.startsWith('nsec1') ? nsecDeserialize(skRaw) : Buffer.from(skRaw, 'hex') } catch (e) { console.error('nsec ilegible:', String(e).slice(0, 80)); process.exit(1) } const pk = getPublicKey(sk) // relays donde Cayce ESCUCHA DMs (los mismos del listener) — son su inbox const INBOX = [ 'wss://relay.damus.io', 'wss://nos.lol', 'wss://relay.primal.net', 'wss://relay.snort.social', 'wss://nostr-pub.wellorder.net', 'wss://public.relaying.io', ] const ev = finalizeEvent({ kind: 10050, created_at: Math.floor(Date.now() / 1000), tags: INBOX.map(r => ['relay', r]), content: '', }, sk) console.log('[10050] pubkey:', pk) console.log('[10050] relays de inbox declarados:', INBOX.join(', ')) const pool = new SimplePool() const ok = [] for (const r of INBOX) { try { await Promise.race([ pool.publish([r], ev), new Promise((_, rej) => setTimeout(() => rej(new Error('timeout')), 6000)), ]) ok.push(r) } catch (e) { console.error(`[10050] ${r}: ${String(e).slice(0, 60)}`) } } pool.close(INBOX) console.log(`[10050] publicado/aceptado en ${ok.length}/${INBOX.length} relays — event id ${ev.id}`)