diff --git a/src/lib/capacitorAmberSigner.ts b/src/lib/capacitorAmberSigner.ts index 9d7bcf0..d992e06 100644 --- a/src/lib/capacitorAmberSigner.ts +++ b/src/lib/capacitorAmberSigner.ts @@ -2,35 +2,40 @@ * CapacitorAmberSigner * * A NostrSigner implementation that delegates all cryptographic operations - * to the nostr-signer-capacitor-plugin, which in turn communicates with - * Amber (or any NIP-55 compatible signer app) via native Android intents. + * to the nostr-signer-capacitor-plugin, which communicates with Amber + * (or any NIP-55 compatible signer app) via native Android intents. * - * This ONLY works inside a Capacitor native app. On web/PWA use AmberSigner - * (the intent:// URL redirect approach) instead. - * - * Usage: - * const signer = new CapacitorAmberSigner(pubkeyHex); - * const event = await signer.signEvent({ kind: 1, content: 'hello', tags: [], created_at: ... }); + * This ONLY works inside a Capacitor native app on Android. + * On web/PWA the AmberSigner (URL redirect) is used instead. */ import type { NostrEvent, NostrSigner } from '@nostrify/nostrify'; import { nip19 } from 'nostr-tools'; -// Amber's package name on Android — used to target the correct signer app. +// Amber's package name on Android const AMBER_PACKAGE_NAME = 'com.greenart7c3.nostrsigner'; /** - * Lazy-load the plugin and set the package name once. - * Returns null if not running inside Capacitor (web/PWA fallback). + * Load the plugin using its correct named export: NostrSignerPlugin. + * The plugin calls ensureAndroid() internally — if not on Android it throws + * with code ANDROID_ONLY. We catch that and return null so the web/PWA + * path is used instead. */ async function getPlugin() { try { - const mod = await import('nostr-signer-capacitor-plugin'); - const plugin = mod.default ?? mod.NostrSignerPlugin; - if (!plugin) return null; - await plugin.setPackageName({ packageName: AMBER_PACKAGE_NAME }); - return plugin; - } catch { + // Named export — NOT a default export + const { NostrSignerPlugin } = await import('nostr-signer-capacitor-plugin'); + if (!NostrSignerPlugin) return null; + // setPackageName takes a plain string, not { packageName: string } + await NostrSignerPlugin.setPackageName(AMBER_PACKAGE_NAME); + return NostrSignerPlugin; + } catch (e: unknown) { + // ANDROID_ONLY error = not on Android (web/PWA) — silent fallback + // Any other error = plugin not loaded correctly — log it + const code = (e as { code?: string })?.code; + if (code !== 'ANDROID_ONLY') { + console.error('[CapacitorAmberSigner] getPlugin failed:', e); + } return null; } } @@ -49,11 +54,9 @@ export class CapacitorAmberSigner implements NostrSigner { async signEvent(event: Omit): Promise { const plugin = await getPlugin(); if (!plugin) throw new Error('Capacitor Amber plugin not available'); - const { event: signedJson } = await plugin.signEvent({ eventJson: JSON.stringify(event), }); - return JSON.parse(signedJson) as NostrEvent; } @@ -88,24 +91,9 @@ export class CapacitorAmberSigner implements NostrSigner { }; } -/** - * Check if the Amber signer app is installed on the device. - * Returns false on web/PWA (plugin not available). - */ -export async function isAmberInstalled(): Promise { - const plugin = await getPlugin(); - if (!plugin) return false; - try { - const { installed } = await plugin.isExternalSignerInstalled(); - return installed; - } catch { - return false; - } -} - /** * Request the public key from Amber via the Capacitor plugin. - * Returns the hex pubkey string, or throws on failure/cancel. + * Returns hex pubkey string. Throws on failure or cancellation. */ export async function getAmberPublicKeyViaPlugin(): Promise { const plugin = await getPlugin(); @@ -118,3 +106,17 @@ export async function getAmberPublicKeyViaPlugin(): Promise { if (decoded.type !== 'npub') throw new Error('Unexpected key format from Amber plugin'); return decoded.data as string; } + +/** + * Check if Amber is installed. Returns false on web/PWA. + */ +export async function isAmberInstalled(): Promise { + const plugin = await getPlugin(); + if (!plugin) return false; + try { + const { installed } = await plugin.isExternalSignerInstalled(AMBER_PACKAGE_NAME); + return installed; + } catch { + return false; + } +}