From 1407af22e38384e2ae789354ed15f6946c6f2113 Mon Sep 17 00:00:00 2001 From: Gigi Date: Fri, 17 Oct 2025 10:50:20 +0200 Subject: [PATCH] feat(debug): interactive /debug page (manual nip04/nip44 encrypt/decrypt, live logs); add DebugBus and wire signer logs --- src/App.tsx | 5 +- src/components/Debug.tsx | 111 +++++++++++++++++++++++++++++---------- src/utils/debugBus.ts | 36 +++++++++++++ 3 files changed, 122 insertions(+), 30 deletions(-) create mode 100644 src/utils/debugBus.ts diff --git a/src/App.tsx b/src/App.tsx index f368f1fb..623a975b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import { RelayPool } from 'applesauce-relay' import { NostrConnectSigner } from 'applesauce-signers' import { getDefaultBunkerPermissions } from './services/nostrConnect' import { createAddressLoader } from 'applesauce-loaders/loaders' +import Debug from './components/Debug' import Bookmarks from './components/Bookmarks' import RouteDebug from './components/RouteDebug' import Toast from './components/Toast' @@ -17,7 +18,7 @@ import { useToast } from './hooks/useToast' import { useOnlineStatus } from './hooks/useOnlineStatus' import { RELAYS } from './config/relays' import { SkeletonThemeProvider } from './components/Skeletons' -import Debug from './components/Debug' +import { DebugBus } from './utils/debugBus' const DEFAULT_ARTICLE = import.meta.env.VITE_DEFAULT_ARTICLE_NADDR || 'naddr1qvzqqqr4gupzqmjxss3dld622uu8q25gywum9qtg4w4cv4064jmg20xsac2aam5nqqxnzd3cxqmrzv3exgmr2wfesgsmew' @@ -336,6 +337,7 @@ function App() { contentLength: typeof content === 'string' ? content.length : undefined } console.log('[bunker] publish via signer:', summary) + try { DebugBus.info('bunker', 'publish', summary) } catch {} } catch (err) { console.warn('[bunker] failed to log publish summary', err) } return originalPublish(relays, event) } @@ -343,6 +345,7 @@ function App() { ;(recreatedSigner as unknown as { subscriptionMethod: (relays: string[], filters: unknown[]) => unknown }).subscriptionMethod = (relays: string[], filters: unknown[]) => { try { console.log('[bunker] subscribe via signer:', { relays, filters }) + try { DebugBus.info('bunker', 'subscribe', { relays, filters }) } catch {} } catch (err) { console.warn('[bunker] failed to log subscribe summary', err) } return originalSubscribe(relays, filters) } diff --git a/src/components/Debug.tsx b/src/components/Debug.tsx index 22918495..56256bba 100644 --- a/src/components/Debug.tsx +++ b/src/components/Debug.tsx @@ -1,55 +1,108 @@ -import React, { useMemo, useState } from 'react' +import React, { useEffect, useMemo, useState } from 'react' import { Hooks } from 'applesauce-react' +import { DebugBus, type DebugLogEntry } from '../utils/debugBus' + +const defaultPayload = 'The quick brown fox jumps over the lazy dog.' const Debug: React.FC = () => { const activeAccount = Hooks.useActiveAccount() - const [result, setResult] = useState('') - const [error, setError] = useState('') + const [payload, setPayload] = useState(defaultPayload) + const [cipher44, setCipher44] = useState('') + const [cipher04, setCipher04] = useState('') + const [plain44, setPlain44] = useState('') + const [plain04, setPlain04] = useState('') + const [logs, setLogs] = useState(DebugBus.snapshot()) + + useEffect(() => { + return DebugBus.subscribe((e) => setLogs(prev => [...prev, e].slice(-300))) + }, []) const signer = useMemo(() => (activeAccount as unknown as { signer?: unknown })?.signer, [activeAccount]) - const hasNip04 = typeof (signer as { nip04?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip04?.encrypt === 'function' - const hasNip44 = typeof (signer as { nip44?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip44?.encrypt === 'function' const pubkey = (activeAccount as unknown as { pubkey?: string })?.pubkey - const doRoundtrip = async (mode: 'nip04' | 'nip44') => { - setResult('') - setError('') - if (!signer || !pubkey) { - setError('No active signer/pubkey') - return - } + const hasNip04 = typeof (signer as { nip04?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip04?.encrypt === 'function' + const hasNip44 = typeof (signer as { nip44?: { encrypt?: unknown; decrypt?: unknown } } | undefined)?.nip44?.encrypt === 'function' + + const doEncrypt = async (mode: 'nip44' | 'nip04') => { + if (!signer || !pubkey) return try { const api = (signer as any)[mode] - if (!api || typeof api.encrypt !== 'function' || typeof api.decrypt !== 'function') { - setError(`${mode} not available on signer`) + DebugBus.info('debug', `encrypt start ${mode}`, { pubkey, len: payload.length }) + const cipher = await api.encrypt(pubkey, payload) + DebugBus.info('debug', `encrypt done ${mode}`, { len: typeof cipher === 'string' ? cipher.length : -1 }) + if (mode === 'nip44') setCipher44(cipher) + else setCipher04(cipher) + } catch (e) { + DebugBus.error('debug', `encrypt error ${mode}`, e instanceof Error ? e.message : String(e)) + } + } + + const doDecrypt = async (mode: 'nip44' | 'nip04') => { + if (!signer || !pubkey) return + try { + const api = (signer as any)[mode] + const cipher = mode === 'nip44' ? cipher44 : cipher04 + if (!cipher) { + DebugBus.warn('debug', `no cipher to decrypt for ${mode}`) return } - const cipher = await api.encrypt(pubkey, `debug-${mode}-${Date.now()}`) + DebugBus.info('debug', `decrypt start ${mode}`, { len: cipher.length }) const plain = await api.decrypt(pubkey, cipher) - setResult(String(plain)) + DebugBus.info('debug', `decrypt done ${mode}`, { len: typeof plain === 'string' ? plain.length : -1 }) + if (mode === 'nip44') setPlain44(String(plain)) + else setPlain04(String(plain)) } catch (e) { - setError(e instanceof Error ? e.message : String(e)) + DebugBus.error('debug', `decrypt error ${mode}`, e instanceof Error ? e.message : String(e)) } } return (
-

Debug / NIP-46 Echo

+

Debug / NIP-46 Tools

Active pubkey: {pubkey || 'none'}
-
Signer has nip04: {hasNip04 ? 'yes' : 'no'}
-
Signer has nip44: {hasNip44 ? 'yes' : 'no'}
-
- - +
+ +