Summary
On the web login page, the only way to sign in with a remote signer is "Connect External Signer," which generates a nostrconnect:// URI. There is no way to paste a bunker:// connection string, even though the full implementation already exists in the codebase.
The nostrconnect flow has known interop issues across signer apps (client-generated URI, requires the signer to honor switch_relays, handle ephemeral kind:24133 events across a potentially hostile relay mix). The bunker:// flow is simpler and more reliable: user copies a URI from their signer app, pastes it, signer pubkey + relays are explicit.
What's already in place
authManager.authenticateWithNIP46(connectionString) — fully implemented, handles both bunker:// and npub1... wss://relay formats (src/lib/authManager.ts:313)
bunkerModal UI — styled, wired to loginWithBunker() (src/routes/login/+page.svelte:520-591)
- Capacitor deep-link handler accepts
bunker:// URIs (src/routes/+layout.svelte:120)
What's missing
Nothing in the login page sets bunkerModal = true. The modal and loginWithBunker() are dead code. The "Connect External Signer" button (src/routes/login/+page.svelte:1108) calls startUniversalPairing() — the nostrconnect:// generator — instead of opening the bunker modal.
Suggested fix
Split "Connect External Signer" into two entries, or make one a disclosure under the other:
- "Scan QR / Universal pairing" → current
startUniversalPairing()
- "Paste bunker URI" → sets
bunkerModal = true (reuses existing modal)
Either placement works; the key is giving users a path to the bunker flow without deep-linking from a signer app.
iOS sub-issue
src/components/LoginFormIOS.svelte comments that "NIP-46 (remote signers) are not supported due to platform restrictions." That's not accurate in the general case — iOS supports network-based NIP-46 fine (nsec.app web, Clave, and Amber-over-cloud all work there). The Apple review restrictions most signer apps run into are around nsec display/export, which the iOS flow already permits.
Even if QR scanning is out of scope for the iOS Capacitor build, iOS users could paste a bunker:// URI using the same modal. The existing authenticateWithNIP46 path already works for them — only the UI trigger is missing.
Repro
- Open https://zap.cooking/login in a browser
- Find "Connect External Signer" link in the advanced options row
- Click it → nostrconnect:// QR appears
- No way to paste a
bunker:// URI from an external signer
Context
Surfaced while debugging a signer compatibility matrix for Clave (an iOS NIP-46 signer). Happy to PR the minimal fix (one state setter + button split) if maintainers confirm the direction.
Summary
On the web login page, the only way to sign in with a remote signer is "Connect External Signer," which generates a
nostrconnect://URI. There is no way to paste abunker://connection string, even though the full implementation already exists in the codebase.The nostrconnect flow has known interop issues across signer apps (client-generated URI, requires the signer to honor
switch_relays, handle ephemeral kind:24133 events across a potentially hostile relay mix). Thebunker://flow is simpler and more reliable: user copies a URI from their signer app, pastes it, signer pubkey + relays are explicit.What's already in place
authManager.authenticateWithNIP46(connectionString)— fully implemented, handles bothbunker://andnpub1... wss://relayformats (src/lib/authManager.ts:313)bunkerModalUI — styled, wired tologinWithBunker()(src/routes/login/+page.svelte:520-591)bunker://URIs (src/routes/+layout.svelte:120)What's missing
Nothing in the login page sets
bunkerModal = true. The modal andloginWithBunker()are dead code. The "Connect External Signer" button (src/routes/login/+page.svelte:1108) callsstartUniversalPairing()— the nostrconnect:// generator — instead of opening the bunker modal.Suggested fix
Split "Connect External Signer" into two entries, or make one a disclosure under the other:
startUniversalPairing()bunkerModal = true(reuses existing modal)Either placement works; the key is giving users a path to the bunker flow without deep-linking from a signer app.
iOS sub-issue
src/components/LoginFormIOS.sveltecomments that "NIP-46 (remote signers) are not supported due to platform restrictions." That's not accurate in the general case — iOS supports network-based NIP-46 fine (nsec.app web, Clave, and Amber-over-cloud all work there). The Apple review restrictions most signer apps run into are around nsec display/export, which the iOS flow already permits.Even if QR scanning is out of scope for the iOS Capacitor build, iOS users could paste a
bunker://URI using the same modal. The existingauthenticateWithNIP46path already works for them — only the UI trigger is missing.Repro
bunker://URI from an external signerContext
Surfaced while debugging a signer compatibility matrix for Clave (an iOS NIP-46 signer). Happy to PR the minimal fix (one state setter + button split) if maintainers confirm the direction.