diff --git a/src/daemon/backend/index.ts b/src/daemon/backend/index.ts index 49112fc..5d05a8a 100644 --- a/src/daemon/backend/index.ts +++ b/src/daemon/backend/index.ts @@ -45,12 +45,36 @@ export class Backend extends NDKNip46Backend { async start(): Promise { this.localUser = await this.signer.user(); await new Promise((resolve) => { + // Pin this subscription to the daemon's explicit relays via + // `relayUrls`. Without that, NDK 3.x's outbox routing tries to + // resolve the relay set from `this.localUser.pubkey`'s NIP-65 + // relay list (kind:10002). Newly-provisioned bunker keys have + // no published kind:10002 yet, so NDK's subscription manager + // queues the REQ waiting for a relay list that will never + // arrive — the kind:24133 subscription never lands on the + // wire, and inbound NIP-46 events (sign_event, get_public_key, + // nip44_*) targeted at this key get dropped by the relay + // with "Filter didn't match" because the bunker isn't actually + // subscribed for them. + // + // `relayUrls` was added in NDK 2.13.0 as the supported way to + // bypass outbox routing per subscription (see + // NDKSubscriptionOptions.relayUrls in @nostr-dev-kit/ndk). + // The relay set built from these URLs matches what the rest + // of the bunker uses (admin RPC channel + per-key Backend + // channels alike), so events flow through the same connection + // the admin interface already established. + // + // See aiolabs/nsecbunkerd#21. const sub = this.ndk.subscribe( { kinds: [24133], "#p": [this.localUser!.pubkey], }, - { closeOnEose: false } + { + closeOnEose: false, + relayUrls: this.ndk.explicitRelayUrls, + } ); sub.on("event", (e: any) => this.handleIncomingEvent(e)); sub.on("eose", () => resolve());