import type { EventTemplate, Event } from 'nostr-tools' import { getEventHash, signEvent } from 'nostr-tools' import { nostrConnectService } from './nostrconnect' import { nostrService } from './nostr' /** * Remote signer using nos2x (NIP-07) or NostrConnect (NIP-46) * Supports nos2x extension (window.nostr) and NostrConnect bridge */ export class NostrRemoteSigner { /** * Sign an event template * Uses nos2x (NIP-07) if available, otherwise falls back to private key signing */ async signEvent(eventTemplate: EventTemplate): Promise { // Get the event hash first const pubkey = nostrService.getPublicKey() if (!pubkey) { throw new Error('Public key required for signing. Please connect a Nostr wallet.') } const unsignedEvent = { pubkey, ...eventTemplate, created_at: eventTemplate.created_at ?? Math.floor(Date.now() / 1000), } const eventId = getEventHash(unsignedEvent) // Try nos2x (NIP-07) first if (typeof window !== 'undefined' && window.nostr) { try { const signedEvent = await window.nostr.signEvent({ kind: unsignedEvent.kind, created_at: unsignedEvent.created_at, tags: unsignedEvent.tags, content: unsignedEvent.content, }) return signedEvent as Event } catch (e) { console.error('Error signing with nos2x:', e) throw new Error('Failed to sign event with nos2x extension') } } // Fallback to private key signing const privateKey = nostrService.getPrivateKey() if (!privateKey) { throw new Error( 'Private key required for signing. ' + 'Please install nos2x extension or use a NostrConnect wallet that provides signing capabilities.' ) } const event = { ...unsignedEvent, id: eventId, sig: signEvent(unsignedEvent, privateKey), } as Event return event } /** * Check if remote signing is available */ isAvailable(): boolean { const state = nostrConnectService.getState() return state.connected && !!state.pubkey } /** * Check if direct signing (with private key) is available */ isDirectSigningAvailable(): boolean { return !!nostrService.getPrivateKey() } } export const nostrRemoteSigner = new NostrRemoteSigner()