import { clearSessionToken, getSessionToken, getStoredSession } from '@/background/backend-client'; import { getConnectionStatus, setConnectionStatus } from '@/background/connection-status'; import { applyLockState, getLockState } from '@/background/lock-state'; import { handleWalletConnected, requestWalletDisconnect, requestWalletReconnect } from '@/background/wallet-auth'; import { connectWsClient } from '@/background/ws-client'; import type { NexaMessage } from '@/shared/messaging'; export default defineBackground(() => { const ws = connectWsClient({ getToken: getSessionToken, onLockState: (state) => void applyLockState(state), onStatusChange: (status) => void setConnectionStatus(status), onAuthExpired: () => { void clearSessionToken().then(() => requestWalletReconnect()); }, }); async function signOut(): Promise { await clearSessionToken(); ws.disconnect(); await requestWalletDisconnect(); } browser.runtime.onMessage.addListener((message: NexaMessage, sender, sendResponse) => { switch (message?.type) { case 'nexa:get-lock-state': getLockState().then(sendResponse); return true; // keep the message channel open for the async response case 'nexa:get-connection-status': sendResponse(getConnectionStatus()); return false; case 'nexa:open-popup': // Best-effort: not all browsers/contexts allow programmatic popup // opening outside a direct user gesture on the action icon. browser.action.openPopup().catch(() => undefined); return false; case 'nexa:wallet-connected': // A content script reports this on every page load (it always tries // a silent onlyIfTrusted connect first), AND whenever the user // switches accounts in Phantom's own UI. Only re-authenticate (which // means asking Phantom to sign a fresh nonce — a popup every time, // unlike a silent connect) when this isn't the wallet we're already // signed in as; a bare "do we have a token" check can't tell those // apart from an account switch. getStoredSession() .then((session) => { if (session?.walletAddress === message.walletAddress) return; return handleWalletConnected(sender.tab?.id, message.walletAddress).then(() => ws.reconnectNow()); }) .catch((err) => console.debug('[nexa/background] wallet auth failed:', err)); // ws-client's own retry loop keeps trying regardless return false; case 'nexa:wallet-disconnected': // Disconnected directly in Phantom's UI (not via our own sign-out // flow, which already clears/disconnects itself) — treat the same way. void clearSessionToken().then(() => ws.disconnect()); return false; case 'nexa:sign-out': void signOut(); return false; default: return undefined; } }); });