fix(stash): guard nip44 getter to prevent crash when no signer/extension

Some signers throw "Browser extension not available" when the .nip44
getter is accessed rather than returning undefined. Wrap the check in a
try/catch so useStash never throws on mount for logged-out users or users
with signers that don't support NIP-44.

Co-authored-by: shakespeare.diy <assistant@shakespeare.diy>
This commit is contained in:
shakespeare.diy 2026-07-30 19:15:44 +07:00
parent af6847c669
commit 4c4e7159ba

View file

@ -50,11 +50,17 @@ export function useStash() {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { mutateAsync: createEvent } = useNostrPublish(); const { mutateAsync: createEvent } = useNostrPublish();
// Safely check if nip44 is available without throwing (some signers throw
// "Browser extension not available" when the getter is accessed with no login)
const hasNip44 = (() => {
try { return !!user?.signer?.nip44; } catch { return false; }
})();
// Fetch and decrypt stash // Fetch and decrypt stash
const { data: stash, isLoading, error } = useQuery({ const { data: stash, isLoading, error } = useQuery({
queryKey: ['stash', user?.pubkey], queryKey: ['stash', user?.pubkey],
queryFn: async ({ signal }): Promise<Stash> => { queryFn: async ({ signal }): Promise<Stash> => {
if (!user?.pubkey || !user.signer?.nip44) { if (!user?.pubkey || !hasNip44) {
return { items: [], updatedAt: 0 }; return { items: [], updatedAt: 0 };
} }
@ -76,7 +82,7 @@ export function useStash() {
try { try {
// Decrypt the content (encrypted to self) // Decrypt the content (encrypted to self)
const decrypted = await user.signer.nip44.decrypt(user.pubkey, event.content); const decrypted = await user.signer!.nip44!.decrypt(user.pubkey, event.content);
const stashData = JSON.parse(decrypted) as Stash; const stashData = JSON.parse(decrypted) as Stash;
return stashData; return stashData;
} catch (err) { } catch (err) {
@ -84,18 +90,18 @@ export function useStash() {
return { items: [], updatedAt: 0 }; return { items: [], updatedAt: 0 };
} }
}, },
enabled: !!user?.pubkey && !!user.signer?.nip44, enabled: !!user?.pubkey && hasNip44,
staleTime: 60000, // 1 minute staleTime: 60000, // 1 minute
}); });
// Save stash (encrypt and publish) // Save stash (encrypt and publish)
const saveStash = useCallback(async (newStash: Stash) => { const saveStash = useCallback(async (newStash: Stash) => {
if (!user?.pubkey || !user.signer?.nip44) { if (!user?.pubkey || !hasNip44) {
throw new Error('Encryption not available'); throw new Error('Encryption not available');
} }
// Encrypt to self // Encrypt to self
const encrypted = await user.signer.nip44.encrypt(user.pubkey, JSON.stringify(newStash)); const encrypted = await user.signer!.nip44!.encrypt(user.pubkey, JSON.stringify(newStash));
// Publish as replaceable event // Publish as replaceable event
await createEvent({ await createEvent({