#!/usr/bin/env node // Throwaway in-memory NIP-01 relay for RESTORE DRILLS. // // node scripts/drill-relay.mjs [port] # default 7777 // // Proves the backup loop end-to-end without touching production or any third // party: start this, `node scripts/restore-relay.mjs --to // ws://localhost:7777`, then query it back and assert every archived event // arrived. Deliberately minimal — no persistence, no auth, no relay policy. import { WebSocketServer } from 'ws'; const PORT = Number(process.argv[2] || 7777); const events = new Map(); function matches(event, filter) { if (filter.ids && !filter.ids.includes(event.id)) return false; if (filter.kinds && !filter.kinds.includes(event.kind)) return false; if (filter.authors && !filter.authors.includes(event.pubkey)) return false; if (filter.since && event.created_at < filter.since) return false; if (filter.until && event.created_at > filter.until) return false; for (const key of Object.keys(filter)) { if (!key.startsWith('#')) continue; const tag = key.slice(1); const wanted = filter[key]; if (!Array.isArray(wanted)) continue; if (!wanted.some((v) => event.tags.some(([n, x]) => n === tag && x === v))) return false; } return true; } const wss = new WebSocketServer({ port: PORT }); wss.on('connection', (ws) => { ws.on('message', (raw) => { let msg; try { msg = JSON.parse(raw.toString()); } catch { return; } const [type] = msg; if (type === 'EVENT') { const event = msg[1]; if (event?.id) { events.set(event.id, event); ws.send(JSON.stringify(['OK', event.id, true, ''])); } else { ws.send(JSON.stringify(['OK', '', false, 'invalid'])); } return; } if (type === 'REQ') { const sub = msg[1]; const filters = msg.slice(2); const out = new Map(); for (const filter of filters) { const matched = [...events.values()] .filter((e) => matches(e, filter)) .sort((a, b) => b.created_at - a.created_at); const limited = typeof filter.limit === 'number' ? matched.slice(0, filter.limit) : matched; for (const e of limited) out.set(e.id, e); } for (const e of out.values()) ws.send(JSON.stringify(['EVENT', sub, e])); ws.send(JSON.stringify(['EOSE', sub])); } }); }); console.log(`[drill-relay] ws://localhost:${PORT} — in-memory, throwaway`); for (const sig of ['SIGINT', 'SIGTERM']) { process.on(sig, () => { console.log(`[drill-relay] stopping (${events.size} events held)`); wss.close(); process.exit(0); }); }