chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create({ id: 'send-to-stash', title: 'Send to stash', contexts: ['page'], }); }); chrome.contextMenus.onClicked.addListener((info, tab) => { if (info.menuItemId === 'send-to-stash' && tab?.id) capture(tab.id); }); chrome.action.onClicked.addListener((tab) => { if (tab?.id) capture(tab.id); }); async function capture(tabId) { try { const [{ result }] = await chrome.scripting.executeScript({ target: { tabId }, files: ['lib/Readability.js', 'extract.js'], }); if (!result) throw new Error('extraction produced nothing'); const { serverUrl, token } = await chrome.storage.local.get(['serverUrl', 'token']); if (!serverUrl || !token) { notify('stash: not configured', 'Set the server URL and token in the extension options.'); chrome.runtime.openOptionsPage(); return; } const res = await fetch(`${serverUrl.replace(/\/$/, '')}/api/capture`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }, body: JSON.stringify(result), }); if (!res.ok) throw new Error(`server responded ${res.status}`); notify('Sent to stash', result.title); } catch (e) { notify('stash capture failed', String(e.message ?? e)); } } function notify(title, message) { chrome.notifications.create({ type: 'basic', iconUrl: 'data:image/svg+xml;base64,' + btoa(''), title, message, }); }