publish(task 10): nip-46 bunker-signer-wrapper mit timeout

createBunkerSigner(bunkerUrl) nutzt NostrConnectSigner.fromBunkerURI
aus applesauce-signers 2.x (früher als Nip46Signer im plan bezeichnet;
klassenname hat sich geändert). subscription- und publishMethod werden
global am class-constructor an einen shared RelayPool gekoppelt.
getPublicKey und signEvent bekommen je 30s-timeout mit sauberem
clearTimeout via withTimeout-helper. signer.ts ist vollständig, aber
ohne eigene unit-tests — integration folgt über check-subcommand
(task 16).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jörg Lohrer 2026-04-18 05:30:15 +02:00
parent 0a858371bf
commit 05ba4e4ef9
1 changed files with 40 additions and 0 deletions

View File

@ -0,0 +1,40 @@
import { NostrConnectSigner } from 'applesauce-signers'
import { RelayPool } from 'applesauce-relay'
import type { UnsignedEvent } from './event.ts'
import type { SignedEvent } from './relays.ts'
export interface Signer {
getPublicKey(): Promise<string>
signEvent(ev: UnsignedEvent): Promise<SignedEvent>
}
const signerPool = new RelayPool()
NostrConnectSigner.subscriptionMethod = (relays, filters) => signerPool.req(relays, filters)
NostrConnectSigner.publishMethod = (relays, event) => signerPool.event(relays, event)
function withTimeout<T>(p: Promise<T>, ms: number, label: string): Promise<T> {
let timerId: number | undefined
const timeoutPromise = new Promise<never>((_r, rej) => {
timerId = setTimeout(() => rej(new Error(`${label} timeout`)), ms)
})
return Promise.race([p, timeoutPromise]).finally(() => {
if (timerId !== undefined) clearTimeout(timerId)
}) as Promise<T>
}
export async function createBunkerSigner(bunkerUrl: string): Promise<Signer> {
const signer = await withTimeout(
NostrConnectSigner.fromBunkerURI(bunkerUrl),
30_000,
'Bunker connect',
)
const pubkey = await withTimeout(signer.getPublicKey(), 30_000, 'Bunker getPublicKey')
return {
getPublicKey: () => Promise.resolve(pubkey),
signEvent: async (ev: UnsignedEvent) => {
const signed = await withTimeout(signer.signEvent(ev), 30_000, 'Bunker signEvent')
return signed as SignedEvent
},
}
}