diff --git a/.github/workflows/release-extension.yml b/.github/workflows/release-extension.yml index 8886e45..74cdb1d 100644 --- a/.github/workflows/release-extension.yml +++ b/.github/workflows/release-extension.yml @@ -15,34 +15,38 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Update Manifest Version + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: extension/package-lock.json + + - name: Install dependencies run: | - VERSION=${GITHUB_REF_NAME#v} - echo "Updating manifests to version $VERSION" + cd extension + npm ci + - name: Update Version + run: | + VERSION=${GITHUB_REF_NAME#v} + echo "Updating to version $VERSION" cd extension - for manifest in manifest.json manifest.chrome.json manifest.firefox.json; do - if [ -f "$manifest" ]; then - tmp=$(mktemp) - jq --arg v "$VERSION" '.version = $v' "$manifest" > "$tmp" && mv "$tmp" "$manifest" - echo "Updated $manifest" - fi - done - cd .. + tmp=$(mktemp) + jq --arg v "$VERSION" '.version = $v' package.json > "$tmp" && mv "$tmp" package.json - - name: Build Extension (Chrome) + - name: Build Chrome Extension run: | cd extension - cp manifest.chrome.json manifest.json - zip -r ../margin-extension-chrome.zip . -x "*.DS_Store" -x "*.git*" -x "manifest.*.json" - cd .. + npm run zip + cp .output/margin-extension-*.zip ../margin-extension-chrome.zip - - name: Build Extension (Firefox) + - name: Build Firefox Extension run: | cd extension - cp manifest.firefox.json manifest.json - zip -r ../margin-extension-firefox.xpi . -x "*.DS_Store" -x "*.git*" -x "manifest.*.json" - cd .. + npm run zip:firefox + cp .output/margin-extension-*-firefox.zip ../margin-extension-firefox.xpi + cp .output/margin-extension-*-sources.zip ../margin-extension-sources.zip - name: Publish to Chrome Web Store continue-on-error: true @@ -83,12 +87,12 @@ jobs: AMO_JWT_ISSUER: ${{ secrets.AMO_JWT_ISSUER }} AMO_JWT_SECRET: ${{ secrets.AMO_JWT_SECRET }} run: | - cd extension + cd extension/.output/firefox-mv3 COMMIT_MSG=$(git log -1 --pretty=%s) echo "{\"release_notes\": {\"en-US\": \"$COMMIT_MSG\"}, \"notes\": \"Thank you!\"}" > amo-metadata.json - npx web-ext sign --channel=listed --api-key=$AMO_JWT_ISSUER --api-secret=$AMO_JWT_SECRET --source-dir=. --artifacts-dir=../web-ext-artifacts --approval-timeout=300000 --amo-metadata=amo-metadata.json || echo "Web-ext sign timed out (expected), continuing..." + npx web-ext sign --channel=listed --api-key=$AMO_JWT_ISSUER --api-secret=$AMO_JWT_SECRET --source-dir=. --artifacts-dir=../../../web-ext-artifacts --approval-timeout=300000 --amo-metadata=amo-metadata.json || echo "Web-ext sign timed out (expected), continuing..." rm amo-metadata.json - cd .. + cd ../../.. - name: Prepare signed Firefox XPI run: | @@ -106,6 +110,7 @@ jobs: files: | margin-extension-chrome.zip margin-extension-firefox.xpi + margin-extension-sources.zip generate_release_notes: true draft: false prerelease: false diff --git a/.gitignore b/.gitignore index bc20c43..cc2200c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,10 @@ main margin-backend backend/server +# WXT +extension/.output/ +extension/.wxt/ + # Environment .env .env.local diff --git a/extension/.prettierrc b/extension/.prettierrc new file mode 100644 index 0000000..1f4c4bb --- /dev/null +++ b/extension/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "es5", + "printWidth": 100 +} diff --git a/extension/background/service-worker.js b/extension/background/service-worker.js deleted file mode 100644 index 471f2c5..0000000 --- a/extension/background/service-worker.js +++ /dev/null @@ -1,764 +0,0 @@ -let API_BASE = "https://margin.at"; -let WEB_BASE = "https://margin.at"; - -const hasSidePanel = - typeof chrome !== "undefined" && typeof chrome.sidePanel !== "undefined"; -const hasSidebarAction = - typeof browser !== "undefined" && - typeof browser.sidebarAction !== "undefined"; -const hasNotifications = - typeof chrome !== "undefined" && typeof chrome.notifications !== "undefined"; - -chrome.storage.local.get(["apiUrl"], (result) => { - if (result.apiUrl) { - updateBaseUrls(result.apiUrl); - } -}); - -function updateBaseUrls(url) { - let cleanUrl = url.replace(/\/$/, ""); - - if (cleanUrl.includes("ngrok") && cleanUrl.startsWith("http://")) { - cleanUrl = cleanUrl.replace("http://", "https://"); - } - - API_BASE = cleanUrl; - WEB_BASE = cleanUrl; - API_BASE = cleanUrl; - WEB_BASE = cleanUrl; -} - -function showNotification(title, message) { - if (hasNotifications) { - chrome.notifications.create({ - type: "basic", - iconUrl: "icons/android-chrome-192x192.png", - title: title, - message: message, - }); - } -} - -async function createHighlight(payload) { - if (!API_BASE) { - throw new Error("API URL not configured"); - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - throw new Error("Not authenticated"); - } - - const res = await fetch(`${API_BASE}/api/highlights`, { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - credentials: "include", - body: JSON.stringify(payload), - }); - - if (!res.ok) { - const errText = await res.text(); - throw new Error(`Failed to create highlight: ${res.status} ${errText}`); - } - - return res.json(); -} - -function refreshTabAnnotations(tabId) { - if (!tabId) return; - chrome.tabs.sendMessage(tabId, { type: "REFRESH_ANNOTATIONS" }).catch(() => { - /* ignore missing content script */ - }); -} - -async function openAnnotationUI(tabId, windowId) { - if (hasSidePanel) { - try { - let targetWindowId = windowId; - - if (!targetWindowId) { - const tab = await chrome.tabs.get(tabId); - targetWindowId = tab.windowId; - } - - await chrome.sidePanel.open({ windowId: targetWindowId }); - return true; - } catch (err) { - console.error("Could not open Chrome side panel:", err); - } - } - - if (hasSidebarAction) { - try { - await browser.sidebarAction.open(); - return true; - } catch (err) { - console.warn("Could not open Firefox sidebar:", err); - } - } - - return false; -} - -chrome.runtime.onInstalled.addListener(async () => { - const stored = await chrome.storage.local.get(["apiUrl"]); - if (!stored.apiUrl) { - await chrome.storage.local.set({ apiUrl: "https://margin.at" }); - updateBaseUrls("https://margin.at"); - } - - await ensureContextMenus(); - - if (hasSidebarAction) { - try { - await browser.sidebarAction.close(); - } catch { - /* ignore */ - } - } -}); - -chrome.runtime.onStartup.addListener(async () => { - await ensureContextMenus(); -}); - -async function ensureContextMenus() { - await chrome.contextMenus.removeAll(); - - chrome.contextMenus.create({ - id: "margin-annotate", - title: 'Annotate "%s"', - contexts: ["selection"], - }); - - chrome.contextMenus.create({ - id: "margin-highlight", - title: 'Highlight "%s"', - contexts: ["selection"], - }); - - chrome.contextMenus.create({ - id: "margin-bookmark", - title: "Bookmark this page", - contexts: ["page"], - }); - - chrome.contextMenus.create({ - id: "margin-open-sidebar", - title: "Open Margin Sidebar", - contexts: ["page", "selection", "link"], - }); -} - -chrome.action.onClicked.addListener(async () => { - const stored = await chrome.storage.local.get(["apiUrl"]); - const webUrl = stored.apiUrl || WEB_BASE; - chrome.tabs.create({ url: webUrl }); -}); - -chrome.contextMenus.onClicked.addListener(async (info, tab) => { - if (info.menuItemId === "margin-open-sidebar") { - await openAnnotationUI(tab.id, tab.windowId); - return; - } - - if (info.menuItemId === "margin-bookmark") { - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - showNotification("Margin", "Please sign in to bookmark pages"); - return; - } - - try { - const res = await fetch(`${API_BASE}/api/bookmarks`, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify({ - url: tab.url, - title: tab.title, - }), - }); - - if (res.ok) { - showNotification("Margin", "Page bookmarked!"); - } - } catch (err) { - console.error("Bookmark error:", err); - } - return; - } - - if (info.menuItemId === "margin-annotate") { - let selector = null; - let canonicalUrl = null; - - try { - const response = await chrome.tabs.sendMessage(tab.id, { - type: "GET_SELECTOR_FOR_ANNOTATE_INLINE", - selectionText: info.selectionText, - }); - selector = response?.selector; - canonicalUrl = response?.canonicalUrl; - } catch { - /* ignore */ - } - - if (!selector && info.selectionText) { - selector = { - type: "TextQuoteSelector", - exact: info.selectionText, - }; - } - - const targetUrl = canonicalUrl || tab.url; - - if (selector) { - try { - await chrome.tabs.sendMessage(tab.id, { - type: "SHOW_INLINE_ANNOTATE", - data: { - url: targetUrl, - title: tab.title, - selector: selector, - }, - }); - return; - } catch (e) { - console.debug("Inline annotate failed, falling back to new tab:", e); - } - } - - if (WEB_BASE) { - let composeUrl = `${WEB_BASE}/new?url=${encodeURIComponent(targetUrl)}`; - if (selector) { - composeUrl += `&selector=${encodeURIComponent(JSON.stringify(selector))}`; - } - chrome.tabs.create({ url: composeUrl }); - } - return; - } - - if (info.menuItemId === "margin-highlight") { - let selector = null; - let canonicalUrl = null; - - try { - const response = await chrome.tabs.sendMessage(tab.id, { - type: "GET_SELECTOR_FOR_HIGHLIGHT", - selectionText: info.selectionText, - }); - if (response?.selector) { - selector = response.selector; - canonicalUrl = response.canonicalUrl; - } - if (response && response.success) return; - } catch { - /* ignore */ - } - - if (!selector && info.selectionText) { - selector = { - type: "TextQuoteSelector", - exact: info.selectionText, - }; - } - - const targetUrl = canonicalUrl || tab.url; - - if (selector) { - try { - await createHighlight({ - url: targetUrl, - title: tab.title, - selector: selector, - }); - showNotification("Margin", "Text highlighted!"); - refreshTabAnnotations(tab.id); - } catch (err) { - console.error("Highlight API error:", err); - if (err?.message === "Not authenticated") { - showNotification("Margin", "Please sign in to create highlights"); - return; - } - showNotification("Margin", "Error creating highlight"); - } - } else { - showNotification("Margin", "No text selected"); - } - } -}); - -chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - handleMessage(request, sender, sendResponse); - return true; -}); - -async function handleMessage(request, sender, sendResponse) { - try { - if (request.type === "UPDATE_SETTINGS") { - const result = await chrome.storage.local.get(["apiUrl"]); - if (result.apiUrl) updateBaseUrls(result.apiUrl); - sendResponse({ success: true }); - return; - } - - switch (request.type) { - case "CHECK_SESSION": { - if (!API_BASE) { - sendResponse({ success: true, data: { authenticated: false } }); - return; - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: true, data: { authenticated: false } }); - return; - } - - try { - const response = await fetch(`${API_BASE}/auth/session`, { - credentials: "include", - }); - - if (!response.ok) { - sendResponse({ success: true, data: { authenticated: false } }); - return; - } - - const sessionData = await response.json(); - sendResponse({ - success: true, - data: { - authenticated: true, - did: sessionData.did, - handle: sessionData.handle, - }, - }); - } catch (err) { - console.error("Session check error:", err); - sendResponse({ success: true, data: { authenticated: false } }); - } - break; - } - - case "GET_ANNOTATIONS": { - const stored = await chrome.storage.local.get(["apiUrl"]); - const currentApiUrl = stored.apiUrl - ? stored.apiUrl.replace(/\/$/, "") - : API_BASE; - - const pageUrl = request.data.url; - const citedUrls = request.data.citedUrls || []; - const uniqueUrls = [...new Set([pageUrl, ...citedUrls])]; - - const fetchPromises = uniqueUrls.map((u) => - fetch( - `${currentApiUrl}/api/targets?source=${encodeURIComponent(u)}`, - ).then((r) => r.json().catch(() => ({}))), - ); - - const results = await Promise.all(fetchPromises); - let allItems = []; - const seenIds = new Set(); - - results.forEach((data) => { - const items = [ - ...(data.annotations || []), - ...(data.highlights || []), - ...(data.bookmarks || []), - ]; - items.forEach((item) => { - const id = item.uri || item.id; - if (id && !seenIds.has(id)) { - seenIds.add(id); - allItems.push(item); - } - }); - }); - - sendResponse({ success: true, data: allItems }); - - if (sender.tab) { - const count = allItems.length; - chrome.action - .setBadgeText({ - text: count > 0 ? count.toString() : "", - tabId: sender.tab.id, - }) - .catch(() => { - /* ignore */ - }); - chrome.action - .setBadgeBackgroundColor({ - color: "#6366f1", - tabId: sender.tab.id, - }) - .catch(() => { - /* ignore */ - }); - } - break; - } - - case "CREATE_ANNOTATION": { - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: false, error: "Not authenticated" }); - return; - } - - const payload = { - url: request.data.url, - text: request.data.text, - title: request.data.title, - }; - - if (request.data.selector) { - payload.selector = request.data.selector; - } - - const createRes = await fetch(`${API_BASE}/api/annotations`, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify(payload), - }); - - if (!createRes.ok) { - const errorText = await createRes.text(); - throw new Error( - `Failed to create annotation: ${createRes.status} ${errorText}`, - ); - } - - const createData = await createRes.json(); - sendResponse({ success: true, data: createData }); - break; - } - - case "OPEN_LOGIN": - if (!WEB_BASE) { - chrome.runtime.openOptionsPage(); - return; - } - chrome.tabs.create({ url: `${WEB_BASE}/login` }); - break; - - case "OPEN_WEB": - if (!WEB_BASE) { - chrome.runtime.openOptionsPage(); - return; - } - chrome.tabs.create({ url: `${WEB_BASE}` }); - break; - - case "OPEN_COMPOSE": { - if (!WEB_BASE) { - chrome.runtime.openOptionsPage(); - return; - } - const { url, selector } = request.data; - let composeUrl = `${WEB_BASE}/new?url=${encodeURIComponent(url)}`; - if (selector) { - composeUrl += `&selector=${encodeURIComponent(JSON.stringify(selector))}`; - } - chrome.tabs.create({ url: composeUrl }); - break; - } - - case "OPEN_APP_URL": { - if (!WEB_BASE) { - chrome.runtime.openOptionsPage(); - return; - } - const path = request.data.path; - const safePath = path.startsWith("/") ? path : `/${path}`; - chrome.tabs.create({ url: `${WEB_BASE}${safePath}` }); - break; - } - - case "OPEN_SIDE_PANEL": - if (sender.tab && sender.tab.windowId) { - chrome.sidePanel - .open({ windowId: sender.tab.windowId }) - .catch((err) => console.error("Failed to open side panel", err)); - } - break; - - case "CREATE_BOOKMARK": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: false, error: "Not authenticated" }); - return; - } - - const bookmarkRes = await fetch(`${API_BASE}/api/bookmarks`, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify({ - url: request.data.url, - title: request.data.title, - }), - }); - - if (!bookmarkRes.ok) { - const errorText = await bookmarkRes.text(); - throw new Error( - `Failed to create bookmark: ${bookmarkRes.status} ${errorText}`, - ); - } - - const bookmarkData = await bookmarkRes.json(); - sendResponse({ success: true, data: bookmarkData }); - break; - } - - case "CREATE_HIGHLIGHT": { - try { - const highlightData = await createHighlight({ - url: request.data.url, - title: request.data.title, - selector: request.data.selector, - color: request.data.color || "yellow", - }); - sendResponse({ success: true, data: highlightData }); - refreshTabAnnotations(sender.tab?.id); - } catch (error) { - sendResponse({ success: false, error: error.message }); - } - break; - } - - case "GET_USER_BOOKMARKS": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const did = request.data.did; - const res = await fetch( - `${API_BASE}/api/users/${encodeURIComponent(did)}/bookmarks`, - ); - - if (!res.ok) { - throw new Error(`Failed to fetch bookmarks: ${res.status}`); - } - - const data = await res.json(); - sendResponse({ success: true, data: data.items || [] }); - break; - } - - case "GET_USER_HIGHLIGHTS": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const did = request.data.did; - const res = await fetch( - `${API_BASE}/api/users/${encodeURIComponent(did)}/highlights`, - ); - - if (!res.ok) { - throw new Error(`Failed to fetch highlights: ${res.status}`); - } - - const data = await res.json(); - sendResponse({ success: true, data: data.items || [] }); - break; - } - - case "GET_USER_COLLECTIONS": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const did = request.data.did; - const res = await fetch( - `${API_BASE}/api/collections?author=${encodeURIComponent(did)}`, - ); - - if (!res.ok) { - throw new Error(`Failed to fetch collections: ${res.status}`); - } - - const data = await res.json(); - sendResponse({ success: true, data: data.items || [] }); - break; - } - - case "GET_CONTAINING_COLLECTIONS": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const uri = request.data.uri; - const res = await fetch( - `${API_BASE}/api/collections/containing?uri=${encodeURIComponent(uri)}`, - ); - - if (!res.ok) { - throw new Error( - `Failed to fetch containing collections: ${res.status}`, - ); - } - - const data = await res.json(); - sendResponse({ success: true, data: data || [] }); - break; - } - - case "ADD_TO_COLLECTION": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: false, error: "Not authenticated" }); - return; - } - - const { collectionUri, annotationUri } = request.data; - const res = await fetch( - `${API_BASE}/api/collections/${encodeURIComponent(collectionUri)}/items`, - { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify({ - annotationUri: annotationUri, - }), - }, - ); - - if (!res.ok) { - const errText = await res.text(); - throw new Error( - `Failed to add to collection: ${res.status} ${errText}`, - ); - } - - const data = await res.json(); - sendResponse({ success: true, data }); - break; - } - - case "GET_REPLIES": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const uri = request.data.uri; - const res = await fetch( - `${API_BASE}/api/replies?uri=${encodeURIComponent(uri)}`, - ); - - if (!res.ok) { - throw new Error(`Failed to fetch replies: ${res.status}`); - } - - const data = await res.json(); - sendResponse({ success: true, data: data.items || [] }); - break; - } - - case "CREATE_REPLY": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: false, error: "Not authenticated" }); - return; - } - - const { parentUri, parentCid, rootUri, rootCid, text } = request.data; - const res = await fetch(`${API_BASE}/api/annotations/reply`, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify({ - parentUri, - parentCid, - rootUri, - rootCid, - text, - }), - }); - - if (!res.ok) { - const errText = await res.text(); - throw new Error(`Failed to create reply: ${res.status} ${errText}`); - } - - const data = await res.json(); - sendResponse({ success: true, data }); - break; - } - } - } catch (error) { - console.error("Service worker error:", error); - sendResponse({ success: false, error: error.message }); - } -} diff --git a/extension/bun.lock b/extension/bun.lock new file mode 100644 index 0000000..1ef497e --- /dev/null +++ b/extension/bun.lock @@ -0,0 +1,1301 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "margin-extension", + "dependencies": { + "@webext-core/messaging": "^1.4.0", + "clsx": "^2.1.1", + "lucide-react": "^0.563.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + }, + "devDependencies": { + "@eslint/js": "^9.39.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@wxt-dev/module-react": "^1.1.1", + "autoprefixer": "^10.4.20", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "postcss": "^8.4.49", + "prettier": "^3.8.1", + "tailwindcss": "^3.4.15", + "typescript": "^5.6.3", + "typescript-eslint": "^8.54.0", + "wxt": "^0.19.13", + }, + }, + }, + "packages": { + "@1natsu/wait-element": ["@1natsu/wait-element@4.1.2", "", { "dependencies": { "defu": "^6.1.4", "many-keys-map": "^2.0.1" } }, "sha512-qWxSJD+Q5b8bKOvESFifvfZ92DuMsY+03SBNjTO34ipJLP6mZ9yK4bQz/vlh48aEQXoJfaZBqUwKL5BdI5iiWw=="], + + "@aklinker1/rollup-plugin-visualizer": ["@aklinker1/rollup-plugin-visualizer@5.12.0", "", { "dependencies": { "open": "^8.4.0", "picomatch": "^2.3.1", "source-map": "^0.7.4", "yargs": "^17.5.1" }, "peerDependencies": { "rollup": "2.x || 3.x || 4.x" }, "optionalPeers": ["rollup"], "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-X24LvEGw6UFmy0lpGJDmXsMyBD58XmX1bbwsaMLhNoM+UMQfQ3b2RtC+nz4b/NoRK5r6QJSKJHBNVeUdwqybaQ=="], + + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.0", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], + + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], + + "@babel/runtime": ["@babel/runtime@7.28.2", "", {}, "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@devicefarmer/adbkit": ["@devicefarmer/adbkit@3.3.8", "", { "dependencies": { "@devicefarmer/adbkit-logcat": "^2.1.2", "@devicefarmer/adbkit-monkey": "~1.2.1", "bluebird": "~3.7", "commander": "^9.1.0", "debug": "~4.3.1", "node-forge": "^1.3.1", "split": "~1.0.1" }, "bin": { "adbkit": "bin/adbkit" } }, "sha512-7rBLLzWQnBwutH2WZ0EWUkQdihqrnLYCUMaB44hSol9e0/cdIhuNFcqZO0xNheAU6qqHVA8sMiLofkYTgb+lmw=="], + + "@devicefarmer/adbkit-logcat": ["@devicefarmer/adbkit-logcat@2.1.3", "", {}, "sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw=="], + + "@devicefarmer/adbkit-monkey": ["@devicefarmer/adbkit-monkey@1.2.1", "", {}, "sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.12", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.12", "", { "os": "android", "cpu": "arm" }, "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.12", "", { "os": "android", "cpu": "arm64" }, "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.12", "", { "os": "android", "cpu": "x64" }, "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.12", "", { "os": "darwin", "cpu": "x64" }, "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.12", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.12", "", { "os": "freebsd", "cpu": "x64" }, "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.12", "", { "os": "linux", "cpu": "arm" }, "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.12", "", { "os": "linux", "cpu": "arm64" }, "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.12", "", { "os": "linux", "cpu": "ia32" }, "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.12", "", { "os": "linux", "cpu": "ppc64" }, "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.12", "", { "os": "linux", "cpu": "none" }, "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.12", "", { "os": "linux", "cpu": "s390x" }, "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.12", "", { "os": "linux", "cpu": "x64" }, "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.12", "", { "os": "none", "cpu": "x64" }, "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.12", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.12", "", { "os": "openbsd", "cpu": "x64" }, "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.12", "", { "os": "none", "cpu": "arm64" }, "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.12", "", { "os": "sunos", "cpu": "x64" }, "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.12", "", { "os": "win32", "cpu": "arm64" }, "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.12", "", { "os": "win32", "cpu": "ia32" }, "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], + + "@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], + + "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@pnpm/config.env-replace": ["@pnpm/config.env-replace@1.1.0", "", {}, "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w=="], + + "@pnpm/network.ca-file": ["@pnpm/network.ca-file@1.0.2", "", { "dependencies": { "graceful-fs": "4.2.10" } }, "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA=="], + + "@pnpm/npm-conf": ["@pnpm/npm-conf@3.0.2", "", { "dependencies": { "@pnpm/config.env-replace": "^1.1.0", "@pnpm/network.ca-file": "^1.0.1", "config-chain": "^1.1.11" } }, "sha512-h104Kh26rR8tm+a3Qkc5S4VLYint3FE48as7+/5oCEcKR2idC/pF1G6AhIXKI+eHPJa/3J9i5z0Al47IeGHPkA=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/chrome": ["@types/chrome@0.0.280", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-AotSmZrL9bcZDDmSI1D9dE7PGbhOur5L0cKxXd7IqbVizQWCY4gcvupPUVsQ4FfDj3V2tt/iOpomT9EY0s+w1g=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/filesystem": ["@types/filesystem@0.0.36", "", { "dependencies": { "@types/filewriter": "*" } }, "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA=="], + + "@types/filewriter": ["@types/filewriter@0.0.33", "", {}, "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g=="], + + "@types/har-format": ["@types/har-format@1.2.16", "", {}, "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/minimatch": ["@types/minimatch@3.0.5", "", {}, "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="], + + "@types/node": ["@types/node@25.1.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA=="], + + "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], + + "@types/react": ["@types/react@18.3.27", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w=="], + + "@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="], + + "@types/webextension-polyfill": ["@types/webextension-polyfill@0.12.4", "", {}, "sha512-wK8YdSI0pDiaehSLDIvtvonYmLwUUivg4Z6JCJO8rkyssMAG82cFJgwPK/V7NO61mJBLg/tXeoXQL8AFzpXZmQ=="], + + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="], + + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="], + + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="], + + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="], + + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="], + + "@webext-core/fake-browser": ["@webext-core/fake-browser@1.3.4", "", { "dependencies": { "lodash.merge": "^4.6.2" } }, "sha512-nZcVWr3JpwpS5E6hKpbAwAMBM/AXZShnfW0F76udW8oLd6Kv0nbW6vFS07md4Na/0ntQonk3hFnlQYGYBAlTrA=="], + + "@webext-core/isolated-element": ["@webext-core/isolated-element@1.1.3", "", { "dependencies": { "is-potential-custom-element-name": "^1.0.1" } }, "sha512-rbtnReIGdiVQb2UhK3MiECU6JqsiIo2K/luWvOdOw57Ot770Iw4KLCEPXUQMITIH5V5er2jfVK8hSWXaEOQGNQ=="], + + "@webext-core/match-patterns": ["@webext-core/match-patterns@1.0.3", "", {}, "sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A=="], + + "@webext-core/messaging": ["@webext-core/messaging@1.4.0", "", { "dependencies": { "serialize-error": "^11.0.0", "webextension-polyfill": "^0.10.0" } }, "sha512-gzXQ13HfKR3Yrn9TnrvTC/5seA7uPFvaqxqNFBsFOOdSZa5LyXt58Rhym8BYXarkWUGp+fh8f6AYM3RYuNbS+A=="], + + "@wxt-dev/browser": ["@wxt-dev/browser@0.1.32", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*" } }, "sha512-jvfSppeLzlH4sOkIvMBJoA1pKoI+U5gTkjDwMKdkTWh0P/fj+KDyze3lzo3S6372viCm8tXUKNez+VKyVz2ZDw=="], + + "@wxt-dev/module-react": ["@wxt-dev/module-react@1.1.5", "", { "dependencies": { "@vitejs/plugin-react": "^4.4.1 || ^5.0.0" }, "peerDependencies": { "wxt": ">=0.19.16" } }, "sha512-KgsUrsgH5rBT8MwiipnDEOHBXmLvTIdFICrI7KjngqSf9DpVRn92HsKmToxY0AYpkP19hHWta2oNYFTzmmm++g=="], + + "@wxt-dev/storage": ["@wxt-dev/storage@1.2.6", "", { "dependencies": { "@wxt-dev/browser": "^0.1.4", "async-mutex": "^0.5.0", "dequal": "^2.0.3" } }, "sha512-f6AknnpJvhNHW4s0WqwSGCuZAj0fjP3EVNPBO5kB30pY+3Zt/nqZGqJN6FgBLCSkYjPJ8VL1hNX5LMVmvxQoDw=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "adm-zip": ["adm-zip@0.5.16", "", {}, "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "^4.1.0" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], + + "ansi-escapes": ["ansi-escapes@7.2.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw=="], + + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], + + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], + + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "array-differ": ["array-differ@4.0.0", "", {}, "sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw=="], + + "array-union": ["array-union@3.0.1", "", {}, "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw=="], + + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "async-mutex": ["async-mutex@0.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA=="], + + "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + + "atomically": ["atomically@2.1.0", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q=="], + + "autoprefixer": ["autoprefixer@10.4.24", "", { "dependencies": { "browserslist": "^4.28.1", "caniuse-lite": "^1.0.30001766", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.9.19", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg=="], + + "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], + + "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "boxen": ["boxen@8.0.1", "", { "dependencies": { "ansi-align": "^3.0.1", "camelcase": "^8.0.0", "chalk": "^5.3.0", "cli-boxes": "^3.0.0", "string-width": "^7.2.0", "type-fest": "^4.21.0", "widest-line": "^5.0.0", "wrap-ansi": "^9.0.0" } }, "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], + + "c12": ["c12@3.3.3", "", { "dependencies": { "chokidar": "^5.0.0", "confbox": "^0.2.2", "defu": "^6.1.4", "dotenv": "^17.2.3", "exsolve": "^1.0.8", "giget": "^2.0.0", "jiti": "^2.6.1", "ohash": "^2.0.11", "pathe": "^2.0.3", "perfect-debounce": "^2.0.0", "pkg-types": "^2.3.0", "rc9": "^2.1.2" }, "peerDependencies": { "magicast": "*" }, "optionalPeers": ["magicast"] }, "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="], + + "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001766", "", {}, "sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + + "chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], + + "chrome-launcher": ["chrome-launcher@1.2.0", "", { "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", "is-wsl": "^2.2.0", "lighthouse-logger": "^2.0.1" }, "bin": { "print-chrome-path": "bin/print-chrome-path.cjs" } }, "sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q=="], + + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], + + "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + + "cli-cursor": ["cli-cursor@5.0.0", "", { "dependencies": { "restore-cursor": "^5.0.0" } }, "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw=="], + + "cli-spinners": ["cli-spinners@2.9.2", "", {}, "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg=="], + + "cli-truncate": ["cli-truncate@4.0.0", "", { "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" } }, "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "colorette": ["colorette@2.0.20", "", {}, "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="], + + "commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "concat-stream": ["concat-stream@1.6.2", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" } }, "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="], + + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], + + "config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="], + + "configstore": ["configstore@7.1.0", "", { "dependencies": { "atomically": "^2.0.3", "dot-prop": "^9.0.0", "graceful-fs": "^4.2.11", "xdg-basedir": "^5.1.0" } }, "sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg=="], + + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "debounce": ["debounce@1.2.1", "", {}, "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "default-browser": ["default-browser@5.4.0", "", { "dependencies": { "bundle-name": "^4.1.0", "default-browser-id": "^5.0.0" } }, "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg=="], + + "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], + + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "destr": ["destr@2.0.5", "", {}, "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA=="], + + "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], + + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-prop": ["dot-prop@9.0.0", "", { "dependencies": { "type-fest": "^4.18.2" } }, "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ=="], + + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "dotenv-expand": ["dotenv-expand@12.0.3", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.283", "", {}, "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + + "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-goat": ["escape-goat@4.0.0", "", {}, "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], + + "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="], + + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-redact": ["fast-redact@3.5.0", "", {}, "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "filesize": ["filesize@10.1.6", "", {}, "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "firefox-profile": ["firefox-profile@4.7.0", "", { "dependencies": { "adm-zip": "~0.5.x", "fs-extra": "^11.2.0", "ini": "^4.1.3", "minimist": "^1.2.8", "xml2js": "^0.6.2" }, "bin": { "firefox-profile": "lib/cli.js" } }, "sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "form-data-encoder": ["form-data-encoder@4.1.0", "", {}, "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw=="], + + "formdata-node": ["formdata-node@6.0.3", "", {}, "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg=="], + + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + + "fs-extra": ["fs-extra@11.3.3", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg=="], + + "fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "fx-runner": ["fx-runner@1.4.0", "", { "dependencies": { "commander": "2.9.0", "shell-quote": "1.7.3", "spawn-sync": "1.0.15", "when": "3.7.7", "which": "1.2.4", "winreg": "0.0.12" }, "bin": { "fx-runner": "bin/fx-runner" } }, "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.4.0", "", {}, "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q=="], + + "get-port-please": ["get-port-please@3.2.0", "", {}, "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A=="], + + "get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="], + + "giget": ["giget@1.2.5", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.5.4", "pathe": "^2.0.3", "tar": "^6.2.1" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + + "global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="], + + "globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "graceful-readlink": ["graceful-readlink@1.0.1", "", {}, "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w=="], + + "growly": ["growly@1.3.0", "", {}, "sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="], + + "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], + + "htmlparser2": ["htmlparser2@10.1.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", "domutils": "^3.2.2", "entities": "^7.0.1" } }, "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ=="], + + "human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "immediate": ["immediate@3.0.6", "", {}, "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "import-meta-resolve": ["import-meta-resolve@4.2.0", "", {}, "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@4.1.3", "", {}, "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg=="], + + "is-absolute": ["is-absolute@0.1.7", "", { "dependencies": { "is-relative": "^0.1.0" } }, "sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-in-ci": ["is-in-ci@1.0.0", "", { "bin": { "is-in-ci": "cli.js" } }, "sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg=="], + + "is-inside-container": ["is-inside-container@1.0.0", "", { "dependencies": { "is-docker": "^3.0.0" }, "bin": { "is-inside-container": "cli.js" } }, "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA=="], + + "is-installed-globally": ["is-installed-globally@1.0.0", "", { "dependencies": { "global-directory": "^4.0.1", "is-path-inside": "^4.0.0" } }, "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ=="], + + "is-interactive": ["is-interactive@2.0.0", "", {}, "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ=="], + + "is-npm": ["is-npm@6.1.0", "", {}, "sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-path-inside": ["is-path-inside@4.0.0", "", {}, "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA=="], + + "is-plain-object": ["is-plain-object@2.0.4", "", { "dependencies": { "isobject": "^3.0.1" } }, "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="], + + "is-potential-custom-element-name": ["is-potential-custom-element-name@1.0.1", "", {}, "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="], + + "is-primitive": ["is-primitive@3.0.1", "", {}, "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w=="], + + "is-relative": ["is-relative@0.1.3", "", {}, "sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA=="], + + "is-stream": ["is-stream@3.0.0", "", {}, "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA=="], + + "is-unicode-supported": ["is-unicode-supported@2.1.0", "", {}, "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ=="], + + "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="], + + "isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "isobject": ["isobject@3.0.1", "", {}, "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="], + + "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@3.0.2", "", {}, "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + + "jszip": ["jszip@3.10.1", "", { "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" } }, "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="], + + "ky": ["ky@1.14.3", "", {}, "sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw=="], + + "latest-version": ["latest-version@9.0.0", "", { "dependencies": { "package-json": "^10.0.0" } }, "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lie": ["lie@3.3.0", "", { "dependencies": { "immediate": "~3.0.5" } }, "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ=="], + + "lighthouse-logger": ["lighthouse-logger@2.0.2", "", { "dependencies": { "debug": "^4.4.1", "marky": "^1.2.2" } }, "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg=="], + + "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "linkedom": ["linkedom@0.18.12", "", { "dependencies": { "css-select": "^5.1.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q=="], + + "listr2": ["listr2@8.3.3", "", { "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.1.0", "rfdc": "^1.4.1", "wrap-ansi": "^9.0.0" } }, "sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ=="], + + "local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "log-symbols": ["log-symbols@6.0.0", "", { "dependencies": { "chalk": "^5.3.0", "is-unicode-supported": "^1.3.0" } }, "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw=="], + + "log-update": ["log-update@6.1.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "cli-cursor": "^5.0.0", "slice-ansi": "^7.1.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], + + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + + "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="], + + "make-error": ["make-error@1.3.6", "", {}, "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="], + + "many-keys-map": ["many-keys-map@2.0.1", "", {}, "sha512-DHnZAD4phTbZ+qnJdjoNEVU1NecYoSdbOOoVmTDH46AuxDkEVh3MxTVpXq10GtcTC6mndN9dkv1rNfpjRcLnOw=="], + + "marky": ["marky@1.3.0", "", {}, "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mimic-fn": ["mimic-fn@4.0.0", "", {}, "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw=="], + + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="], + + "minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="], + + "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + + "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "multimatch": ["multimatch@6.0.0", "", { "dependencies": { "@types/minimatch": "^3.0.5", "array-differ": "^4.0.0", "array-union": "^3.0.1", "minimatch": "^3.0.4" } }, "sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ=="], + + "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], + + "nano-spawn": ["nano-spawn@0.2.1", "", {}, "sha512-/pULofvsF8mOVcl/nUeVXL/GYOEvc7eJWSIxa+K4OYUolvXa5zwSgevsn4eoHs1xvh/BO3vx/PZiD9+Ow2ZVuw=="], + + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "node-fetch-native": ["node-fetch-native@1.6.7", "", {}, "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q=="], + + "node-forge": ["node-forge@1.3.3", "", {}, "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg=="], + + "node-notifier": ["node-notifier@10.0.1", "", { "dependencies": { "growly": "^1.3.0", "is-wsl": "^2.2.0", "semver": "^7.3.5", "shellwords": "^0.1.1", "uuid": "^8.3.2", "which": "^2.0.2" } }, "sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ=="], + + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], + + "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], + + "npm-run-path": ["npm-run-path@5.3.0", "", { "dependencies": { "path-key": "^4.0.0" } }, "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "nypm": ["nypm@0.3.12", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.2.3", "execa": "^8.0.1", "pathe": "^1.1.2", "pkg-types": "^1.2.0", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-D3pzNDWIvgA+7IORhD/IuWzEk4uXv6GsgOxiid4UU3h9oq5IqV1KtPDi63n4sZJ/xcWlr88c0QM2RgN5VbOhFA=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + + "ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="], + + "ohash": ["ohash@1.1.6", "", {}, "sha512-TBu7PtV8YkAZn0tSxobKY2n2aAQva936lhRrj6957aDaCf9IEtqsKbgMzXE/F/sjqYOwmrukeORHNLe5glk7Cg=="], + + "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], + + "onetime": ["onetime@6.0.0", "", { "dependencies": { "mimic-fn": "^4.0.0" } }, "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ=="], + + "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "ora": ["ora@8.2.0", "", { "dependencies": { "chalk": "^5.3.0", "cli-cursor": "^5.0.0", "cli-spinners": "^2.9.2", "is-interactive": "^2.0.0", "is-unicode-supported": "^2.0.0", "log-symbols": "^6.0.0", "stdin-discarder": "^0.2.2", "string-width": "^7.2.0", "strip-ansi": "^7.1.0" } }, "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw=="], + + "os-shim": ["os-shim@0.1.3", "", {}, "sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "package-json": ["package-json@10.0.1", "", { "dependencies": { "ky": "^1.2.0", "registry-auth-token": "^5.0.2", "registry-url": "^6.0.1", "semver": "^7.6.0" } }, "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-json": ["parse-json@7.1.1", "", { "dependencies": { "@babel/code-frame": "^7.21.4", "error-ex": "^1.3.2", "json-parse-even-better-errors": "^3.0.0", "lines-and-columns": "^2.0.3", "type-fest": "^3.8.0" } }, "sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "perfect-debounce": ["perfect-debounce@1.0.0", "", {}, "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + + "pino": ["pino@9.7.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg=="], + + "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], + + "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], + + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], + + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], + + "postcss-js": ["postcss-js@4.1.0", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw=="], + + "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], + + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + + "postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], + + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + + "promise-toolbox": ["promise-toolbox@0.21.0", "", { "dependencies": { "make-error": "^1.3.2" } }, "sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg=="], + + "prompts": ["prompts@2.4.2", "", { "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" } }, "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="], + + "proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="], + + "publish-browser-extension": ["publish-browser-extension@3.0.3", "", { "dependencies": { "cac": "^6.7.14", "consola": "^3.4.2", "dotenv": "^17.2.3", "form-data-encoder": "^4.1.0", "formdata-node": "^6.0.3", "listr2": "^8.3.3", "ofetch": "^1.4.1", "zod": "^3.25.76 || ^4.0.0" }, "bin": { "publish-extension": "bin/publish-extension.cjs" } }, "sha512-cBINZCkLo7YQaGoUvEHthZ0sDzgJQht28IS+SFMT2omSNhGsPiVNRkWir3qLiTrhGhW9Ci2KVHpA1QAMoBdL2g=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "pupa": ["pupa@3.3.0", "", { "dependencies": { "escape-goat": "^4.0.0" } }, "sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA=="], + + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "rc9": ["rc9@2.1.2", "", { "dependencies": { "defu": "^6.1.4", "destr": "^2.0.3" } }, "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg=="], + + "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], + + "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], + + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], + + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + + "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], + + "registry-auth-token": ["registry-auth-token@5.1.1", "", { "dependencies": { "@pnpm/npm-conf": "^3.0.2" } }, "sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q=="], + + "registry-url": ["registry-url@6.0.1", "", { "dependencies": { "rc": "1.2.8" } }, "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "restore-cursor": ["restore-cursor@5.1.0", "", { "dependencies": { "onetime": "^7.0.0", "signal-exit": "^4.1.0" } }, "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], + + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], + + "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + + "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], + + "scule": ["scule@1.3.0", "", {}, "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "serialize-error": ["serialize-error@11.0.3", "", { "dependencies": { "type-fest": "^2.12.2" } }, "sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g=="], + + "set-value": ["set-value@4.1.0", "", { "dependencies": { "is-plain-object": "^2.0.4", "is-primitive": "^3.0.1" } }, "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw=="], + + "setimmediate": ["setimmediate@1.0.5", "", {}, "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "shell-quote": ["shell-quote@1.7.3", "", {}, "sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="], + + "shellwords": ["shellwords@0.1.1", "", {}, "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="], + + "slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="], + + "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "spawn-sync": ["spawn-sync@1.0.15", "", { "dependencies": { "concat-stream": "^1.4.7", "os-shim": "^0.1.2" } }, "sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw=="], + + "split": ["split@1.0.1", "", { "dependencies": { "through": "2" } }, "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg=="], + + "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], + + "stdin-discarder": ["stdin-discarder@0.2.2", "", {}, "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ=="], + + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "strip-bom": ["strip-bom@5.0.0", "", {}, "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A=="], + + "strip-final-newline": ["strip-final-newline@3.0.0", "", {}, "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "strip-literal": ["strip-literal@2.1.1", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q=="], + + "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="], + + "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="], + + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], + + "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "tailwindcss": ["tailwindcss@3.4.19", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="], + + "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], + + "thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="], + + "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], + + "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], + + "through": ["through@2.3.8", "", {}, "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="], + + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tmp": ["tmp@0.2.5", "", {}, "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + + "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], + + "typedarray": ["typedarray@0.0.6", "", {}, "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "typescript-eslint": ["typescript-eslint@8.54.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.54.0", "@typescript-eslint/parser": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "uhyphen": ["uhyphen@0.2.0", "", {}, "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "unimport": ["unimport@3.14.6", "", { "dependencies": { "@rollup/pluginutils": "^5.1.4", "acorn": "^8.14.0", "escape-string-regexp": "^5.0.0", "estree-walker": "^3.0.3", "fast-glob": "^3.3.3", "local-pkg": "^1.0.0", "magic-string": "^0.30.17", "mlly": "^1.7.4", "pathe": "^2.0.1", "picomatch": "^4.0.2", "pkg-types": "^1.3.0", "scule": "^1.3.0", "strip-literal": "^2.1.1", "unplugin": "^1.16.1" } }, "sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "update-notifier": ["update-notifier@7.3.1", "", { "dependencies": { "boxen": "^8.0.1", "chalk": "^5.3.0", "configstore": "^7.0.0", "is-in-ci": "^1.0.0", "is-installed-globally": "^1.0.0", "is-npm": "^6.0.0", "latest-version": "^9.0.0", "pupa": "^3.1.0", "semver": "^7.6.3", "xdg-basedir": "^5.1.0" } }, "sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], + + "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="], + + "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], + + "watchpack": ["watchpack@2.4.4", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA=="], + + "web-ext-run": ["web-ext-run@0.2.4", "", { "dependencies": { "@babel/runtime": "7.28.2", "@devicefarmer/adbkit": "3.3.8", "chrome-launcher": "1.2.0", "debounce": "1.2.1", "es6-error": "4.1.1", "firefox-profile": "4.7.0", "fx-runner": "1.4.0", "multimatch": "6.0.0", "node-notifier": "10.0.1", "parse-json": "7.1.1", "pino": "9.7.0", "promise-toolbox": "0.21.0", "set-value": "4.1.0", "source-map-support": "0.5.21", "strip-bom": "5.0.0", "strip-json-comments": "5.0.2", "tmp": "0.2.5", "update-notifier": "7.3.1", "watchpack": "2.4.4", "zip-dir": "2.0.0" } }, "sha512-rQicL7OwuqWdQWI33JkSXKcp7cuv1mJG8u3jRQwx/8aDsmhbTHs9ZRmNYOL+LX0wX8edIEQX8jj4bB60GoXtKA=="], + + "webextension-polyfill": ["webextension-polyfill@0.12.0", "", {}, "sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q=="], + + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], + + "when": ["when@3.7.7", "", {}, "sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw=="], + + "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "widest-line": ["widest-line@5.0.0", "", { "dependencies": { "string-width": "^7.0.0" } }, "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA=="], + + "winreg": ["winreg@0.0.12", "", {}, "sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + + "wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="], + + "wxt": ["wxt@0.19.29", "", { "dependencies": { "@1natsu/wait-element": "^4.1.2", "@aklinker1/rollup-plugin-visualizer": "5.12.0", "@types/chrome": "^0.0.280", "@types/webextension-polyfill": "^0.12.1", "@webext-core/fake-browser": "^1.3.1", "@webext-core/isolated-element": "^1.1.2", "@webext-core/match-patterns": "^1.0.3", "@wxt-dev/storage": "^1.0.0", "async-mutex": "^0.5.0", "c12": "^3.0.2", "cac": "^6.7.14", "chokidar": "^4.0.3", "ci-info": "^4.1.0", "consola": "^3.2.3", "defu": "^6.1.4", "dotenv": "^16.4.5", "dotenv-expand": "^12.0.1", "esbuild": "^0.25.0", "fast-glob": "^3.3.2", "filesize": "^10.1.6", "fs-extra": "^11.2.0", "get-port-please": "^3.1.2", "giget": "^1.2.3", "hookable": "^5.5.3", "import-meta-resolve": "^4.1.0", "is-wsl": "^3.1.0", "jiti": "^2.4.2", "json5": "^2.2.3", "jszip": "^3.10.1", "linkedom": "^0.18.5", "magicast": "^0.3.5", "minimatch": "^10.0.1", "nano-spawn": "^0.2.0", "normalize-path": "^3.0.0", "nypm": "^0.3.12", "ohash": "^1.1.4", "open": "^10.1.0", "ora": "^8.1.1", "perfect-debounce": "^1.0.0", "picocolors": "^1.1.1", "prompts": "^2.4.2", "publish-browser-extension": "^2.3.0 || ^3.0.0", "scule": "^1.3.0", "unimport": "^3.13.1", "vite": "^5.0.0 || ^6.0.0", "vite-node": "^2.1.4 || ^3.0.0", "web-ext-run": "^0.2.1", "webextension-polyfill": "^0.12.0" }, "bin": { "wxt": "bin/wxt.mjs", "wxt-publish-extension": "bin/wxt-publish-extension.cjs" } }, "sha512-n6DRR34OAFczJfZOwJeY5dn+j+w2BTquW2nAX32vk3FMLWUhzpv5svMvSUTyNiFq3P0o3U7YxfxHdmKJnXZHBA=="], + + "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], + + "xml2js": ["xml2js@0.6.2", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA=="], + + "xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "zip-dir": ["zip-dir@2.0.0", "", { "dependencies": { "async": "^3.2.0", "jszip": "^3.2.2" } }, "sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg=="], + + "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + + "@aklinker1/rollup-plugin-visualizer/open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", "is-wsl": "^2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], + + "@babel/core/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@devicefarmer/adbkit/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + + "@devicefarmer/adbkit/debug": ["debug@4.3.7", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@pnpm/network.ca-file/graceful-fs": ["graceful-fs@4.2.10", "", {}, "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="], + + "@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "@rollup/pluginutils/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], + + "@webext-core/messaging/webextension-polyfill": ["webextension-polyfill@0.10.0", "", {}, "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g=="], + + "ansi-align/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "boxen/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "boxen/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "c12/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + + "c12/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + + "c12/giget": ["giget@2.0.0", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "defu": "^6.1.4", "node-fetch-native": "^1.6.6", "nypm": "^0.6.0", "pathe": "^2.0.3" }, "bin": { "giget": "dist/cli.mjs" } }, "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA=="], + + "c12/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "c12/ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "c12/perfect-debounce": ["perfect-debounce@2.1.0", "", {}, "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g=="], + + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "chrome-launcher/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "config-chain/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "dot-prop/type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "fx-runner/commander": ["commander@2.9.0", "", { "dependencies": { "graceful-readlink": ">= 1.0.0" } }, "sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A=="], + + "fx-runner/which": ["which@1.2.4", "", { "dependencies": { "is-absolute": "^0.1.7", "isexe": "^1.1.1" }, "bin": { "which": "./bin/which" } }, "sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA=="], + + "giget/nypm": ["nypm@0.5.4", "", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "tinyexec": "^0.3.2", "ufo": "^1.5.4" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA=="], + + "global-directory/ini": ["ini@4.1.1", "", {}, "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g=="], + + "is-inside-container/is-docker": ["is-docker@3.0.0", "", { "bin": { "is-docker": "cli.js" } }, "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ=="], + + "log-symbols/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "log-symbols/is-unicode-supported": ["is-unicode-supported@1.3.0", "", {}, "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ=="], + + "log-update/slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="], + + "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "node-notifier/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "npm-run-path/path-key": ["path-key@4.0.0", "", {}, "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ=="], + + "nypm/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="], + + "nypm/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "ora/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "parse-json/lines-and-columns": ["lines-and-columns@2.0.4", "", {}, "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A=="], + + "parse-json/type-fest": ["type-fest@3.13.1", "", {}, "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g=="], + + "publish-browser-extension/dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + + "rc/ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "restore-cursor/onetime": ["onetime@7.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ=="], + + "slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@4.0.0", "", {}, "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ=="], + + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], + + "tinyglobby/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "unimport/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "unimport/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "unimport/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "update-notifier/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + + "vite/picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "web-ext-run/strip-json-comments": ["strip-json-comments@5.0.2", "", {}, "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "wxt/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + + "wxt/jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "wxt/minimatch": ["minimatch@10.1.1", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ=="], + + "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "@aklinker1/rollup-plugin-visualizer/open/define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], + + "@aklinker1/rollup-plugin-visualizer/open/is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "c12/chokidar/readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], + + "c12/giget/nypm": ["nypm@0.6.4", "", { "dependencies": { "citty": "^0.2.0", "pathe": "^2.0.3", "tinyexec": "^1.0.2" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-1TvCKjZyyklN+JJj2TS3P4uSQEInrM/HkkuSXsEzm1ApPgBffOn8gFguNnZf07r/1X6vlryfIqMUkJKQMzlZiw=="], + + "cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "fx-runner/which/isexe": ["isexe@1.1.2", "", {}, "sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw=="], + + "giget/nypm/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], + + "log-update/slice-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "log-update/slice-ansi/is-fullwidth-code-point": ["is-fullwidth-code-point@5.1.0", "", { "dependencies": { "get-east-asian-width": "^1.3.1" } }, "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ=="], + + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "nypm/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "nypm/pkg-types/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "unimport/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "wxt/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "yargs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "yargs/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "c12/giget/nypm/citty": ["citty@0.2.0", "", {}, "sha512-8csy5IBFI2ex2hTVpaHN2j+LNE199AgiI7y4dMintrr8i0lQiFn+0AWMZrWdHKIgMOer65f8IThysYhoReqjWA=="], + + "c12/giget/nypm/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + + "giget/nypm/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + + "yargs/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + } +} diff --git a/extension/content/content.css b/extension/content/content.css deleted file mode 100644 index ef62d1e..0000000 --- a/extension/content/content.css +++ /dev/null @@ -1,21 +0,0 @@ -::highlight(margin-highlight-preview) { - background-color: rgba(149, 122, 134, 0.3); - color: inherit; -} - -::highlight(margin-scroll-highlight) { - background-color: rgba(149, 122, 134, 0.5); - color: inherit; -} - -::highlight(margin-page-highlights) { - background-color: rgba(149, 122, 134, 0.25); - color: inherit; -} - -.margin-notification { - position: fixed; - bottom: 24px; - right: 24px; - z-index: 999999; -} diff --git a/extension/content/content.js b/extension/content/content.js deleted file mode 100644 index a899e77..0000000 --- a/extension/content/content.js +++ /dev/null @@ -1,1263 +0,0 @@ -(() => { - let sidebarHost = null; - let sidebarShadow = null; - let popoverEl = null; - - let activeItems = []; - let currentSelection = null; - - const OVERLAY_STYLES = ` - :host { - all: initial; - --bg-primary: #0a0a0d; - --bg-secondary: #121216; - --bg-tertiary: #1a1a1f; - --bg-card: #0f0f13; - --bg-elevated: #18181d; - --bg-hover: #1e1e24; - - --text-primary: #eaeaee; - --text-secondary: #b7b6c5; - --text-tertiary: #6e6d7a; - --border: rgba(183, 182, 197, 0.12); - - --accent: #957a86; - --accent-hover: #a98d98; - --accent-subtle: rgba(149, 122, 134, 0.15); - } - - :host(.light) { - --bg-primary: #f8f8fa; - --bg-secondary: #ffffff; - --bg-tertiary: #f0f0f4; - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-hover: #eeeef2; - - --text-primary: #18171c; - --text-secondary: #5c495a; - --text-tertiary: #8a8494; - --border: rgba(92, 73, 90, 0.12); - - --accent: #7a5f6d; - --accent-hover: #664e5b; - --accent-subtle: rgba(149, 122, 134, 0.12); - } - - .margin-overlay { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - } - - .margin-popover { - position: absolute; - width: 300px; - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: 12px; - padding: 0; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); - display: flex; - flex-direction: column; - pointer-events: auto; - z-index: 2147483647; - font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; - color: var(--text-primary); - opacity: 0; - transform: translateY(-4px); - animation: popover-in 0.15s forwards; - max-height: 400px; - overflow: hidden; - } - @keyframes popover-in { to { opacity: 1; transform: translateY(0); } } - - .popover-header { - padding: 10px 14px; - border-bottom: 1px solid var(--border); - display: flex; - justify-content: space-between; - align-items: center; - background: var(--bg-primary); - border-radius: 12px 12px 0 0; - font-weight: 500; - font-size: 11px; - color: var(--text-tertiary); - text-transform: uppercase; - letter-spacing: 0.5px; - } - .popover-close { - background: none; - border: none; - color: var(--text-tertiary); - cursor: pointer; - padding: 2px; - font-size: 16px; - line-height: 1; - opacity: 0.6; - transition: opacity 0.15s; - } - .popover-close:hover { opacity: 1; } - - .popover-scroll-area { - overflow-y: auto; - max-height: 340px; - } - - .comment-item { - padding: 12px 14px; - border-bottom: 1px solid var(--border); - } - .comment-item:last-child { - border-bottom: none; - } - - .comment-header { - display: flex; - align-items: center; - gap: 8px; - margin-bottom: 6px; - } - .comment-avatar { - width: 22px; - height: 22px; - border-radius: 50%; - background: var(--accent); - display: flex; - align-items: center; - justify-content: center; - font-size: 9px; - font-weight: 600; - color: white; - } - .comment-handle { - font-size: 12px; - font-weight: 600; - color: var(--text-primary); - } - .comment-time { - font-size: 11px; - color: var(--text-tertiary); - margin-left: auto; - } - - .comment-text { - font-size: 13px; - line-height: 1.5; - color: var(--text-primary); - margin-bottom: 8px; - } - - .highlight-only-badge { - display: inline-flex; - align-items: center; - gap: 4px; - font-size: 11px; - color: var(--text-tertiary); - font-style: italic; - } - - .comment-actions { - display: flex; - gap: 8px; - margin-top: 8px; - } - .highlight-only-badge { - font-size: 11px; - color: var(--text-tertiary); - font-style: italic; - opacity: 0.7; - } - .comment-action-btn { - background: none; - border: none; - padding: 4px 8px; - color: var(--text-tertiary); - font-size: 11px; - cursor: pointer; - border-radius: 4px; - transition: all 0.15s; - } - .comment-action-btn:hover { - background: var(--bg-hover); - color: var(--text-secondary); - } - - .margin-selection-popup { - position: fixed; - display: flex; - gap: 4px; - padding: 6px; - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: 8px; - box-shadow: 0 8px 24px rgba(0,0,0,0.3); - z-index: 2147483647; - pointer-events: auto; - font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; - animation: popover-in 0.15s forwards; - } - .selection-btn { - display: flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - background: transparent; - border: none; - border-radius: 6px; - color: var(--text-primary); - font-size: 12px; - font-weight: 500; - cursor: pointer; - transition: background 0.15s; - } - .selection-btn:hover { - background: var(--bg-hover); - } - .selection-btn svg { - width: 14px; - height: 14px; - } - .inline-compose-modal { - position: fixed; - width: 340px; - max-width: calc(100vw - 40px); - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: 12px; - padding: 16px; - box-sizing: border-box; - box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4); - z-index: 2147483647; - pointer-events: auto; - font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; - color: var(--text-primary); - animation: popover-in 0.15s forwards; - overflow: hidden; - } - .inline-compose-modal * { - box-sizing: border-box; - } - .inline-compose-quote { - padding: 8px 12px; - background: var(--accent-subtle); - border-left: 2px solid var(--accent); - border-radius: 4px; - font-size: 12px; - color: var(--text-secondary); - font-style: italic; - margin-bottom: 12px; - max-height: 60px; - overflow: hidden; - word-break: break-word; - } - .inline-compose-textarea { - width: 100%; - min-height: 80px; - padding: 10px 12px; - background: var(--bg-elevated); - border: 1px solid var(--border); - border-radius: 8px; - color: var(--text-primary); - font-family: inherit; - font-size: 13px; - resize: vertical; - margin-bottom: 12px; - box-sizing: border-box; - } - .inline-compose-textarea:focus { - outline: none; - border-color: var(--accent); - } - .inline-compose-actions { - display: flex; - justify-content: flex-end; - gap: 8px; - } - .btn-cancel { - padding: 8px 16px; - background: transparent; - border: 1px solid var(--border); - border-radius: 6px; - color: var(--text-secondary); - font-size: 13px; - cursor: pointer; - } - .btn-cancel:hover { - background: var(--bg-hover); - color: var(--text-primary); - } - .btn-submit { - padding: 8px 16px; - background: var(--accent); - border: none; - border-radius: 6px; - color: white; - font-size: 13px; - font-weight: 500; - cursor: pointer; - } - .btn-submit:hover { - background: var(--accent-hover); - } - .btn-submit:disabled { - opacity: 0.5; - cursor: not-allowed; - } - .reply-section { - border-top: 1px solid var(--border); - padding: 10px 14px; - background: var(--bg-primary); - border-radius: 0 0 12px 12px; - } - .reply-textarea { - width: 100%; - min-height: 50px; - padding: 8px 10px; - background: var(--bg-elevated); - border: 1px solid var(--border); - border-radius: 6px; - color: var(--text-primary); - font-family: inherit; - font-size: 12px; - resize: none; - margin-bottom: 8px; - } - .reply-textarea:focus { - outline: none; - border-color: var(--accent); - } - .reply-submit { - padding: 6px 12px; - background: var(--accent); - border: none; - border-radius: 4px; - color: white; - font-size: 11px; - font-weight: 500; - cursor: pointer; - float: right; - } - .reply-submit:disabled { - opacity: 0.5; - } - .reply-item { - padding: 8px 0; - border-top: 1px solid var(--border); - } - .reply-item:first-child { - border-top: none; - } - .reply-author { - font-size: 11px; - font-weight: 600; - color: var(--text-secondary); - margin-bottom: 4px; - } - .reply-text { - font-size: 12px; - color: var(--text-primary); - line-height: 1.4; - } - `; - - class DOMTextMatcher { - constructor() { - this.textNodes = []; - this.corpus = ""; - this.indices = []; - this.buildMap(); - } - - buildMap() { - const walker = document.createTreeWalker( - document.body, - NodeFilter.SHOW_TEXT, - { - acceptNode: (node) => { - if (!node.parentNode) return NodeFilter.FILTER_REJECT; - const tag = node.parentNode.tagName; - if ( - ["SCRIPT", "STYLE", "NOSCRIPT", "TEXTAREA", "INPUT"].includes(tag) - ) - return NodeFilter.FILTER_REJECT; - if (node.textContent.trim().length === 0) - return NodeFilter.FILTER_SKIP; - - if (node.parentNode.offsetParent === null) - return NodeFilter.FILTER_REJECT; - - return NodeFilter.FILTER_ACCEPT; - }, - }, - ); - - let currentNode; - let index = 0; - while ((currentNode = walker.nextNode())) { - const text = currentNode.textContent; - this.textNodes.push(currentNode); - this.corpus += text; - this.indices.push({ - start: index, - node: currentNode, - length: text.length, - }); - index += text.length; - } - } - - findRange(searchText) { - if (!searchText) return null; - - let matchIndex = this.corpus.indexOf(searchText); - - if (matchIndex === -1) { - const normalizedSearch = searchText.replace(/\s+/g, " ").trim(); - matchIndex = this.corpus.indexOf(normalizedSearch); - - if (matchIndex === -1) { - const fuzzyMatch = this.fuzzyFindInCorpus(searchText); - if (fuzzyMatch) { - const start = this.mapIndexToPoint(fuzzyMatch.start); - const end = this.mapIndexToPoint(fuzzyMatch.end); - if (start && end) { - const range = document.createRange(); - range.setStart(start.node, start.offset); - range.setEnd(end.node, end.offset); - return range; - } - } - return null; - } - } - - const start = this.mapIndexToPoint(matchIndex); - const end = this.mapIndexToPoint(matchIndex + searchText.length); - - if (start && end) { - const range = document.createRange(); - range.setStart(start.node, start.offset); - range.setEnd(end.node, end.offset); - return range; - } - return null; - } - - fuzzyFindInCorpus(searchText) { - const searchWords = searchText - .trim() - .split(/\s+/) - .filter((w) => w.length > 0); - if (searchWords.length === 0) return null; - - const corpusLower = this.corpus.toLowerCase(); - - const firstWord = searchWords[0].toLowerCase(); - let searchStart = 0; - - while (searchStart < corpusLower.length) { - const wordStart = corpusLower.indexOf(firstWord, searchStart); - if (wordStart === -1) break; - - let corpusPos = wordStart; - let matched = true; - let lastMatchEnd = wordStart; - - for (const word of searchWords) { - const wordLower = word.toLowerCase(); - while ( - corpusPos < corpusLower.length && - /\s/.test(this.corpus[corpusPos]) - ) { - corpusPos++; - } - const corpusSlice = corpusLower.slice( - corpusPos, - corpusPos + wordLower.length, - ); - if (corpusSlice !== wordLower) { - matched = false; - break; - } - - corpusPos += wordLower.length; - lastMatchEnd = corpusPos; - } - - if (matched) { - return { start: wordStart, end: lastMatchEnd }; - } - - searchStart = wordStart + 1; - } - - return null; - } - - mapIndexToPoint(corpusIndex) { - for (const info of this.indices) { - if ( - corpusIndex >= info.start && - corpusIndex < info.start + info.length - ) { - return { node: info.node, offset: corpusIndex - info.start }; - } - } - if (this.indices.length > 0) { - const last = this.indices[this.indices.length - 1]; - if (corpusIndex === last.start + last.length) { - return { node: last.node, offset: last.length }; - } - } - return null; - } - } - - function applyTheme(theme) { - if (!sidebarHost) return; - sidebarHost.classList.remove("light", "dark"); - if (theme === "system" || !theme) { - if (window.matchMedia("(prefers-color-scheme: light)").matches) { - sidebarHost.classList.add("light"); - } - } else { - sidebarHost.classList.add(theme); - } - } - - window - .matchMedia("(prefers-color-scheme: light)") - .addEventListener("change", (e) => { - chrome.storage.local.get(["theme"], (result) => { - if (!result.theme || result.theme === "system") { - if (e.matches) { - sidebarHost?.classList.add("light"); - } else { - sidebarHost?.classList.remove("light"); - } - } - }); - }); - - function initOverlay() { - sidebarHost = document.createElement("div"); - sidebarHost.id = "margin-overlay-host"; - sidebarHost.style.cssText = ` - position: absolute; top: 0; left: 0; width: 100%; - height: 0; - overflow: visible; - pointer-events: none; z-index: 2147483647; - `; - document.body?.appendChild(sidebarHost) || - document.documentElement.appendChild(sidebarHost); - - sidebarShadow = sidebarHost.attachShadow({ mode: "open" }); - const styleEl = document.createElement("style"); - styleEl.textContent = OVERLAY_STYLES; - sidebarShadow.appendChild(styleEl); - - const container = document.createElement("div"); - container.className = "margin-overlay"; - container.id = "margin-overlay-container"; - sidebarShadow.appendChild(container); - - if (typeof chrome !== "undefined" && chrome.storage) { - chrome.storage.local.get(["showOverlay", "theme"], (result) => { - applyTheme(result.theme); - if (result.showOverlay === false) { - sidebarHost.style.display = "none"; - } else { - fetchAnnotations(); - } - }); - } else { - fetchAnnotations(); - } - - document.addEventListener("mousemove", handleMouseMove); - document.addEventListener("click", handleDocumentClick, true); - - chrome.storage.onChanged.addListener((changes, area) => { - if (area === "local") { - if (changes.theme) { - applyTheme(changes.theme.newValue); - } - if (changes.showOverlay) { - if (changes.showOverlay.newValue === false) { - sidebarHost.style.display = "none"; - activeItems = []; - if (typeof CSS !== "undefined" && CSS.highlights) { - CSS.highlights.clear(); - } - } else { - sidebarHost.style.display = ""; - fetchAnnotations(); - } - } - } - }); - } - - function showInlineComposeModal() { - if (!sidebarShadow || !currentSelection) return; - - const container = sidebarShadow.getElementById("margin-overlay-container"); - if (!container) return; - - const existingModal = container.querySelector(".inline-compose-modal"); - if (existingModal) existingModal.remove(); - - const modal = document.createElement("div"); - modal.className = "inline-compose-modal"; - - modal.style.left = `${Math.max(20, (window.innerWidth - 340) / 2)}px`; - modal.style.top = `${Math.min(200, window.innerHeight / 4)}px`; - - const truncatedQuote = - currentSelection.text.length > 100 - ? currentSelection.text.substring(0, 100) + "..." - : currentSelection.text; - - modal.innerHTML = ` -
"${truncatedQuote}"
- -
- - -
- `; - - const textarea = modal.querySelector("textarea"); - const submitBtn = modal.querySelector(".btn-submit"); - const cancelBtn = modal.querySelector(".btn-cancel"); - - cancelBtn.addEventListener("click", () => { - modal.remove(); - }); - - submitBtn.addEventListener("click", async () => { - const text = textarea.value.trim(); - if (!text) return; - - submitBtn.disabled = true; - submitBtn.textContent = "Posting..."; - - chrome.runtime.sendMessage( - { - type: "CREATE_ANNOTATION", - data: { - url: currentSelection.url || window.location.href, - title: currentSelection.title || document.title, - text: text, - selector: currentSelection.selector, - }, - }, - (res) => { - if (res && res.success) { - modal.remove(); - fetchAnnotations(); - } else { - submitBtn.disabled = false; - submitBtn.textContent = "Post Annotation"; - alert( - "Failed to create annotation: " + (res?.error || "Unknown error"), - ); - } - }, - ); - }); - - container.appendChild(modal); - textarea.focus(); - - const handleEscape = (e) => { - if (e.key === "Escape") { - modal.remove(); - document.removeEventListener("keydown", handleEscape); - } - }; - document.addEventListener("keydown", handleEscape); - } - - let hoverIndicator = null; - - function handleMouseMove(e) { - const x = e.clientX; - const y = e.clientY; - - if (sidebarHost && sidebarHost.style.display === "none") return; - - let foundItems = []; - let firstRange = null; - for (const { range, item } of activeItems) { - const rects = range.getClientRects(); - for (const rect of rects) { - if ( - x >= rect.left && - x <= rect.right && - y >= rect.top && - y <= rect.bottom - ) { - let container = range.commonAncestorContainer; - if (container.nodeType === Node.TEXT_NODE) { - container = container.parentNode; - } - - if ( - container && - (e.target.contains(container) || container.contains(e.target)) - ) { - if (!firstRange) firstRange = range; - if (!foundItems.some((f) => f.item === item)) { - foundItems.push({ range, item, rect }); - } - } - break; - } - } - } - - if (foundItems.length > 0) { - document.body.style.cursor = "pointer"; - - if (!hoverIndicator && sidebarShadow) { - const container = sidebarShadow.getElementById( - "margin-overlay-container", - ); - if (container) { - hoverIndicator = document.createElement("div"); - hoverIndicator.className = "margin-hover-indicator"; - hoverIndicator.style.cssText = ` - position: fixed; - display: flex; - align-items: center; - pointer-events: none; - z-index: 2147483647; - opacity: 0; - transition: opacity 0.15s, transform 0.15s; - transform: scale(0.8); - `; - container.appendChild(hoverIndicator); - } - } - - if (hoverIndicator) { - const authorsMap = new Map(); - foundItems.forEach(({ item }) => { - const author = item.author || item.creator || {}; - const id = author.did || author.handle || "unknown"; - if (!authorsMap.has(id)) { - authorsMap.set(id, author); - } - }); - const uniqueAuthors = Array.from(authorsMap.values()); - - const maxShow = 3; - const displayAuthors = uniqueAuthors.slice(0, maxShow); - const overflow = uniqueAuthors.length - maxShow; - - let html = displayAuthors - .map((author, i) => { - const avatar = author.avatar; - const handle = author.handle || "U"; - const marginLeft = i === 0 ? "0" : "-8px"; - - if (avatar) { - return ``; - } else { - return `
${handle[0]?.toUpperCase() || "U"}
`; - } - }) - .join(""); - - if (overflow > 0) { - html += `
+${overflow}
`; - } - - hoverIndicator.innerHTML = html; - - const firstRect = firstRange.getClientRects()[0]; - const totalWidth = - Math.min(uniqueAuthors.length, maxShow + (overflow > 0 ? 1 : 0)) * - 18 + - 8; - const leftPos = firstRect.left - totalWidth; - const topPos = firstRect.top + firstRect.height / 2 - 12; - - hoverIndicator.style.left = `${leftPos}px`; - hoverIndicator.style.top = `${topPos}px`; - hoverIndicator.style.opacity = "1"; - hoverIndicator.style.transform = "scale(1)"; - } - } else { - document.body.style.cursor = ""; - if (hoverIndicator) { - hoverIndicator.style.opacity = "0"; - hoverIndicator.style.transform = "scale(0.8)"; - } - } - } - - function handleDocumentClick(e) { - const x = e.clientX; - const y = e.clientY; - - if (sidebarHost && sidebarHost.style.display === "none") return; - - if (popoverEl && sidebarShadow) { - const rect = popoverEl.getBoundingClientRect(); - if ( - x >= rect.left && - x <= rect.right && - y >= rect.top && - y <= rect.bottom - ) { - return; - } - } - - let clickedItems = []; - for (const { range, item } of activeItems) { - const rects = range.getClientRects(); - for (const rect of rects) { - if ( - x >= rect.left && - x <= rect.right && - y >= rect.top && - y <= rect.bottom - ) { - let container = range.commonAncestorContainer; - if (container.nodeType === Node.TEXT_NODE) { - container = container.parentNode; - } - - if ( - container && - (e.target.contains(container) || container.contains(e.target)) - ) { - if (!clickedItems.includes(item)) { - clickedItems.push(item); - } - } - break; - } - } - } - - if (clickedItems.length > 0) { - e.preventDefault(); - e.stopPropagation(); - - if (popoverEl) { - const currentIds = popoverEl.dataset.itemIds; - const newIds = clickedItems - .map((i) => i.uri || i.id) - .sort() - .join(","); - - if (currentIds === newIds) { - popoverEl.remove(); - popoverEl = null; - return; - } - } - - const firstItem = clickedItems[0]; - const match = activeItems.find((x) => x.item === firstItem); - if (match) { - const rects = match.range.getClientRects(); - if (rects.length > 0) { - const rect = rects[0]; - const top = rect.top + window.scrollY; - const left = rect.left + window.scrollX; - showPopover(clickedItems, top, left); - } - } - } else { - if (popoverEl) { - popoverEl.remove(); - popoverEl = null; - } - } - } - - function renderBadges(annotations) { - if (!sidebarShadow) return; - - const itemsToRender = annotations || []; - activeItems = []; - const rangesByColor = {}; - - const matcher = new DOMTextMatcher(); - - itemsToRender.forEach((item) => { - const selector = item.target?.selector || item.selector; - if (!selector?.exact) return; - - const range = matcher.findRange(selector.exact); - if (range) { - activeItems.push({ range, item }); - - const color = item.color || "#6366f1"; - if (!rangesByColor[color]) rangesByColor[color] = []; - rangesByColor[color].push(range); - } - }); - - if (typeof CSS !== "undefined" && CSS.highlights) { - CSS.highlights.clear(); - for (const [color, ranges] of Object.entries(rangesByColor)) { - const highlight = new Highlight(...ranges); - const safeColor = color.replace(/[^a-zA-Z0-9]/g, ""); - const name = `margin-hl-${safeColor}`; - CSS.highlights.set(name, highlight); - injectHighlightStyle(name, color); - } - } - } - - const injectedStyles = new Set(); - function injectHighlightStyle(name, color) { - if (injectedStyles.has(name)) return; - const style = document.createElement("style"); - style.textContent = ` - ::highlight(${name}) { - text-decoration: underline; - text-decoration-color: ${color}; - text-decoration-thickness: 2px; - text-underline-offset: 2px; - cursor: pointer; - } - `; - document.head.appendChild(style); - injectedStyles.add(name); - } - - function showPopover(items, top, left) { - if (popoverEl) popoverEl.remove(); - const container = sidebarShadow.getElementById("margin-overlay-container"); - popoverEl = document.createElement("div"); - popoverEl.className = "margin-popover"; - - const ids = items - .map((i) => i.uri || i.id) - .sort() - .join(","); - popoverEl.dataset.itemIds = ids; - - const popWidth = 300; - const screenWidth = window.innerWidth; - let finalLeft = left; - if (left + popWidth > screenWidth) finalLeft = screenWidth - popWidth - 20; - - popoverEl.style.top = `${top + 20}px`; - popoverEl.style.left = `${finalLeft}px`; - - const count = items.length; - const title = count === 1 ? "1 Comment" : `${count} Comments`; - - let contentHtml = items - .map((item) => { - const author = item.author || item.creator || {}; - const handle = author.handle || "User"; - const avatar = author.avatar; - const text = item.body?.value || item.text || ""; - const id = item.id || item.uri; - const isHighlight = item.type === "Highlight"; - - let avatarHtml = `
${handle[0]?.toUpperCase() || "U"}
`; - if (avatar) { - avatarHtml = ``; - } - - let bodyHtml = ""; - if (isHighlight && !text) { - bodyHtml = `
Highlighted
`; - } else { - bodyHtml = `
${text}
`; - } - - return ` -
-
- ${avatarHtml} - @${handle} -
- ${bodyHtml} -
- ${!isHighlight ? `` : ""} - -
-
- `; - }) - .join(""); - - popoverEl.innerHTML = ` -
- ${title} - -
-
- ${contentHtml} -
- `; - - popoverEl.querySelector(".popover-close").addEventListener("click", (e) => { - e.stopPropagation(); - popoverEl.remove(); - popoverEl = null; - }); - - const replyBtns = popoverEl.querySelectorAll(".btn-reply"); - replyBtns.forEach((btn) => { - btn.addEventListener("click", (e) => { - e.stopPropagation(); - const id = btn.getAttribute("data-id"); - if (id) { - chrome.runtime.sendMessage({ - type: "OPEN_APP_URL", - data: { path: `/annotation/${encodeURIComponent(id)}` }, - }); - } - }); - }); - - const shareBtns = popoverEl.querySelectorAll(".btn-share"); - shareBtns.forEach((btn) => { - btn.addEventListener("click", async () => { - const id = btn.getAttribute("data-id"); - const text = btn.getAttribute("data-text"); - const u = `https://margin.at/annotation/${encodeURIComponent(id)}`; - const shareText = text ? `${text}\n${u}` : u; - - try { - await navigator.clipboard.writeText(shareText); - const originalText = btn.innerText; - btn.innerText = "Copied!"; - setTimeout(() => (btn.innerText = originalText), 2000); - } catch (e) { - console.error("Failed to copy", e); - } - }); - }); - - container.appendChild(popoverEl); - - setTimeout(() => { - document.addEventListener("click", closePopoverOutside); - }, 0); - } - - function closePopoverOutside() { - if (popoverEl) { - popoverEl.remove(); - popoverEl = null; - document.removeEventListener("click", closePopoverOutside); - } - } - - function fetchAnnotations(retryCount = 0) { - if (typeof chrome !== "undefined" && chrome.runtime) { - const citedUrls = Array.from(document.querySelectorAll("[cite]")) - .map((el) => el.getAttribute("cite")) - .filter((url) => url && url.startsWith("http")); - const uniqueCitedUrls = [...new Set(citedUrls)]; - - chrome.runtime.sendMessage( - { - type: "GET_ANNOTATIONS", - data: { - url: window.location.href, - citedUrls: uniqueCitedUrls, - }, - }, - (res) => { - if (res && res.success && res.data && res.data.length > 0) { - renderBadges(res.data); - } else if (retryCount < 3) { - setTimeout( - () => fetchAnnotations(retryCount + 1), - 1000 * (retryCount + 1), - ); - } - }, - ); - } - } - - function findCanonicalUrl(range) { - if (!range) return null; - let node = range.commonAncestorContainer; - if (node.nodeType === Node.TEXT_NODE) { - node = node.parentNode; - } - - while (node && node !== document.body) { - if ( - (node.tagName === "BLOCKQUOTE" || node.tagName === "Q") && - node.hasAttribute("cite") - ) { - if (node.contains(range.commonAncestorContainer)) { - return node.getAttribute("cite"); - } - } - node = node.parentNode; - } - return null; - } - - chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { - if (request.type === "GET_SELECTOR_FOR_ANNOTATE_INLINE") { - const sel = window.getSelection(); - if (!sel || !sel.toString()) { - sendResponse({ selector: null }); - return true; - } - const exact = sel.toString().trim(); - const canonicalUrl = findCanonicalUrl(sel.getRangeAt(0)); - - sendResponse({ - selector: { type: "TextQuoteSelector", exact }, - canonicalUrl, - }); - return true; - } - - if (request.type === "SHOW_INLINE_ANNOTATE") { - currentSelection = { - text: request.data.selector?.exact || "", - selector: request.data.selector, - url: request.data.url, - title: request.data.title, - }; - showInlineComposeModal(); - sendResponse({ success: true }); - return true; - } - - if (request.type === "GET_SELECTOR_FOR_HIGHLIGHT") { - const sel = window.getSelection(); - if (!sel || !sel.toString().trim()) { - sendResponse({ success: false, selector: null }); - return true; - } - const exact = sel.toString().trim(); - const canonicalUrl = findCanonicalUrl(sel.getRangeAt(0)); - - sendResponse({ - success: false, - selector: { type: "TextQuoteSelector", exact }, - canonicalUrl, - }); - return true; - } - - if (request.type === "REFRESH_ANNOTATIONS") { - fetchAnnotations(); - sendResponse({ success: true }); - return true; - } - - if (request.type === "UPDATE_OVERLAY_VISIBILITY") { - if (sidebarHost) { - sidebarHost.style.display = request.show ? "block" : "none"; - } - if (request.show) { - fetchAnnotations(); - } else { - activeItems = []; - if (typeof CSS !== "undefined" && CSS.highlights) { - CSS.highlights.clear(); - } - } - sendResponse({ success: true }); - return true; - } - - if (request.type === "SCROLL_TO_TEXT") { - const selector = request.selector; - if (selector?.exact) { - const matcher = new DOMTextMatcher(); - const range = matcher.findRange(selector.exact); - if (range) { - const rect = range.getBoundingClientRect(); - window.scrollTo({ - top: window.scrollY + rect.top - window.innerHeight / 3, - behavior: "smooth", - }); - const highlight = new Highlight(range); - CSS.highlights.set("margin-scroll-flash", highlight); - injectHighlightStyle("margin-scroll-flash", "#8b5cf6"); - setTimeout(() => CSS.highlights.delete("margin-scroll-flash"), 2000); - } - } - } - return true; - }); - - if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", initOverlay); - } else { - initOverlay(); - } - - window.addEventListener("load", () => { - if (typeof chrome !== "undefined" && chrome.storage) { - chrome.storage.local.get(["showOverlay"], (result) => { - if (result.showOverlay !== false) { - setTimeout(() => fetchAnnotations(), 500); - } - }); - } else { - setTimeout(() => fetchAnnotations(), 500); - } - }); - - let lastUrl = window.location.href; - - function checkUrlChange() { - if (window.location.href !== lastUrl) { - lastUrl = window.location.href; - onUrlChange(); - } - } - - function onUrlChange() { - if (typeof CSS !== "undefined" && CSS.highlights) { - CSS.highlights.clear(); - } - activeItems = []; - - if (typeof chrome !== "undefined" && chrome.storage) { - chrome.storage.local.get(["showOverlay"], (result) => { - if (result.showOverlay !== false) { - fetchAnnotations(); - } - }); - } else { - fetchAnnotations(); - } - } - - window.addEventListener("popstate", onUrlChange); - - const originalPushState = history.pushState; - const originalReplaceState = history.replaceState; - - history.pushState = function (...args) { - originalPushState.apply(this, args); - checkUrlChange(); - }; - - history.replaceState = function (...args) { - originalReplaceState.apply(this, args); - checkUrlChange(); - }; - - setInterval(checkUrlChange, 1000); -})(); diff --git a/extension/eslint.config.js b/extension/eslint.config.js index 969fabc..be7093f 100644 --- a/extension/eslint.config.js +++ b/extension/eslint.config.js @@ -1,25 +1,18 @@ -import js from "@eslint/js"; -import globals from "globals"; +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintConfigPrettier from 'eslint-config-prettier'; -export default [ - { ignores: ["dist"] }, +export default tseslint.config( + js.configs.recommended, + ...tseslint.configs.recommended, + eslintConfigPrettier, + { + ignores: ['.output/', '.wxt/', 'node_modules/', '*.config.js'], + }, { - files: ["**/*.js"], - languageOptions: { - ecmaVersion: 2020, - globals: { - ...globals.browser, - ...globals.webextensions, - }, - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - }, - }, rules: { - ...js.configs.recommended.rules, - "no-unused-vars": ["warn", { argsIgnorePattern: "^_" }], - "no-undef": "warn", + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }], }, - }, -]; + } +); diff --git a/extension/icons/site.webmanifest b/extension/icons/site.webmanifest deleted file mode 100644 index ebcc90d..0000000 --- a/extension/icons/site.webmanifest +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "Margin", - "short_name": "Margin", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} diff --git a/extension/manifest.chrome.json b/extension/manifest.chrome.json deleted file mode 100644 index 813c3ad..0000000 --- a/extension/manifest.chrome.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "manifest_version": 3, - "name": "Margin", - "description": "Write in the margins of the web. Annotate any URL with AT Protocol.", - "version": "0.0.11", - "icons": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - }, - "action": { - "default_popup": "popup/popup.html", - "default_icon": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png" - }, - "default_title": "Margin - View annotations" - }, - "background": { - "service_worker": "background/service-worker.js", - "type": "module" - }, - "content_scripts": [ - { - "matches": [""], - "js": ["content/content.js"], - "css": ["content/content.css"], - "run_at": "document_idle" - } - ], - "permissions": [ - "storage", - "activeTab", - "tabs", - "cookies", - "contextMenus", - "sidePanel" - ], - "side_panel": { - "default_path": "sidepanel/sidepanel.html" - }, - "optional_permissions": ["notifications"], - "host_permissions": [""], - "options_ui": { - "page": "popup/popup.html", - "open_in_tab": true - }, - "browser_specific_settings": { - "gecko": { - "id": "hello@margin.at", - "strict_min_version": "109.0" - } - } -} diff --git a/extension/manifest.firefox.json b/extension/manifest.firefox.json deleted file mode 100644 index f594075..0000000 --- a/extension/manifest.firefox.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "manifest_version": 3, - "name": "Margin", - "description": "Write in the margins of the web. Annotate any URL with AT Protocol.", - "version": "0.0.11", - "icons": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png", - "64": "icons/icon-64x64.png", - "128": "icons/icon-128x128.png" - }, - "action": { - "default_popup": "popup/popup.html", - "default_icon": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png" - }, - "default_title": "Margin - View annotations" - }, - "sidebar_action": { - "default_panel": "sidepanel/sidepanel.html", - "default_icon": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png" - }, - "default_title": "Margin Sidebar", - "open_at_install": false - }, - "background": { - "scripts": ["background/service-worker.js"], - "type": "module" - }, - "content_scripts": [ - { - "matches": [""], - "js": ["content/content.js"], - "css": ["content/content.css"], - "run_at": "document_idle" - } - ], - "permissions": ["storage", "activeTab", "tabs", "cookies", "contextMenus"], - "optional_permissions": ["notifications"], - "host_permissions": [""], - "options_ui": { - "page": "popup/popup.html", - "open_in_tab": true - }, - "browser_specific_settings": { - "gecko": { - "id": "hello@margin.at", - "strict_min_version": "140.0", - "data_collection_permissions": { - "required": ["none"] - } - } - } -} diff --git a/extension/manifest.json b/extension/manifest.json deleted file mode 100644 index 5a577ff..0000000 --- a/extension/manifest.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "manifest_version": 3, - "name": "Margin", - "description": "Write in the margins of the web. Annotate any URL with AT Protocol.", - "version": "0.0.11", - "icons": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png", - "128": "icons/icon-128x128.png" - }, - "action": { - "default_popup": "popup/popup.html", - "default_icon": { - "16": "icons/favicon-16x16.png", - "32": "icons/favicon-32x32.png", - "48": "icons/icon-48x48.png" - }, - "default_title": "Margin - View annotations" - }, - "background": { - "service_worker": "background/service-worker.js", - "type": "module" - }, - "content_scripts": [ - { - "matches": [""], - "js": ["content/content.js"], - "css": ["content/content.css"], - "run_at": "document_idle" - } - ], - "permissions": [ - "storage", - "activeTab", - "tabs", - "cookies", - "contextMenus", - "sidePanel" - ], - "side_panel": { - "default_path": "sidepanel/sidepanel.html" - }, - "optional_permissions": ["notifications"], - "host_permissions": [""], - "browser_specific_settings": { - "gecko": { - "id": "hello@margin.at", - "strict_min_version": "109.0" - } - } -} diff --git a/extension/package-lock.json b/extension/package-lock.json deleted file mode 100644 index ddbc6ad..0000000 --- a/extension/package-lock.json +++ /dev/null @@ -1,1091 +0,0 @@ -{ - "name": "margin-extension", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "margin-extension", - "version": "0.1.0", - "devDependencies": { - "@eslint/js": "^9.39.2", - "eslint": "^9.39.2", - "globals": "^17.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.0.0.tgz", - "integrity": "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/extension/package.json b/extension/package.json index 20f8c95..09df068 100644 --- a/extension/package.json +++ b/extension/package.json @@ -1,14 +1,41 @@ { "name": "margin-extension", - "version": "0.1.0", + "description": "Annotate and highlight any webpage, with your notes saved to the decentralized AT Protocol.", "private": true, + "version": "1.0.0", "type": "module", "scripts": { - "lint": "eslint ." + "dev": "wxt", + "dev:firefox": "wxt -b firefox", + "build": "wxt build", + "build:firefox": "wxt build -b firefox", + "zip": "wxt zip", + "zip:firefox": "wxt zip -b firefox", + "lint": "eslint src", + "lint:fix": "eslint src --fix", + "format": "prettier --write \"src/**/*.{ts,tsx,css}\"", + "postinstall": "wxt prepare" + }, + "dependencies": { + "@webext-core/messaging": "^1.4.0", + "clsx": "^2.1.1", + "lucide-react": "^0.563.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" }, "devDependencies": { "@eslint/js": "^9.39.2", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "@wxt-dev/module-react": "^1.1.1", + "autoprefixer": "^10.4.20", "eslint": "^9.39.2", - "globals": "^17.0.0" + "eslint-config-prettier": "^10.1.8", + "postcss": "^8.4.49", + "prettier": "^3.8.1", + "tailwindcss": "^3.4.15", + "typescript": "^5.6.3", + "typescript-eslint": "^8.54.0", + "wxt": "^0.19.13" } } diff --git a/extension/popup/popup.css b/extension/popup/popup.css deleted file mode 100644 index d7d9685..0000000 --- a/extension/popup/popup.css +++ /dev/null @@ -1,817 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&display=swap"); - -:root { - --bg-primary: #0a0a0d; - --bg-secondary: #121216; - --bg-tertiary: #1a1a1f; - --bg-card: #0f0f13; - --bg-elevated: #18181d; - --bg-hover: #1e1e24; - - --text-primary: #eaeaee; - --text-secondary: #b7b6c5; - --text-tertiary: #6e6d7a; - - --border: rgba(183, 182, 197, 0.12); - --border-hover: rgba(183, 182, 197, 0.2); - - --accent: #957a86; - --accent-hover: #a98d98; - --accent-subtle: rgba(149, 122, 134, 0.15); - --accent-text: #c4a8b2; - - --success: #7fb069; - --error: #d97766; - --warning: #e8a54b; - - --radius-sm: 6px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-full: 9999px; - - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -@media (prefers-color-scheme: light) { - :root { - --bg-primary: #f8f8fa; - --bg-secondary: #ffffff; - --bg-tertiary: #f0f0f4; - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-hover: #eeeef2; - - --text-primary: #18171c; - --text-secondary: #5c495a; - --text-tertiary: #8a8494; - - --border: rgba(92, 73, 90, 0.12); - --border-hover: rgba(92, 73, 90, 0.22); - - --accent: #7a5f6d; - --accent-hover: #664e5b; - --accent-subtle: rgba(149, 122, 134, 0.12); - --accent-text: #5c495a; - - --shadow-sm: 0 1px 3px rgba(92, 73, 90, 0.06); - --shadow-md: 0 4px 12px rgba(92, 73, 90, 0.08); - } -} - -body.light { - --bg-primary: #f8f8fa; - --bg-secondary: #ffffff; - --bg-tertiary: #f0f0f4; - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-hover: #eeeef2; - - --text-primary: #18171c; - --text-secondary: #5c495a; - --text-tertiary: #8a8494; - - --border: rgba(92, 73, 90, 0.12); - --border-hover: rgba(92, 73, 90, 0.22); - - --accent: #7a5f6d; - --accent-hover: #664e5b; - --accent-subtle: rgba(149, 122, 134, 0.12); - --accent-text: #5c495a; - - --shadow-sm: 0 1px 3px rgba(92, 73, 90, 0.06); - --shadow-md: 0 4px 12px rgba(92, 73, 90, 0.08); -} - -body.dark { - --bg-primary: #0a0a0d; - --bg-secondary: #121216; - --bg-tertiary: #1a1a1f; - --bg-card: #0f0f13; - --bg-elevated: #18181d; - --bg-hover: #1e1e24; - - --text-primary: #eaeaee; - --text-secondary: #b7b6c5; - --text-tertiary: #6e6d7a; - - --border: rgba(183, 182, 197, 0.12); - --border-hover: rgba(183, 182, 197, 0.2); - - --accent: #957a86; - --accent-hover: #a98d98; - --accent-subtle: rgba(149, 122, 134, 0.15); - --accent-text: #c4a8b2; - - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - width: 380px; - height: 520px; - font-family: - "IBM Plex Sans", - -apple-system, - BlinkMacSystemFont, - sans-serif; - color: var(--text-primary); - background-color: var(--bg-primary); - overflow: hidden; - -webkit-font-smoothing: antialiased; -} - -.popup { - display: flex; - flex-direction: column; - height: 100%; -} - -.popup-header { - padding: 14px 16px; - border-bottom: 1px solid var(--border); - display: flex; - justify-content: space-between; - align-items: center; - background: var(--bg-primary); -} - -.popup-brand { - display: flex; - align-items: center; - gap: 10px; -} - -.popup-logo { - color: var(--accent); -} - -.popup-title { - font-weight: 600; - font-size: 15px; - color: var(--text-primary); - letter-spacing: -0.02em; -} - -.user-info { - display: flex; - align-items: center; - gap: 8px; -} - -.user-handle { - font-size: 12px; - color: var(--text-secondary); - background: var(--bg-tertiary); - padding: 4px 10px; - border-radius: var(--radius-full); -} - -.tabs { - display: flex; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); - padding: 4px 8px; - gap: 4px; -} - -.tab-btn { - flex: 1; - padding: 10px 8px; - background: transparent; - border: none; - font-size: 12px; - font-weight: 500; - color: var(--text-tertiary); - cursor: pointer; - border-radius: var(--radius-sm); - transition: all 0.15s; -} - -.tab-btn:hover { - color: var(--text-secondary); - background: var(--bg-hover); -} - -.tab-btn.active { - color: var(--text-primary); - background: var(--bg-tertiary); -} - -.tab-content { - display: none; - flex: 1; - flex-direction: column; - overflow-y: auto; -} - -.tab-content.active { - display: flex; -} - -.popup-content { - flex: 1; - overflow-y: auto; - display: flex; - flex-direction: column; - background: var(--bg-primary); -} - -.loading { - display: none; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - color: var(--text-tertiary); - gap: 12px; -} - -.spinner { - width: 20px; - height: 20px; - border: 2px solid var(--border); - border-top-color: var(--accent); - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.login-prompt { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - padding: 32px; - text-align: center; - gap: 20px; -} - -.login-at-logo { - font-size: 3.5rem; - font-weight: 700; - color: var(--accent); - line-height: 1; -} - -.login-title { - font-size: 1rem; - font-weight: 600; - color: var(--text-primary); -} - -.login-text { - font-size: 13px; - color: var(--text-secondary); - line-height: 1.5; -} - -.quick-actions { - padding: 12px 16px; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); -} - -.create-form { - padding: 16px; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); -} - -.form-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; -} - -.form-title { - font-size: 12px; - font-weight: 600; - color: var(--text-primary); - letter-spacing: -0.01em; -} - -.current-url { - font-size: 11px; - color: var(--text-tertiary); - max-width: 150px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.annotation-input { - width: 100%; - padding: 12px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - font-family: inherit; - font-size: 13px; - resize: none; - margin-bottom: 10px; - background: var(--bg-elevated); - color: var(--text-primary); - transition: border-color 0.15s; -} - -.annotation-input::placeholder { - color: var(--text-tertiary); -} - -.annotation-input:focus { - outline: none; - border-color: var(--accent); -} - -.form-actions { - display: flex; - justify-content: flex-end; -} - -.quote-preview { - margin-bottom: 12px; - padding: 10px 12px; - background: var(--accent-subtle); - border-left: 2px solid var(--accent); - border-radius: var(--radius-sm); -} - -.quote-preview-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 6px; - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--accent-text); -} - -.quote-preview-clear { - background: none; - border: none; - color: var(--text-tertiary); - font-size: 14px; - cursor: pointer; - padding: 0 4px; - line-height: 1; -} - -.quote-preview-clear:hover { - color: var(--text-primary); -} - -.quote-preview-text { - font-size: 12px; - font-style: italic; - color: var(--text-secondary); - line-height: 1.4; - max-height: 60px; - overflow: hidden; -} - -.annotations-section { - flex: 1; -} - -.section-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 14px 16px; - background: var(--bg-primary); -} - -.section-title { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - color: var(--text-tertiary); - letter-spacing: 0.5px; -} - -.annotation-count { - font-size: 11px; - background: var(--bg-tertiary); - padding: 3px 8px; - border-radius: var(--radius-full); - color: var(--text-secondary); -} - -.annotations { - display: flex; - flex-direction: column; - gap: 1px; - background: var(--border); -} - -.annotation-item { - padding: 14px 16px; - background: var(--bg-primary); - transition: background 0.15s; -} - -.annotation-item:hover { - background: var(--bg-hover); -} - -.annotation-item-header { - display: flex; - align-items: center; - margin-bottom: 8px; - gap: 10px; -} - -.annotation-item-avatar { - width: 26px; - height: 26px; - border-radius: 50%; - background: var(--accent); - color: var(--bg-primary); - display: flex; - align-items: center; - justify-content: center; - font-size: 10px; - font-weight: 600; -} - -.annotation-item-meta { - flex: 1; -} - -.annotation-item-author { - font-size: 12px; - font-weight: 600; - color: var(--text-primary); -} - -.annotation-item-time { - font-size: 11px; - color: var(--text-tertiary); -} - -.annotation-type-badge { - font-size: 10px; - padding: 3px 8px; - border-radius: var(--radius-full); - font-weight: 500; -} - -.annotation-type-badge.highlight { - background: var(--accent-subtle); - color: var(--accent-text); -} - -.annotation-item-quote { - padding: 8px 12px; - border-left: 2px solid var(--accent); - margin-bottom: 8px; - font-size: 12px; - color: var(--text-secondary); - font-style: italic; - background: var(--accent-subtle); - border-radius: 0 var(--radius-sm) var(--radius-sm) 0; -} - -.annotation-item-text { - font-size: 13px; - line-height: 1.5; - color: var(--text-primary); -} - -.bookmark-item { - padding: 14px 16px; - background: var(--bg-primary); - text-decoration: none; - color: inherit; - display: block; - transition: background 0.15s; -} - -.bookmark-item:hover { - background: var(--bg-hover); -} - -.bookmark-title { - font-size: 13px; - font-weight: 500; - margin-bottom: 4px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: var(--text-primary); -} - -.bookmark-url { - font-size: 11px; - color: var(--text-tertiary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 40px 16px; - text-align: center; - color: var(--text-tertiary); -} - -.empty-icon { - margin-bottom: 12px; - color: var(--text-tertiary); - opacity: 0.4; -} - -.empty-text { - font-size: 13px; - color: var(--text-secondary); -} - -.btn { - padding: 10px 18px; - border-radius: var(--radius-md); - border: none; - font-weight: 600; - cursor: pointer; - font-size: 13px; - transition: all 0.15s; - display: inline-flex; - align-items: center; - justify-content: center; - gap: 8px; -} - -.btn-small { - padding: 8px 14px; - font-size: 12px; -} - -.btn-primary { - background: var(--accent); - color: white; -} - -.btn-primary:hover { - background: var(--accent-hover); -} - -.btn-secondary { - background: var(--bg-tertiary); - border: 1px solid var(--border); - color: var(--text-primary); - width: 100%; -} - -.btn-secondary:hover { - background: var(--bg-hover); - border-color: var(--border-hover); -} - -.btn-icon { - background: none; - border: none; - color: var(--text-tertiary); - cursor: pointer; - padding: 6px; - border-radius: var(--radius-sm); -} - -.btn-icon:hover { - color: var(--text-primary); - background: var(--bg-hover); -} - -.popup-link { - font-size: 12px; - color: var(--text-tertiary); - text-decoration: none; -} - -.popup-link:hover { - color: var(--accent-text); -} - -.popup-footer { - padding: 12px 16px; - border-top: 1px solid var(--border); - background: var(--bg-primary); -} - -.settings-view { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--bg-primary); - z-index: 20; - display: flex; - flex-direction: column; - padding: 16px; -} - -.settings-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 24px; - color: var(--text-primary); -} - -.setting-item { - margin-bottom: 20px; -} - -.setting-label { - font-size: 13px; - font-weight: 500; - color: var(--text-primary); - margin-bottom: 6px; -} - -.setting-help { - font-size: 11px; - color: var(--text-tertiary); - margin-top: 4px; -} - -::-webkit-scrollbar { - width: 8px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: var(--bg-hover); - border-radius: var(--radius-full); -} - -::-webkit-scrollbar-thumb:hover { - background: var(--text-tertiary); -} - -.collection-selector { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--bg-primary); - z-index: 30; - display: flex; - flex-direction: column; - padding: 16px; -} - -.collection-list { - display: flex; - flex-direction: column; - gap: 8px; - overflow-y: auto; - flex: 1; -} - -.collection-select-btn { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: var(--radius-md); - color: var(--text-primary); - font-size: 14px; - cursor: pointer; - text-align: left; - transition: all 0.15s; -} - -.collection-select-btn:hover { - border-color: var(--accent); - background: var(--bg-hover); -} - -.collection-select-btn:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.annotation-item-actions { - display: flex; - align-items: center; - gap: 8px; - margin-left: auto; -} - -.toggle-switch { - position: relative; - display: inline-block; - width: 40px; - height: 22px; - flex-shrink: 0; -} - -.toggle-switch input { - opacity: 0; - width: 0; - height: 0; -} - -.toggle-slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--bg-tertiary); - transition: 0.2s; - border-radius: 22px; -} - -.toggle-slider:before { - position: absolute; - content: ""; - height: 16px; - width: 16px; - left: 3px; - bottom: 3px; - background-color: var(--text-tertiary); - transition: 0.2s; - border-radius: 50%; -} - -.toggle-switch input:checked + .toggle-slider { - background-color: var(--accent); -} - -.toggle-switch input:checked + .toggle-slider:before { - transform: translateX(18px); - background-color: white; -} - -.settings-input { - width: 100%; - padding: 10px 12px; - background: var(--bg-elevated); - border: 1px solid var(--border); - border-radius: var(--radius-md); - color: var(--text-primary); - font-size: 13px; -} - -.settings-input:focus { - outline: none; - border-color: var(--accent); -} - -.theme-toggle-group { - display: flex; - background: var(--bg-tertiary); - padding: 3px; - border-radius: var(--radius-md); - gap: 2px; - margin-top: 8px; -} - -.theme-btn { - flex: 1; - padding: 6px; - border: none; - background: transparent; - color: var(--text-tertiary); - font-size: 12px; - font-weight: 500; - border-radius: var(--radius-sm); - cursor: pointer; - transition: all 0.15s ease; -} - -.theme-btn:hover { - color: var(--text-secondary); -} - -.theme-btn.active { - background: var(--bg-primary); - color: var(--text-primary); -} diff --git a/extension/popup/popup.html b/extension/popup/popup.html deleted file mode 100644 index 3895207..0000000 --- a/extension/popup/popup.html +++ /dev/null @@ -1,308 +0,0 @@ - - - - - - Margin - - - - - - - - - - - - diff --git a/extension/popup/popup.js b/extension/popup/popup.js deleted file mode 100644 index 850ff5d..0000000 --- a/extension/popup/popup.js +++ /dev/null @@ -1,835 +0,0 @@ -const browserAPI = typeof browser !== "undefined" ? browser : chrome; - -document.addEventListener("DOMContentLoaded", async () => { - const views = { - loading: document.getElementById("loading"), - login: document.getElementById("login-prompt"), - main: document.getElementById("main-content"), - settings: document.getElementById("settings-view"), - collectionSelector: document.getElementById("collection-selector"), - }; - - const els = { - userHandle: document.getElementById("user-handle"), - userInfo: document.getElementById("user-info"), - signInBtn: document.getElementById("sign-in"), - openWebBtn: document.getElementById("open-web"), - submitBtn: document.getElementById("submit-annotation"), - textInput: document.getElementById("annotation-text"), - currentUrl: document.getElementById("current-url"), - annotationsList: document.getElementById("annotations"), - annotationCount: document.getElementById("annotation-count"), - emptyState: document.getElementById("empty"), - toggleSettings: document.getElementById("toggle-settings"), - closeSettings: document.getElementById("close-settings"), - saveSettings: document.getElementById("save-settings"), - apiUrlInput: document.getElementById("api-url"), - bookmarkBtn: document.getElementById("bookmark-page"), - - tabs: document.querySelectorAll(".tab-btn"), - tabContents: document.querySelectorAll(".tab-content"), - bookmarksList: document.getElementById("bookmarks-list"), - bookmarksEmpty: document.getElementById("bookmarks-empty"), - highlightsList: document.getElementById("highlights-list"), - highlightsEmpty: document.getElementById("highlights-empty"), - - closeCollectionSelector: document.getElementById( - "close-collection-selector", - ), - collectionList: document.getElementById("collection-list"), - collectionLoading: document.getElementById("collection-loading"), - collectionsEmpty: document.getElementById("collections-empty"), - overlayToggle: document.getElementById("overlay-toggle"), - themeBtns: document.querySelectorAll(".theme-btn"), - }; - - let currentTab = null; - let apiUrl = "https://margin.at"; - let currentUserDid = null; - let pendingSelector = null; - // let _activeAnnotationUriForCollection = null; - - const storage = await browserAPI.storage.local.get([ - "apiUrl", - "showOverlay", - "theme", - ]); - if (storage.apiUrl) { - apiUrl = storage.apiUrl; - } - els.apiUrlInput.value = apiUrl; - - if (els.overlayToggle) { - els.overlayToggle.checked = storage.showOverlay !== false; - } - - const currentTheme = storage.theme || "system"; - applyTheme(currentTheme); - updateThemeUI(currentTheme); - - try { - const [tab] = await browserAPI.tabs.query({ - active: true, - currentWindow: true, - }); - currentTab = tab; - - if (els.currentUrl) { - els.currentUrl.textContent = new URL(tab.url).hostname; - } - - let pendingData = null; - if (browserAPI.storage.session) { - try { - const sessionData = await browserAPI.storage.session.get([ - "pendingAnnotation", - ]); - if (sessionData.pendingAnnotation) { - pendingData = sessionData.pendingAnnotation; - await browserAPI.storage.session.remove(["pendingAnnotation"]); - } - } catch { - /* ignore */ - } - } - - if (!pendingData) { - const localData = await browserAPI.storage.local.get([ - "pendingAnnotation", - "pendingAnnotationExpiry", - ]); - if ( - localData.pendingAnnotation && - localData.pendingAnnotationExpiry > Date.now() - ) { - pendingData = localData.pendingAnnotation; - } - await browserAPI.storage.local.remove([ - "pendingAnnotation", - "pendingAnnotationExpiry", - ]); - } - - if (pendingData?.selector) { - pendingSelector = pendingData.selector; - showQuotePreview(pendingSelector); - } - - checkSession(); - } catch (err) { - console.error("Init error:", err); - showView("login"); - } - - els.signInBtn?.addEventListener("click", () => { - browserAPI.runtime.sendMessage({ type: "OPEN_LOGIN" }); - }); - - els.openWebBtn?.addEventListener("click", () => { - browserAPI.runtime.sendMessage({ type: "OPEN_WEB" }); - }); - - els.tabs.forEach((btn) => { - btn.addEventListener("click", () => { - els.tabs.forEach((t) => t.classList.remove("active")); - els.tabContents.forEach((c) => c.classList.remove("active")); - - const tabId = btn.getAttribute("data-tab"); - btn.classList.add("active"); - document.getElementById(`tab-${tabId}`).classList.add("active"); - - if (tabId === "bookmarks") loadBookmarks(); - if (tabId === "highlights") loadHighlights(); - }); - }); - - els.submitBtn?.addEventListener("click", async () => { - const text = els.textInput.value.trim(); - if (!text) return; - - els.submitBtn.disabled = true; - els.submitBtn.textContent = "Posting..."; - - try { - const annotationData = { - url: currentTab.url, - text: text, - title: currentTab.title, - }; - - if (pendingSelector) { - annotationData.selector = pendingSelector; - } - - const res = await sendMessage({ - type: "CREATE_ANNOTATION", - data: annotationData, - }); - - if (res.success) { - els.textInput.value = ""; - pendingSelector = null; - hideQuotePreview(); - loadAnnotations(); - } else { - alert("Failed to post annotation"); - } - } catch (err) { - console.error("Post error:", err); - alert("Error posting annotation"); - } finally { - els.submitBtn.disabled = false; - els.submitBtn.textContent = "Post"; - } - }); - - els.bookmarkBtn?.addEventListener("click", async () => { - els.bookmarkBtn.disabled = true; - els.bookmarkBtn.textContent = "Saving..."; - - try { - const res = await sendMessage({ - type: "CREATE_BOOKMARK", - data: { - url: currentTab.url, - title: currentTab.title, - }, - }); - - if (res.success) { - els.bookmarkBtn.textContent = "✓ Bookmarked"; - setTimeout(() => { - els.bookmarkBtn.textContent = "Bookmark Page"; - els.bookmarkBtn.disabled = false; - }, 2000); - } else { - alert("Failed to bookmark page"); - els.bookmarkBtn.textContent = "Bookmark Page"; - els.bookmarkBtn.disabled = false; - } - } catch (err) { - console.error("Bookmark error:", err); - alert("Error bookmarking page"); - els.bookmarkBtn.textContent = "Bookmark Page"; - els.bookmarkBtn.disabled = false; - } - }); - - els.toggleSettings?.addEventListener("click", () => { - views.settings.style.display = "flex"; - }); - - els.closeSettings?.addEventListener("click", () => { - views.settings.style.display = "none"; - }); - - els.saveSettings?.addEventListener("click", async () => { - const newUrl = els.apiUrlInput.value.replace(/\/$/, ""); - const showOverlay = els.overlayToggle?.checked ?? true; - - await browserAPI.storage.local.set({ apiUrl: newUrl, showOverlay }); - if (newUrl) { - apiUrl = newUrl; - } - await sendMessage({ type: "UPDATE_SETTINGS" }); - - const tabs = await browserAPI.tabs.query({}); - for (const tab of tabs) { - if (tab.id) { - try { - await browserAPI.tabs.sendMessage(tab.id, { - type: "UPDATE_OVERLAY_VISIBILITY", - show: showOverlay, - }); - } catch { - /* ignore */ - } - } - } - - views.settings.style.display = "none"; - checkSession(); - }); - - els.themeBtns.forEach((btn) => { - btn.addEventListener("click", async () => { - const theme = btn.getAttribute("data-theme"); - await browserAPI.storage.local.set({ theme }); - applyTheme(theme); - updateThemeUI(theme); - }); - }); - - els.closeCollectionSelector?.addEventListener("click", () => { - views.collectionSelector.style.display = "none"; - }); - - async function openCollectionSelector(annotationUri) { - if (!currentUserDid) { - console.error("No currentUserDid, returning early"); - return; - } - views.collectionSelector.style.display = "flex"; - els.collectionList.innerHTML = ""; - els.collectionLoading.style.display = "block"; - els.collectionsEmpty.style.display = "none"; - - try { - const [collectionsRes, containingRes] = await Promise.all([ - sendMessage({ - type: "GET_USER_COLLECTIONS", - data: { did: currentUserDid }, - }), - sendMessage({ - type: "GET_CONTAINING_COLLECTIONS", - data: { uri: annotationUri }, - }), - ]); - - if (collectionsRes.success) { - const containingUris = containingRes.success - ? new Set(containingRes.data) - : new Set(); - renderCollectionList( - collectionsRes.data, - annotationUri, - containingUris, - ); - } - } catch (err) { - console.error("Load collections error:", err); - els.collectionList.innerHTML = - '

Failed to load collections

'; - } finally { - els.collectionLoading.style.display = "none"; - } - } - - function renderCollectionList( - items, - annotationUri, - containingUris = new Set(), - ) { - els.collectionList.innerHTML = ""; - els.collectionList.dataset.annotationUri = annotationUri; - - if (!items || items.length === 0) { - els.collectionsEmpty.style.display = "block"; - return; - } - - items.forEach((col) => { - const btn = document.createElement("button"); - btn.className = "collection-select-btn"; - const isAdded = containingUris.has(col.uri); - - const iconSpan = document.createElement("span"); - iconSpan.textContent = isAdded ? "✓" : "📁"; - btn.appendChild(iconSpan); - - const nameSpan = document.createElement("span"); - nameSpan.textContent = col.name; - btn.appendChild(nameSpan); - - if (isAdded) { - btn.classList.add("added"); - btn.disabled = true; - } - - btn.addEventListener("click", async () => { - if (btn.disabled) return; - const annUri = els.collectionList.dataset.annotationUri; - await handleAddToCollection(col.uri, btn, annUri); - }); - - els.collectionList.appendChild(btn); - }); - } - - async function handleAddToCollection( - collectionUri, - btnElement, - annotationUri, - ) { - if (!annotationUri) { - console.error("No annotationUri provided!"); - alert("Error: No item selected to add"); - return; - } - - const originalText = btnElement.textContent; - btnElement.disabled = true; - btnElement.textContent = "Adding..."; - - try { - const res = await sendMessage({ - type: "ADD_TO_COLLECTION", - data: { - collectionUri: collectionUri, - annotationUri: annotationUri, - }, - }); - - if (res && res.success) { - btnElement.textContent = "✓ Added"; - btnElement.textContent = "✓ Added"; - setTimeout(() => { - btnElement.textContent = originalText; - btnElement.disabled = false; - }, 2000); - } else { - alert( - "Failed to add to collection: " + (res?.error || "Unknown error"), - ); - btnElement.textContent = originalText; - btnElement.disabled = false; - } - } catch (err) { - console.error("Add to collection error:", err); - alert("Error adding to collection: " + err.message); - btnElement.textContent = originalText; - btnElement.disabled = false; - } - } - - async function checkSession() { - showView("loading"); - try { - const res = await sendMessage({ type: "CHECK_SESSION" }); - - if (res.success && res.data?.authenticated) { - if (els.userHandle) { - const handle = res.data.handle || res.data.email || "User"; - els.userHandle.textContent = "@" + handle; - } - els.userInfo.style.display = "flex"; - currentUserDid = res.data.did; - showView("main"); - loadAnnotations(); - } else { - els.userInfo.style.display = "none"; - showView("login"); - } - } catch (err) { - console.error("Session check error:", err); - els.userInfo.style.display = "none"; - showView("login"); - } - } - - async function loadAnnotations() { - try { - const res = await sendMessage({ - type: "GET_ANNOTATIONS", - data: { url: currentTab.url }, - }); - - if (res.success) { - if (currentUserDid) { - const isBookmarked = res.data.some( - (item) => - item.type === "Bookmark" && item.creator.did === currentUserDid, - ); - if (els.bookmarkBtn) { - if (isBookmarked) { - els.bookmarkBtn.textContent = "✓ Bookmarked"; - els.bookmarkBtn.disabled = true; - } else { - els.bookmarkBtn.textContent = "Bookmark Page"; - els.bookmarkBtn.disabled = false; - } - } - } - - const listItems = res.data.filter((item) => item.type !== "Bookmark"); - renderAnnotations(listItems); - } - } catch (err) { - console.error("Load annotations error:", err); - } - } - - async function loadBookmarks() { - if (!currentUserDid) return; - els.bookmarksList.innerHTML = - '
'; - els.bookmarksEmpty.style.display = "none"; - - try { - const res = await sendMessage({ - type: "GET_USER_BOOKMARKS", - data: { did: currentUserDid }, - }); - - if (res.success) { - renderBookmarks(res.data); - } - } catch (err) { - console.error("Load bookmarks error:", err); - els.bookmarksList.innerHTML = - '

Failed to load bookmarks

'; - } - } - - async function loadHighlights() { - if (!currentUserDid) return; - els.highlightsList.innerHTML = - '
'; - els.highlightsEmpty.style.display = "none"; - - try { - const res = await sendMessage({ - type: "GET_USER_HIGHLIGHTS", - data: { did: currentUserDid }, - }); - - if (res.success) { - renderHighlights(res.data); - } - } catch (err) { - console.error("Load highlights error:", err); - els.highlightsList.innerHTML = - '

Failed to load highlights

'; - } - } - - function renderAnnotations(items) { - els.annotationsList.innerHTML = ""; - els.annotationCount.textContent = items?.length || 0; - - if (!items || items.length === 0) { - els.emptyState.style.display = "block"; - return; - } - - els.emptyState.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("div"); - el.className = "annotation-item"; - - const author = item.creator || item.author || {}; - const authorName = author.handle || author.displayName || "Unknown"; - const authorInitial = authorName[0]?.toUpperCase() || "?"; - const createdAt = item.created || item.createdAt; - const text = item.body?.value || item.text || ""; - const selector = item.target?.selector; - - const isHighlight = item.type === "Highlight"; - const quote = selector?.exact || ""; - - const header = document.createElement("div"); - header.className = "annotation-item-header"; - - const avatar = document.createElement("div"); - avatar.className = "annotation-item-avatar"; - if (author.avatar) { - const img = document.createElement("img"); - img.src = author.avatar; - img.alt = authorName; - img.style.width = "100%"; - img.style.height = "100%"; - img.style.borderRadius = "50%"; - img.style.objectFit = "cover"; - avatar.appendChild(img); - avatar.style.background = "none"; - } else { - avatar.textContent = authorInitial; - } - header.appendChild(avatar); - - const meta = document.createElement("div"); - meta.className = "annotation-item-meta"; - - const authorEl = document.createElement("div"); - authorEl.className = "annotation-item-author"; - authorEl.textContent = "@" + authorName; - meta.appendChild(authorEl); - - const timeEl = document.createElement("div"); - timeEl.className = "annotation-item-time"; - timeEl.textContent = formatDate(createdAt); - meta.appendChild(timeEl); - - header.appendChild(meta); - - if (isHighlight) { - const badge = document.createElement("span"); - badge.className = "annotation-type-badge highlight"; - badge.textContent = "Highlight"; - header.appendChild(badge); - } - - el.appendChild(header); - - const actions = document.createElement("div"); - actions.className = "annotation-item-actions"; - - if (currentUserDid) { - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.stopPropagation(); - const uri = item.id || item.uri; - openCollectionSelector(uri); - }); - actions.appendChild(folderBtn); - } - - header.appendChild(actions); - - if (quote) { - const quoteEl = document.createElement("div"); - quoteEl.className = "annotation-item-quote"; - quoteEl.textContent = '"' + quote + '"'; - el.appendChild(quoteEl); - } - - if (text) { - const textEl = document.createElement("div"); - textEl.className = "annotation-item-text"; - textEl.textContent = text; - el.appendChild(textEl); - } - - els.annotationsList.appendChild(el); - }); - } - - function renderBookmarks(items) { - els.bookmarksList.innerHTML = ""; - - if (!items || items.length === 0) { - els.bookmarksEmpty.style.display = "flex"; - return; - } - - els.bookmarksEmpty.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("a"); - el.className = "bookmark-item"; - el.href = item.source; - el.target = "_blank"; - - const row = document.createElement("div"); - row.style.display = "flex"; - row.style.justifyContent = "space-between"; - row.style.alignItems = "center"; - - const content = document.createElement("div"); - content.style.flex = "1"; - content.style.overflow = "hidden"; - - const titleEl = document.createElement("div"); - titleEl.className = "bookmark-title"; - titleEl.textContent = item.title || item.source; - content.appendChild(titleEl); - - const urlEl = document.createElement("div"); - urlEl.className = "bookmark-url"; - urlEl.textContent = new URL(item.source).hostname; - content.appendChild(urlEl); - - row.appendChild(content); - - if (currentUserDid) { - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.preventDefault(); - e.stopPropagation(); - const uri = item.id || item.uri; - openCollectionSelector(uri); - }); - row.appendChild(folderBtn); - } - - el.appendChild(row); - els.bookmarksList.appendChild(el); - }); - } - - function renderHighlights(items) { - els.highlightsList.innerHTML = ""; - - if (!items || items.length === 0) { - els.highlightsEmpty.style.display = "flex"; - return; - } - - els.highlightsEmpty.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("div"); - el.className = "annotation-item"; - - const target = item.target || {}; - const selector = target.selector || {}; - const quote = selector.exact || ""; - const url = target.source || ""; - - const header = document.createElement("div"); - header.className = "annotation-item-header"; - - const meta = document.createElement("div"); - meta.className = "annotation-item-meta"; - - const authorEl = document.createElement("div"); - authorEl.className = "annotation-item-author"; - authorEl.textContent = new URL(url).hostname; - meta.appendChild(authorEl); - - const timeEl = document.createElement("div"); - timeEl.className = "annotation-item-time"; - timeEl.textContent = formatDate(item.created); - meta.appendChild(timeEl); - - header.appendChild(meta); - - const actions = document.createElement("div"); - actions.className = "annotation-item-actions"; - - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.stopPropagation(); - const uri = item.id || item.uri; - openCollectionSelector(uri); - }); - actions.appendChild(folderBtn); - - header.appendChild(actions); - el.appendChild(header); - - if (quote) { - const quoteEl = document.createElement("div"); - quoteEl.className = "annotation-item-quote"; - quoteEl.style.marginLeft = "0"; - quoteEl.style.borderColor = item.color || "#fcd34d"; - quoteEl.textContent = '"' + quote + '"'; - el.appendChild(quoteEl); - } - - el.style.cursor = "pointer"; - el.addEventListener("click", () => { - const textFragment = createTextFragment(url, selector); - browserAPI.tabs.create({ url: textFragment }); - }); - - els.highlightsList.appendChild(el); - }); - } - - function createTextFragment(url, selector) { - if (!selector || selector.type !== "TextQuoteSelector" || !selector.exact) - return url; - - let fragment = ":~:text="; - if (selector.prefix) fragment += encodeURIComponent(selector.prefix) + "-,"; - fragment += encodeURIComponent(selector.exact); - if (selector.suffix) fragment += ",-" + encodeURIComponent(selector.suffix); - - return url + "#" + fragment; - } - - function showQuotePreview(selector) { - if (!selector?.exact) return; - - let preview = document.getElementById("quote-preview"); - if (!preview) { - preview = document.createElement("div"); - preview.id = "quote-preview"; - preview.className = "quote-preview"; - const form = document.getElementById("create-form"); - if (form) { - form.insertBefore(preview, els.textInput); - } - } - - const header = document.createElement("div"); - header.className = "quote-preview-header"; - - const label = document.createElement("span"); - label.textContent = "Annotating:"; - header.appendChild(label); - - const clearBtn = document.createElement("button"); - clearBtn.className = "quote-preview-clear"; - clearBtn.title = "Clear"; - clearBtn.textContent = "×"; - clearBtn.addEventListener("click", () => { - pendingSelector = null; - hideQuotePreview(); - }); - header.appendChild(clearBtn); - - preview.appendChild(header); - - const text = document.createElement("div"); - text.className = "quote-preview-text"; - text.textContent = '"' + selector.exact + '"'; - preview.appendChild(text); - - els.textInput?.focus(); - } - - function hideQuotePreview() { - const preview = document.getElementById("quote-preview"); - if (preview) preview.remove(); - } - - function formatDate(dateString) { - if (!dateString) return ""; - try { - return new Date(dateString).toLocaleDateString(); - } catch { - return dateString; - } - } - - function showView(viewName) { - Object.keys(views).forEach((key) => { - if (views[key]) views[key].style.display = "none"; - }); - if (views[viewName]) { - views[viewName].style.display = - viewName === "loading" || viewName === "settings" ? "flex" : "block"; - } - } - - function sendMessage(message) { - return new Promise((resolve, reject) => { - browserAPI.runtime.sendMessage(message, (response) => { - if (browserAPI.runtime.lastError) { - reject(browserAPI.runtime.lastError); - } else { - resolve(response); - } - }); - }); - } -}); - -function applyTheme(theme) { - document.body.classList.remove("light", "dark"); - if (theme === "system") return; - document.body.classList.add(theme); -} - -function updateThemeUI(theme) { - const btns = document.querySelectorAll(".theme-btn"); - btns.forEach((btn) => { - if (btn.getAttribute("data-theme") === theme) { - btn.classList.add("active"); - } else { - btn.classList.remove("active"); - } - }); -} diff --git a/extension/postcss.config.js b/extension/postcss.config.js new file mode 100644 index 0000000..2aa7205 --- /dev/null +++ b/extension/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/extension/icons/icon-128x128.png b/extension/public/icons/icon-128.png similarity index 100% rename from extension/icons/icon-128x128.png rename to extension/public/icons/icon-128.png diff --git a/extension/icons/favicon-16x16.png b/extension/public/icons/icon-16.png similarity index 100% rename from extension/icons/favicon-16x16.png rename to extension/public/icons/icon-16.png diff --git a/extension/icons/favicon-32x32.png b/extension/public/icons/icon-32.png similarity index 100% rename from extension/icons/favicon-32x32.png rename to extension/public/icons/icon-32.png diff --git a/extension/icons/icon-48x48.png b/extension/public/icons/icon-48.png similarity index 100% rename from extension/icons/icon-48x48.png rename to extension/public/icons/icon-48.png diff --git a/extension/icons/icon-64x64.png b/extension/public/icons/icon-64.png similarity index 100% rename from extension/icons/icon-64x64.png rename to extension/public/icons/icon-64.png diff --git a/extension/icons/logo.svg b/extension/public/icons/logo.svg similarity index 100% rename from extension/icons/logo.svg rename to extension/public/icons/logo.svg diff --git a/extension/public/icons/semble-logo.svg b/extension/public/icons/semble-logo.svg new file mode 100644 index 0000000..322b17c --- /dev/null +++ b/extension/public/icons/semble-logo.svg @@ -0,0 +1 @@ + diff --git a/extension/sidepanel/sidepanel.css b/extension/sidepanel/sidepanel.css deleted file mode 100644 index 2e45e68..0000000 --- a/extension/sidepanel/sidepanel.css +++ /dev/null @@ -1,877 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&display=swap"); - -:root { - --bg-primary: #0a0a0d; - --bg-secondary: #121216; - --bg-tertiary: #1a1a1f; - --bg-card: #0f0f13; - --bg-elevated: #18181d; - --bg-hover: #1e1e24; - - --text-primary: #eaeaee; - --text-secondary: #b7b6c5; - --text-tertiary: #6e6d7a; - - --border: rgba(183, 182, 197, 0.12); - --border-hover: rgba(183, 182, 197, 0.2); - - --accent: #957a86; - --accent-hover: #a98d98; - --accent-subtle: rgba(149, 122, 134, 0.15); - --accent-text: #c4a8b2; - - --success: #7fb069; - --error: #d97766; - --warning: #e8a54b; - - --radius-sm: 6px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-full: 9999px; - - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -@media (prefers-color-scheme: light) { - :root { - --bg-primary: #f8f8fa; - --bg-secondary: #ffffff; - --bg-tertiary: #f0f0f4; - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-hover: #eeeef2; - - --text-primary: #18171c; - --text-secondary: #5c495a; - --text-tertiary: #8a8494; - - --border: rgba(92, 73, 90, 0.12); - --border-hover: rgba(92, 73, 90, 0.22); - - --accent: #7a5f6d; - --accent-hover: #664e5b; - --accent-subtle: rgba(149, 122, 134, 0.12); - --accent-text: #5c495a; - - --shadow-sm: 0 1px 3px rgba(92, 73, 90, 0.06); - --shadow-md: 0 4px 12px rgba(92, 73, 90, 0.08); - } -} - -body.light { - --bg-primary: #f8f8fa; - --bg-secondary: #ffffff; - --bg-tertiary: #f0f0f4; - --bg-card: #ffffff; - --bg-elevated: #ffffff; - --bg-hover: #eeeef2; - - --text-primary: #18171c; - --text-secondary: #5c495a; - --text-tertiary: #8a8494; - - --border: rgba(92, 73, 90, 0.12); - --border-hover: rgba(92, 73, 90, 0.22); - - --accent: #7a5f6d; - --accent-hover: #664e5b; - --accent-subtle: rgba(149, 122, 134, 0.12); - --accent-text: #5c495a; - - --shadow-sm: 0 1px 3px rgba(92, 73, 90, 0.06); - --shadow-md: 0 4px 12px rgba(92, 73, 90, 0.08); -} - -body.dark { - --bg-primary: #0a0a0d; - --bg-secondary: #121216; - --bg-tertiary: #1a1a1f; - --bg-card: #0f0f13; - --bg-elevated: #18181d; - --bg-hover: #1e1e24; - - --text-primary: #eaeaee; - --text-secondary: #b7b6c5; - --text-tertiary: #6e6d7a; - - --border: rgba(183, 182, 197, 0.12); - --border-hover: rgba(183, 182, 197, 0.2); - - --accent: #957a86; - --accent-hover: #a98d98; - --accent-subtle: rgba(149, 122, 134, 0.15); - --accent-text: #c4a8b2; - - --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -body { - font-family: - "IBM Plex Sans", - -apple-system, - BlinkMacSystemFont, - sans-serif; - background: var(--bg-primary); - color: var(--text-primary); - min-height: 100vh; - -webkit-font-smoothing: antialiased; -} - -.sidebar { - display: flex; - flex-direction: column; - height: 100vh; - background: var(--bg-primary); -} - -.sidebar-header { - display: flex; - align-items: center; - justify-content: space-between; - padding: 14px 16px; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); -} - -.sidebar-brand { - display: flex; - align-items: center; - gap: 10px; -} - -.sidebar-logo { - color: var(--accent); -} - -.sidebar-title { - font-weight: 600; - font-size: 15px; - color: var(--text-primary); - letter-spacing: -0.02em; -} - -.user-info { - display: flex; - align-items: center; - gap: 8px; -} - -.user-handle { - font-size: 12px; - color: var(--text-secondary); - background: var(--bg-tertiary); - padding: 4px 10px; - border-radius: var(--radius-full); -} - -.current-page-info { - display: flex; - align-items: center; - gap: 8px; - padding: 10px 16px; - background: var(--bg-primary); - border-bottom: 1px solid var(--border); -} - -.page-url { - font-size: 12px; - color: var(--text-tertiary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.sidebar-content { - flex: 1; - overflow-y: auto; - display: flex; - flex-direction: column; -} - -.loading { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - color: var(--text-tertiary); - gap: 12px; -} - -.spinner { - width: 20px; - height: 20px; - border: 2px solid var(--border); - border-top-color: var(--accent); - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - to { - transform: rotate(360deg); - } -} - -.login-prompt { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100%; - padding: 32px; - text-align: center; - gap: 20px; -} - -.login-at-logo { - font-size: 3.5rem; - font-weight: 700; - color: var(--accent); - line-height: 1; -} - -.login-title { - font-size: 1rem; - font-weight: 600; - color: var(--text-primary); -} - -.login-text { - font-size: 13px; - color: var(--text-secondary); - line-height: 1.5; -} - -.tabs { - display: flex; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); - padding: 4px 8px; - gap: 4px; - margin: 0; -} - -.tab-btn { - flex: 1; - padding: 10px 8px; - background: transparent; - border: none; - font-size: 12px; - font-weight: 500; - color: var(--text-tertiary); - cursor: pointer; - border-radius: var(--radius-sm); - transition: all 0.15s; -} - -.tab-btn:hover { - color: var(--text-secondary); - background: var(--bg-hover); -} - -.tab-btn.active { - color: var(--text-primary); - background: var(--bg-tertiary); -} - -.tab-content { - display: none; - flex: 1; - flex-direction: column; - overflow-y: auto; -} - -.tab-content.active { - display: flex; -} - -.quick-actions { - display: flex; - gap: 8px; - padding: 12px 16px; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); -} - -.btn { - padding: 10px 18px; - border-radius: var(--radius-md); - border: none; - font-weight: 600; - cursor: pointer; - font-size: 13px; - transition: all 0.15s; - display: inline-flex; - align-items: center; - justify-content: center; - gap: 8px; -} - -.btn-small { - padding: 8px 14px; - font-size: 12px; -} - -.btn-primary { - background: var(--accent); - color: white; -} - -.btn-primary:hover { - background: var(--accent-hover); -} - -.btn-primary:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.btn-secondary { - background: var(--bg-tertiary); - border: 1px solid var(--border); - color: var(--text-primary); - flex: 1; -} - -.btn-secondary:hover { - background: var(--bg-hover); - border-color: var(--border-hover); -} - -.btn-icon-text { - flex: 1; -} - -.btn-icon { - background: none; - border: none; - color: var(--text-tertiary); - cursor: pointer; - padding: 6px; - border-radius: var(--radius-sm); -} - -.btn-icon:hover { - color: var(--text-primary); - background: var(--bg-hover); -} - -.create-form { - padding: 16px; - border-bottom: 1px solid var(--border); - background: var(--bg-primary); -} - -.form-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; -} - -.form-title { - font-size: 12px; - font-weight: 600; - color: var(--text-primary); - letter-spacing: -0.01em; -} - -.annotation-input { - width: 100%; - padding: 12px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - font-family: inherit; - font-size: 13px; - resize: none; - margin-bottom: 10px; - background: var(--bg-elevated); - color: var(--text-primary); - transition: border-color 0.15s; -} - -.annotation-input::placeholder { - color: var(--text-tertiary); -} - -.annotation-input:focus { - outline: none; - border-color: var(--accent); -} - -.form-actions { - display: flex; - justify-content: flex-end; -} - -.quote-preview { - margin-bottom: 12px; - padding: 12px; - background: var(--accent-subtle); - border-left: 2px solid var(--accent); - border-radius: var(--radius-sm); -} - -.quote-preview-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 8px; - font-size: 10px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.5px; - color: var(--accent-text); -} - -.quote-preview-clear { - background: none; - border: none; - color: var(--text-tertiary); - font-size: 16px; - cursor: pointer; - padding: 0 4px; - line-height: 1; -} - -.quote-preview-clear:hover { - color: var(--text-primary); -} - -.quote-preview-text { - font-size: 12px; - font-style: italic; - color: var(--text-secondary); - line-height: 1.5; -} - -.annotations-section { - flex: 1; -} - -.section-header { - display: flex; - justify-content: space-between; - align-items: center; - padding: 14px 16px; - background: var(--bg-primary); - border-bottom: 1px solid var(--border); -} - -.section-title { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - color: var(--text-tertiary); - letter-spacing: 0.5px; -} - -.annotation-count { - font-size: 11px; - background: var(--bg-tertiary); - padding: 3px 8px; - border-radius: var(--radius-full); - color: var(--text-secondary); -} - -.annotations-list { - display: flex; - flex-direction: column; - gap: 1px; - background: var(--border); -} - -.annotation-item { - padding: 14px 16px; - background: var(--bg-primary); - transition: background 0.15s; -} - -.annotation-item:hover { - background: var(--bg-hover); -} - -.annotation-item-header { - display: flex; - align-items: center; - margin-bottom: 8px; - gap: 10px; -} - -.annotation-item-avatar { - width: 26px; - height: 26px; - border-radius: 50%; - background: var(--accent); - color: var(--bg-primary); - display: flex; - align-items: center; - justify-content: center; - font-size: 10px; - font-weight: 600; -} - -.annotation-item-meta { - flex: 1; -} - -.annotation-item-author { - font-size: 12px; - font-weight: 600; - color: var(--text-primary); -} - -.annotation-item-time { - font-size: 11px; - color: var(--text-tertiary); -} - -.annotation-type-badge { - font-size: 10px; - padding: 3px 8px; - border-radius: var(--radius-full); - font-weight: 500; -} - -.annotation-type-badge.highlight { - background: var(--accent-subtle); - color: var(--accent-text); -} - -.annotation-item-quote { - padding: 8px 12px; - border-left: 2px solid var(--accent); - margin-bottom: 8px; - font-size: 12px; - color: var(--text-secondary); - font-style: italic; - background: var(--accent-subtle); - border-radius: 0 var(--radius-sm) var(--radius-sm) 0; -} - -.annotation-item-text { - font-size: 13px; - line-height: 1.5; - color: var(--text-primary); -} - -.bookmarks-list { - display: flex; - flex-direction: column; - gap: 1px; - background: var(--border); -} - -.bookmark-item { - padding: 14px 16px; - background: var(--bg-primary); - text-decoration: none; - color: inherit; - display: block; - transition: background 0.15s; -} - -.bookmark-item:hover { - background: var(--bg-hover); -} - -.bookmark-title { - font-size: 13px; - font-weight: 500; - margin-bottom: 4px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: var(--text-primary); -} - -.bookmark-url { - font-size: 11px; - color: var(--text-tertiary); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.empty-state { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 40px 16px; - text-align: center; - color: var(--text-tertiary); -} - -.empty-icon { - margin-bottom: 12px; - color: var(--text-tertiary); - opacity: 0.4; -} - -.empty-text { - font-size: 13px; - color: var(--text-secondary); - margin-bottom: 4px; -} - -.empty-hint { - font-size: 12px; - color: var(--text-tertiary); -} - -.sidebar-footer { - display: flex; - align-items: center; - justify-content: space-between; - padding: 12px 16px; - border-top: 1px solid var(--border); - background: var(--bg-primary); -} - -.sidebar-link { - font-size: 12px; - color: var(--text-tertiary); - text-decoration: none; -} - -.sidebar-link:hover { - color: var(--accent-text); -} - -.settings-view { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--bg-primary); - z-index: 20; - display: flex; - flex-direction: column; - padding: 16px; -} - -.settings-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 24px; - color: var(--text-primary); -} - -.settings-title { - font-size: 18px; - font-weight: 600; -} - -.setting-item { - margin-bottom: 20px; -} - -.setting-item label { - font-size: 13px; - font-weight: 500; - color: var(--text-primary); - margin-bottom: 6px; - display: block; -} - -.settings-input { - width: 100%; - padding: 12px; - border: 1px solid var(--border); - border-radius: var(--radius-md); - font-family: inherit; - font-size: 13px; - background: var(--bg-elevated); - color: var(--text-primary); - transition: border-color 0.15s; -} - -.settings-input:focus { - outline: none; - border-color: var(--accent); -} - -.setting-help { - font-size: 11px; - color: var(--text-tertiary); - margin-top: 4px; -} - -.scroll-to-btn { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 6px 10px; - font-size: 11px; - color: var(--accent-text); - background: var(--accent-subtle); - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - margin-top: 8px; - transition: all 0.15s; -} - -.scroll-to-btn:hover { - background: rgba(149, 122, 134, 0.25); -} - -::-webkit-scrollbar { - width: 8px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: var(--bg-hover); - border-radius: var(--radius-full); -} - -::-webkit-scrollbar-thumb:hover { - background: var(--text-tertiary); -} - -.collection-selector { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--bg-primary); - z-index: 30; - display: flex; - flex-direction: column; - padding: 16px; -} - -.collection-list { - display: flex; - flex-direction: column; - gap: 8px; - overflow-y: auto; - flex: 1; -} - -.collection-select-btn { - display: flex; - align-items: center; - gap: 12px; - padding: 12px; - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: var(--radius-md); - color: var(--text-primary); - font-size: 14px; - cursor: pointer; - text-align: left; - transition: all 0.15s; -} - -.collection-select-btn:hover { - border-color: var(--accent); - background: var(--bg-hover); -} - -.collection-select-btn:disabled { - opacity: 0.6; - cursor: not-allowed; -} - -.annotation-item-actions { - display: flex; - align-items: center; - gap: 8px; - margin-left: auto; -} - -.toggle-switch { - position: relative; - display: inline-block; - width: 40px; - height: 22px; - flex-shrink: 0; -} - -.toggle-switch input { - opacity: 0; - width: 0; - height: 0; -} - -.toggle-slider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: var(--bg-tertiary); - transition: 0.2s; - border-radius: 22px; -} - -.toggle-slider:before { - position: absolute; - content: ""; - height: 16px; - width: 16px; - left: 3px; - bottom: 3px; - background-color: var(--text-tertiary); - transition: 0.2s; - border-radius: 50%; -} - -.toggle-switch input:checked + .toggle-slider { - background-color: var(--accent); -} - -.toggle-switch input:checked + .toggle-slider:before { - transform: translateX(18px); - background-color: white; -} - -.theme-toggle-group { - display: flex; - background: var(--bg-tertiary); - padding: 3px; - border-radius: var(--radius-md); - gap: 2px; - margin-top: 8px; -} - -.theme-btn { - flex: 1; - padding: 6px; - border: none; - background: transparent; - color: var(--text-tertiary); - font-size: 12px; - font-weight: 500; - border-radius: var(--radius-sm); - cursor: pointer; - transition: all 0.15s ease; -} - -.theme-btn:hover { - color: var(--text-secondary); -} - -.theme-btn.active { - background: var(--bg-primary); - color: var(--text-primary); -} diff --git a/extension/sidepanel/sidepanel.html b/extension/sidepanel/sidepanel.html deleted file mode 100644 index 0e0ca68..0000000 --- a/extension/sidepanel/sidepanel.html +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - Margin - - - - - - - - - - - - diff --git a/extension/sidepanel/sidepanel.js b/extension/sidepanel/sidepanel.js deleted file mode 100644 index d1a9227..0000000 --- a/extension/sidepanel/sidepanel.js +++ /dev/null @@ -1,973 +0,0 @@ -document.addEventListener("DOMContentLoaded", async () => { - const views = { - loading: document.getElementById("loading"), - login: document.getElementById("login-prompt"), - main: document.getElementById("main-content"), - settings: document.getElementById("settings-view"), - collectionSelector: document.getElementById("collection-selector"), - }; - - const els = { - userHandle: document.getElementById("user-handle"), - userInfo: document.getElementById("user-info"), - signInBtn: document.getElementById("sign-in"), - openWebBtn: document.getElementById("open-web"), - submitBtn: document.getElementById("submit-annotation"), - textInput: document.getElementById("annotation-text"), - currentPageUrl: document.getElementById("current-page-url"), - annotationsList: document.getElementById("annotations"), - annotationCount: document.getElementById("annotation-count"), - emptyState: document.getElementById("empty"), - toggleSettings: document.getElementById("toggle-settings"), - closeSettings: document.getElementById("close-settings"), - saveSettings: document.getElementById("save-settings"), - signOutBtn: document.getElementById("sign-out"), - apiUrlInput: document.getElementById("api-url"), - bookmarkBtn: document.getElementById("bookmark-page"), - refreshBtn: document.getElementById("refresh-annotations"), - tabs: document.querySelectorAll(".tab-btn"), - tabContents: document.querySelectorAll(".tab-content"), - bookmarksList: document.getElementById("bookmarks-list"), - bookmarksEmpty: document.getElementById("bookmarks-empty"), - highlightsList: document.getElementById("highlights-list"), - highlightsEmpty: document.getElementById("highlights-empty"), - closeCollectionSelector: document.getElementById( - "close-collection-selector", - ), - collectionList: document.getElementById("collection-list"), - collectionLoading: document.getElementById("collection-loading"), - collectionsEmpty: document.getElementById("collections-empty"), - overlayToggle: document.getElementById("overlay-toggle"), - }; - - let currentTab = null; - let apiUrl = ""; - let currentUserDid = null; - let pendingSelector = null; - - const storage = await chrome.storage.local.get(["apiUrl"]); - if (storage.apiUrl) { - apiUrl = storage.apiUrl; - } - - els.apiUrlInput.value = apiUrl; - - const overlayStorage = await chrome.storage.local.get(["showOverlay"]); - if (els.overlayToggle) { - els.overlayToggle.checked = overlayStorage.showOverlay !== false; - } - - chrome.storage.onChanged.addListener((changes, area) => { - if (area === "local") { - if (changes.apiUrl) { - apiUrl = changes.apiUrl.newValue || ""; - els.apiUrlInput.value = apiUrl; - checkSession(); - } - if (changes.theme) { - const newTheme = changes.theme.newValue || "system"; - applyTheme(newTheme); - updateThemeUI(newTheme); - } - } - }); - - chrome.storage.local.get(["theme"], (result) => { - const currentTheme = result.theme || "system"; - applyTheme(currentTheme); - updateThemeUI(currentTheme); - }); - - const themeBtns = document.querySelectorAll(".theme-btn"); - themeBtns.forEach((btn) => { - btn.addEventListener("click", () => { - const theme = btn.getAttribute("data-theme"); - chrome.storage.local.set({ theme }); - applyTheme(theme); - updateThemeUI(theme); - }); - }); - - try { - const [tab] = await chrome.tabs.query({ - active: true, - currentWindow: true, - }); - currentTab = tab; - if (els.currentPageUrl) { - try { - els.currentPageUrl.textContent = new URL(tab.url).hostname; - } catch { - els.currentPageUrl.textContent = tab.url; - } - } - - let pendingData = null; - if (chrome.storage.session) { - const sessionData = await chrome.storage.session.get([ - "pendingAnnotation", - ]); - if (sessionData.pendingAnnotation) { - pendingData = sessionData.pendingAnnotation; - await chrome.storage.session.remove(["pendingAnnotation"]); - } - } - - if (!pendingData) { - const localData = await chrome.storage.local.get([ - "pendingAnnotation", - "pendingAnnotationExpiry", - ]); - if ( - localData.pendingAnnotation && - localData.pendingAnnotationExpiry > Date.now() - ) { - pendingData = localData.pendingAnnotation; - } - await chrome.storage.local.remove([ - "pendingAnnotation", - "pendingAnnotationExpiry", - ]); - } - - if (pendingData?.selector) { - pendingSelector = pendingData.selector; - showQuotePreview(pendingSelector); - } - - checkSession(); - } catch (err) { - console.error("Init error:", err); - showView("login"); - } - - chrome.tabs.onActivated.addListener(async (activeInfo) => { - try { - const tab = await chrome.tabs.get(activeInfo.tabId); - currentTab = tab; - if (els.currentPageUrl) { - try { - els.currentPageUrl.textContent = new URL(tab.url).hostname; - } catch { - els.currentPageUrl.textContent = tab.url; - } - } - loadAnnotations(); - } catch (err) { - console.error("Tab change error:", err); - } - }); - - chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { - if (currentTab && tabId === currentTab.id && changeInfo.url) { - currentTab = tab; - if (els.currentPageUrl) { - try { - els.currentPageUrl.textContent = new URL(tab.url).hostname; - } catch { - els.currentPageUrl.textContent = tab.url; - } - } - loadAnnotations(); - } - }); - - els.signInBtn?.addEventListener("click", () => { - chrome.runtime.sendMessage({ type: "OPEN_LOGIN" }); - }); - - els.openWebBtn?.addEventListener("click", (e) => { - e.preventDefault(); - chrome.runtime.sendMessage({ type: "OPEN_WEB" }); - }); - - els.tabs.forEach((btn) => { - btn.addEventListener("click", () => { - els.tabs.forEach((t) => t.classList.remove("active")); - els.tabContents.forEach((c) => c.classList.remove("active")); - const tabId = btn.getAttribute("data-tab"); - btn.classList.add("active"); - document.getElementById(`tab-${tabId}`).classList.add("active"); - if (tabId === "bookmarks") loadBookmarks(); - if (tabId === "highlights") loadHighlights(); - }); - }); - - els.submitBtn?.addEventListener("click", async () => { - const text = els.textInput.value.trim(); - if (!text) return; - - els.submitBtn.disabled = true; - els.submitBtn.textContent = "Posting..."; - - try { - const annotationData = { - url: currentTab.url, - text: text, - title: currentTab.title, - }; - - if (pendingSelector) { - annotationData.selector = pendingSelector; - } - - const res = await sendMessage({ - type: "CREATE_ANNOTATION", - data: annotationData, - }); - - if (res.success) { - els.textInput.value = ""; - pendingSelector = null; - hideQuotePreview(); - loadAnnotations(); - } else { - alert("Failed to post annotation: " + (res.error || "Unknown error")); - } - } catch (err) { - console.error("Post error:", err); - alert("Error posting annotation"); - } finally { - els.submitBtn.disabled = false; - els.submitBtn.textContent = "Post"; - } - }); - - els.bookmarkBtn?.addEventListener("click", async () => { - els.bookmarkBtn.disabled = true; - const originalText = els.bookmarkBtn.textContent; - els.bookmarkBtn.textContent = "Saving..."; - - try { - const res = await sendMessage({ - type: "CREATE_BOOKMARK", - data: { - url: currentTab.url, - title: currentTab.title, - }, - }); - - if (res.success) { - els.bookmarkBtn.textContent = "✓ Bookmarked"; - setTimeout(() => { - els.bookmarkBtn.textContent = originalText; - els.bookmarkBtn.disabled = false; - }, 2000); - } else { - alert("Failed to bookmark page: " + (res.error || "Unknown error")); - els.bookmarkBtn.textContent = originalText; - els.bookmarkBtn.disabled = false; - } - } catch (err) { - console.error("Bookmark error:", err); - alert("Error bookmarking page"); - els.bookmarkBtn.textContent = originalText; - els.bookmarkBtn.disabled = false; - } - }); - - els.refreshBtn?.addEventListener("click", () => { - loadAnnotations(); - }); - - els.toggleSettings?.addEventListener("click", () => { - views.settings.style.display = "flex"; - }); - - els.closeSettings?.addEventListener("click", () => { - views.settings.style.display = "none"; - }); - - els.closeCollectionSelector?.addEventListener("click", () => { - views.collectionSelector.style.display = "none"; - }); - - els.saveSettings?.addEventListener("click", async () => { - const newUrl = els.apiUrlInput.value.replace(/\/$/, ""); - const showOverlay = els.overlayToggle?.checked ?? true; - - await chrome.storage.local.set({ - apiUrl: newUrl, - showOverlay, - }); - if (newUrl) { - apiUrl = newUrl; - } - await sendMessage({ type: "UPDATE_SETTINGS" }); - - const tabs = await chrome.tabs.query({}); - for (const tab of tabs) { - if (tab.id) { - try { - await chrome.tabs.sendMessage(tab.id, { - type: "UPDATE_OVERLAY_VISIBILITY", - show: showOverlay, - }); - } catch { - /* ignore */ - } - } - } - - views.settings.style.display = "none"; - checkSession(); - }); - - els.signOutBtn?.addEventListener("click", async () => { - if (apiUrl) { - await chrome.cookies.remove({ - url: apiUrl, - name: "margin_session", - }); - } - views.settings.style.display = "none"; - showView("login"); - els.userInfo.style.display = "none"; - }); - - async function checkSession() { - showView("loading"); - try { - const res = await sendMessage({ type: "CHECK_SESSION" }); - - if (res.success && res.data?.authenticated) { - if (els.userHandle) els.userHandle.textContent = "@" + res.data.handle; - els.userInfo.style.display = "flex"; - currentUserDid = res.data.did; - showView("main"); - loadAnnotations(); - } else { - els.userInfo.style.display = "none"; - showView("login"); - } - } catch (err) { - console.error("Session check error:", err); - els.userInfo.style.display = "none"; - showView("login"); - } - } - - async function loadAnnotations() { - if (!currentTab?.url) return; - - try { - const res = await sendMessage({ - type: "GET_ANNOTATIONS", - data: { url: currentTab.url }, - }); - - if (res.success) { - if (currentUserDid) { - const isBookmarked = res.data.some( - (item) => - item.type === "Bookmark" && item.creator.did === currentUserDid, - ); - if (els.bookmarkBtn) { - if (isBookmarked) { - els.bookmarkBtn.textContent = "✓ Bookmarked"; - els.bookmarkBtn.disabled = true; - } else { - els.bookmarkBtn.textContent = "Bookmark Page"; - els.bookmarkBtn.disabled = false; - } - } - } - - const listItems = res.data.filter((item) => item.type !== "Bookmark"); - renderAnnotations(listItems); - } - } catch (err) { - console.error("Load annotations error:", err); - } - } - - async function loadBookmarks() { - if (!currentUserDid) return; - els.bookmarksList.innerHTML = - '
'; - els.bookmarksEmpty.style.display = "none"; - - try { - const res = await sendMessage({ - type: "GET_USER_BOOKMARKS", - data: { did: currentUserDid }, - }); - - if (res.success) { - renderBookmarks(res.data); - } - } catch (err) { - console.error("Load bookmarks error:", err); - els.bookmarksList.innerHTML = - '

Failed to load bookmarks

'; - } - } - - async function loadHighlights() { - if (!currentUserDid) return; - els.highlightsList.innerHTML = - '
'; - els.highlightsEmpty.style.display = "none"; - - try { - const res = await sendMessage({ - type: "GET_USER_HIGHLIGHTS", - data: { did: currentUserDid }, - }); - - if (res.success) { - renderHighlights(res.data); - } - } catch (err) { - console.error("Load highlights error:", err); - els.highlightsList.innerHTML = - '

Failed to load highlights

'; - } - } - - async function openCollectionSelector(annotationUri) { - if (!currentUserDid) { - console.error("No currentUserDid, returning early"); - return; - } - views.collectionSelector.style.display = "flex"; - els.collectionList.innerHTML = ""; - els.collectionLoading.style.display = "block"; - els.collectionsEmpty.style.display = "none"; - - try { - const [collectionsRes, containingRes] = await Promise.all([ - sendMessage({ - type: "GET_USER_COLLECTIONS", - data: { did: currentUserDid }, - }), - sendMessage({ - type: "GET_CONTAINING_COLLECTIONS", - data: { uri: annotationUri }, - }), - ]); - - if (collectionsRes.success) { - const containingUris = containingRes.success - ? new Set(containingRes.data) - : new Set(); - renderCollectionList( - collectionsRes.data, - annotationUri, - containingUris, - ); - } - } catch (err) { - console.error("Load collections error:", err); - els.collectionList.innerHTML = - '

Failed to load collections

'; - } finally { - els.collectionLoading.style.display = "none"; - } - } - - function renderCollectionList( - items, - annotationUri, - containingUris = new Set(), - ) { - els.collectionList.innerHTML = ""; - els.collectionList.dataset.annotationUri = annotationUri; - - if (!items || items.length === 0) { - els.collectionsEmpty.style.display = "block"; - return; - } - - items.forEach((collection) => { - const btn = document.createElement("button"); - btn.className = "collection-select-btn"; - const isAdded = containingUris.has(collection.uri); - - const icon = document.createElement("span"); - if (isAdded) { - icon.textContent = "✓"; - } else { - icon.innerHTML = - ''; - } - btn.appendChild(icon); - - const name = document.createElement("span"); - name.textContent = collection.name; - btn.appendChild(name); - - if (isAdded) { - btn.classList.add("added"); - btn.disabled = true; - } - - btn.addEventListener("click", async () => { - if (btn.disabled) return; - const annUri = els.collectionList.dataset.annotationUri; - await handleAddToCollection(collection.uri, btn, annUri); - }); - - els.collectionList.appendChild(btn); - }); - } - - async function handleAddToCollection( - collectionUri, - btnElement, - annotationUri, - ) { - if (!annotationUri) { - console.error("No annotationUri provided!"); - alert("Error: No item selected to add"); - return; - } - - const originalText = btnElement.textContent; - btnElement.disabled = true; - btnElement.textContent = "Adding..."; - - try { - const res = await sendMessage({ - type: "ADD_TO_COLLECTION", - data: { - collectionUri: collectionUri, - annotationUri: annotationUri, - }, - }); - - if (res && res.success) { - btnElement.textContent = "✓ Added"; - setTimeout(() => { - btnElement.textContent = originalText; - btnElement.disabled = false; - }, 2000); - } else { - alert( - "Failed to add to collection: " + (res?.error || "Unknown error"), - ); - btnElement.textContent = originalText; - btnElement.disabled = false; - } - } catch (err) { - console.error("Add to collection error:", err); - alert("Error adding to collection: " + err.message); - btnElement.textContent = originalText; - btnElement.disabled = false; - } - } - - function renderAnnotations(items) { - els.annotationsList.innerHTML = ""; - els.annotationCount.textContent = items?.length || 0; - - if (!items || items.length === 0) { - els.emptyState.style.display = "flex"; - return; - } - - els.emptyState.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("div"); - el.className = "annotation-item"; - - const author = item.creator || item.author || {}; - const authorName = author.handle || author.displayName || "Unknown"; - const authorInitial = authorName[0]?.toUpperCase() || "?"; - const createdAt = item.created || item.createdAt; - const text = item.body?.value || item.text || ""; - const selector = item.target?.selector; - const isHighlight = item.type === "Highlight"; - const quote = selector?.exact || ""; - - const header = document.createElement("div"); - header.className = "annotation-item-header"; - - const avatar = document.createElement("div"); - avatar.className = "annotation-item-avatar"; - - if (author.avatar) { - const img = document.createElement("img"); - img.src = author.avatar; - img.alt = authorName; - img.style.width = "100%"; - img.style.height = "100%"; - img.style.borderRadius = "50%"; - img.style.objectFit = "cover"; - avatar.appendChild(img); - avatar.style.background = "none"; - } else { - avatar.textContent = authorInitial; - } - header.appendChild(avatar); - - const meta = document.createElement("div"); - meta.className = "annotation-item-meta"; - - const authorEl = document.createElement("div"); - authorEl.className = "annotation-item-author"; - authorEl.textContent = "@" + authorName; - meta.appendChild(authorEl); - - const timeEl = document.createElement("div"); - timeEl.className = "annotation-item-time"; - timeEl.textContent = formatDate(createdAt); - meta.appendChild(timeEl); - - header.appendChild(meta); - - if (isHighlight) { - const badge = document.createElement("span"); - badge.className = "annotation-type-badge highlight"; - badge.textContent = "Highlight"; - header.appendChild(badge); - } - - if (currentUserDid) { - const actions = document.createElement("div"); - actions.className = "annotation-item-actions"; - - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.stopPropagation(); - openCollectionSelector(item.uri); - }); - actions.appendChild(folderBtn); - header.appendChild(actions); - } - - el.appendChild(header); - - if (quote) { - const quoteEl = document.createElement("div"); - quoteEl.className = "annotation-item-quote"; - quoteEl.textContent = '"' + quote + '"'; - el.appendChild(quoteEl); - } - - if (text) { - const textEl = document.createElement("div"); - textEl.className = "annotation-item-text"; - textEl.textContent = text; - el.appendChild(textEl); - } - - if (selector) { - const jumpBtn = document.createElement("button"); - jumpBtn.className = "scroll-to-btn"; - jumpBtn.textContent = "Jump to text →"; - el.appendChild(jumpBtn); - } - - if (selector) { - el.querySelector(".scroll-to-btn")?.addEventListener("click", (e) => { - e.stopPropagation(); - scrollToText(selector); - }); - } - - els.annotationsList.appendChild(el); - }); - } - - function renderBookmarks(items) { - els.bookmarksList.innerHTML = ""; - - if (!items || items.length === 0) { - els.bookmarksEmpty.style.display = "flex"; - return; - } - - els.bookmarksEmpty.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("div"); - el.className = "bookmark-item"; - el.style.cursor = "pointer"; - el.addEventListener("click", () => { - window.open(item.source, "_blank"); - }); - - let hostname = item.source; - try { - hostname = new URL(item.source).hostname; - } catch { - /* ignore */ - } - - const row = document.createElement("div"); - row.style.display = "flex"; - row.style.justifyContent = "space-between"; - row.style.alignItems = "center"; - - const content = document.createElement("div"); - content.style.flex = "1"; - content.style.overflow = "hidden"; - - const titleEl = document.createElement("div"); - titleEl.className = "bookmark-title"; - titleEl.textContent = item.title || item.source; - content.appendChild(titleEl); - - const urlEl = document.createElement("div"); - urlEl.className = "bookmark-url"; - urlEl.textContent = hostname; - content.appendChild(urlEl); - - row.appendChild(content); - - if (currentUserDid) { - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.preventDefault(); - e.stopPropagation(); - openCollectionSelector(item.uri); - }); - row.appendChild(folderBtn); - } - - el.appendChild(row); - els.bookmarksList.appendChild(el); - }); - } - - function renderHighlights(items) { - els.highlightsList.innerHTML = ""; - - if (!items || items.length === 0) { - els.highlightsEmpty.style.display = "flex"; - return; - } - - els.highlightsEmpty.style.display = "none"; - items.forEach((item) => { - const el = document.createElement("div"); - el.className = "annotation-item"; - - const target = item.target || {}; - const selector = target.selector || {}; - const quote = selector.exact || ""; - const url = target.source || ""; - - let hostname = url; - try { - hostname = new URL(url).hostname; - } catch { - /* ignore */ - } - - const header = document.createElement("div"); - header.className = "annotation-item-header"; - - const meta = document.createElement("div"); - meta.className = "annotation-item-meta"; - - const authorEl = document.createElement("div"); - authorEl.className = "annotation-item-author"; - authorEl.textContent = hostname; - meta.appendChild(authorEl); - - const timeEl = document.createElement("div"); - timeEl.className = "annotation-item-time"; - timeEl.textContent = formatDate(item.created); - meta.appendChild(timeEl); - - header.appendChild(meta); - - if (currentUserDid) { - const actions = document.createElement("div"); - actions.className = "annotation-item-actions"; - - const folderBtn = document.createElement("button"); - folderBtn.className = "btn-icon"; - folderBtn.innerHTML = - ''; - folderBtn.title = "Add to Collection"; - folderBtn.addEventListener("click", (e) => { - e.stopPropagation(); - openCollectionSelector(item.uri); - }); - actions.appendChild(folderBtn); - header.appendChild(actions); - } - - el.appendChild(header); - - if (quote) { - const quoteEl = document.createElement("div"); - quoteEl.className = "annotation-item-quote"; - quoteEl.style.borderColor = item.color || "#fcd34d"; - quoteEl.textContent = '"' + quote + '"'; - el.appendChild(quoteEl); - } - - const openBtn = document.createElement("button"); - openBtn.className = "scroll-to-btn"; - openBtn.textContent = "Open page →"; - el.appendChild(openBtn); - - el.querySelector(".scroll-to-btn")?.addEventListener("click", (e) => { - e.stopPropagation(); - const textFragment = createTextFragment(url, selector); - chrome.tabs.create({ url: textFragment }); - }); - - els.highlightsList.appendChild(el); - }); - } - - async function scrollToText(selector) { - let tabId = currentTab?.id; - if (!tabId) { - try { - const [tab] = await chrome.tabs.query({ - active: true, - currentWindow: true, - }); - tabId = tab?.id; - } catch (e) { - console.error("Could not get active tab:", e); - } - } - - if (!tabId) { - console.error("No tab ID available for scroll"); - return; - } - - try { - await chrome.tabs.sendMessage(tabId, { - type: "SCROLL_TO_TEXT", - selector: selector, - }); - } catch (err) { - console.error("Error sending SCROLL_TO_TEXT:", err); - } - } - - function createTextFragment(url, selector) { - if (!selector || selector.type !== "TextQuoteSelector" || !selector.exact) - return url; - - let fragment = ":~:text="; - if (selector.prefix) fragment += encodeURIComponent(selector.prefix) + "-,"; - fragment += encodeURIComponent(selector.exact); - if (selector.suffix) fragment += ",-" + encodeURIComponent(selector.suffix); - - return url + "#" + fragment; - } - - function formatDate(dateString) { - if (!dateString) return ""; - try { - const date = new Date(dateString); - const now = new Date(); - const diffMs = now - date; - const diffMins = Math.floor(diffMs / 60000); - const diffHours = Math.floor(diffMs / 3600000); - const diffDays = Math.floor(diffMs / 86400000); - - if (diffMins < 1) return "Just now"; - if (diffMins < 60) return `${diffMins}m ago`; - if (diffHours < 24) return `${diffHours}h ago`; - if (diffDays < 7) return `${diffDays}d ago`; - return date.toLocaleDateString(); - } catch { - return dateString; - } - } - - function showQuotePreview(selector) { - if (!selector?.exact) return; - - let preview = document.getElementById("quote-preview"); - if (!preview) { - preview = document.createElement("div"); - preview.id = "quote-preview"; - preview.className = "quote-preview"; - const form = document.querySelector(".create-form"); - if (form) { - form.insertBefore(preview, form.querySelector(".annotation-input")); - } - } - - const header = document.createElement("div"); - header.className = "quote-preview-header"; - - const label = document.createElement("span"); - label.textContent = "Annotating selection:"; - header.appendChild(label); - - const clearBtn = document.createElement("button"); - clearBtn.className = "quote-preview-clear"; - clearBtn.title = "Clear selection"; - clearBtn.textContent = "×"; - clearBtn.addEventListener("click", () => { - pendingSelector = null; - hideQuotePreview(); - }); - header.appendChild(clearBtn); - - preview.appendChild(header); - - const text = document.createElement("div"); - text.className = "quote-preview-text"; - text.textContent = '"' + selector.exact + '"'; - preview.appendChild(text); - - els.textInput?.focus(); - } - - function hideQuotePreview() { - const preview = document.getElementById("quote-preview"); - if (preview) { - preview.remove(); - } - } - - function showView(viewName) { - Object.keys(views).forEach((key) => { - if (views[key]) views[key].style.display = "none"; - }); - if (views[viewName]) { - views[viewName].style.display = - viewName === "loading" || viewName === "settings" ? "flex" : "block"; - } - } - - function sendMessage(message) { - return new Promise((resolve, reject) => { - chrome.runtime.sendMessage(message, (response) => { - if (chrome.runtime.lastError) { - reject(chrome.runtime.lastError); - } else { - resolve(response); - } - }); - }); - } - - function applyTheme(theme) { - document.body.classList.remove("light", "dark"); - if (theme === "system") return; - document.body.classList.add(theme); - } - - function updateThemeUI(theme) { - const btns = document.querySelectorAll(".theme-btn"); - btns.forEach((btn) => { - if (btn.getAttribute("data-theme") === theme) { - btn.classList.add("active"); - } else { - btn.classList.remove("active"); - } - }); - } -}); diff --git a/extension/src/assets/styles.css b/extension/src/assets/styles.css new file mode 100644 index 0000000..e6c7faf --- /dev/null +++ b/extension/src/assets/styles.css @@ -0,0 +1,161 @@ +@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&display=swap'); + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --bg-primary: #0a0a0d; + --bg-secondary: #121216; + --bg-tertiary: #1a1a1f; + --bg-card: #0f0f13; + --bg-elevated: #18181d; + --bg-hover: #1e1e24; + --text-primary: #eaeaee; + --text-secondary: #b7b6c5; + --text-tertiary: #6e6d7a; + --border: rgba(183, 182, 197, 0.12); + --border-strong: rgba(183, 182, 197, 0.2); + --accent: #957a86; + --accent-hover: #a98d98; + --accent-subtle: rgba(149, 122, 134, 0.15); + --success: #34d399; + --warning: #fbbf24; +} + +.light { + --bg-primary: #f8f8fa; + --bg-secondary: #ffffff; + --bg-tertiary: #f0f0f4; + --bg-card: #ffffff; + --bg-elevated: #ffffff; + --bg-hover: #eeeef2; + --text-primary: #18171c; + --text-secondary: #5c495a; + --text-tertiary: #8a8494; + --border: rgba(92, 73, 90, 0.12); + --border-strong: rgba(92, 73, 90, 0.2); + --accent: #7a5f6d; + --accent-hover: #664e5b; + --accent-subtle: rgba(149, 122, 134, 0.12); +} + +body { + background: var(--bg-primary); + color: var(--text-primary); + font-family: + 'IBM Plex Sans', + -apple-system, + BlinkMacSystemFont, + sans-serif; + margin: 0; + padding: 0; + min-width: 320px; + max-width: 100%; + min-height: 100vh; + overflow: hidden; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html.popup body { + width: 380px; + height: 520px; + min-height: 520px; +} + +* { + box-sizing: border-box; +} + +::-webkit-scrollbar { + width: 6px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + background: var(--bg-tertiary); + border-radius: 3px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +} + +button, +a, +input, +textarea { + transition: all 0.15s ease; +} + +input:focus, +textarea:focus, +button:focus-visible { + outline: none; + box-shadow: + 0 0 0 2px var(--accent-subtle), + 0 0 0 4px var(--accent); +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(-4px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideDown { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.animate-fadeIn { + animation: fadeIn 0.2s ease forwards; +} + +.animate-slideUp { + animation: slideUp 0.25s ease forwards; +} + +.animate-slideDown { + animation: slideDown 0.2s ease forwards; +} + +.animate-pulse { + animation: pulse 1.5s ease-in-out infinite; +} diff --git a/extension/src/components/CollectionIcon.tsx b/extension/src/components/CollectionIcon.tsx new file mode 100644 index 0000000..b9cdba6 --- /dev/null +++ b/extension/src/components/CollectionIcon.tsx @@ -0,0 +1,124 @@ +import { + Folder, + Star, + Heart, + Bookmark, + Lightbulb, + Zap, + Coffee, + Music, + Camera, + Code, + Globe, + Flag, + Tag, + Box, + Archive, + FileText, + Image, + Video, + Mail, + MapPin, + Calendar, + Clock, + Search, + Settings, + User, + Users, + Home, + Briefcase, + Gift, + Award, + Target, + TrendingUp, + Activity, + Cpu, + Database, + Cloud, + Sun, + Moon, + Flame, + Leaf, + type LucideIcon, +} from 'lucide-react'; + +const ICON_MAP: Record = { + folder: Folder, + star: Star, + heart: Heart, + bookmark: Bookmark, + lightbulb: Lightbulb, + zap: Zap, + coffee: Coffee, + music: Music, + camera: Camera, + code: Code, + globe: Globe, + flag: Flag, + tag: Tag, + box: Box, + archive: Archive, + file: FileText, + image: Image, + video: Video, + mail: Mail, + pin: MapPin, + calendar: Calendar, + clock: Clock, + search: Search, + settings: Settings, + user: User, + users: Users, + home: Home, + briefcase: Briefcase, + gift: Gift, + award: Award, + target: Target, + trending: TrendingUp, + activity: Activity, + cpu: Cpu, + database: Database, + cloud: Cloud, + sun: Sun, + moon: Moon, + flame: Flame, + leaf: Leaf, +}; + +interface CollectionIconProps { + icon?: string; + size?: number; + className?: string; +} + +export default function CollectionIcon({ icon, size = 18, className = '' }: CollectionIconProps) { + if (!icon) { + return ; + } + + if (icon === 'icon:semble') { + return ( + Semble + ); + } + + if (icon.startsWith('icon:')) { + const iconName = icon.replace('icon:', ''); + const IconComponent = ICON_MAP[iconName]; + if (IconComponent) { + return ; + } + return ; + } + + return ( + + {icon} + + ); +} diff --git a/extension/src/components/popup/App.tsx b/extension/src/components/popup/App.tsx new file mode 100644 index 0000000..718dd05 --- /dev/null +++ b/extension/src/components/popup/App.tsx @@ -0,0 +1,986 @@ +import { useState, useEffect } from 'react'; +import { sendMessage } from '@/utils/messaging'; +import { themeItem, apiUrlItem, overlayEnabledItem } from '@/utils/storage'; +import type { MarginSession, Annotation, Bookmark, Highlight, Collection } from '@/utils/types'; +import CollectionIcon from '@/components/CollectionIcon'; +import { + Settings, + ExternalLink, + Bookmark as BookmarkIcon, + Highlighter, + MessageSquare, + X, + Sun, + Moon, + Monitor, + Check, + Globe, + ChevronRight, + Sparkles, + FolderPlus, + Folder, +} from 'lucide-react'; + +type Tab = 'page' | 'bookmarks' | 'highlights' | 'collections'; + +export function App() { + const [session, setSession] = useState(null); + const [loading, setLoading] = useState(true); + const [activeTab, setActiveTab] = useState('page'); + const [annotations, setAnnotations] = useState([]); + const [bookmarks, setBookmarks] = useState([]); + const [highlights, setHighlights] = useState([]); + const [collections, setCollections] = useState([]); + const [loadingAnnotations, setLoadingAnnotations] = useState(false); + const [loadingBookmarks, setLoadingBookmarks] = useState(false); + const [loadingHighlights, setLoadingHighlights] = useState(false); + const [loadingCollections, setLoadingCollections] = useState(false); + const [collectionModalItem, setCollectionModalItem] = useState(null); + const [addingToCollection, setAddingToCollection] = useState(null); + const [containingCollections, setContainingCollections] = useState>(new Set()); + const [currentUrl, setCurrentUrl] = useState(''); + const [currentTitle, setCurrentTitle] = useState(''); + const [text, setText] = useState(''); + const [posting, setPosting] = useState(false); + const [bookmarking, setBookmarking] = useState(false); + const [bookmarked, setBookmarked] = useState(false); + const [theme, setTheme] = useState<'light' | 'dark' | 'system'>('system'); + const [showSettings, setShowSettings] = useState(false); + const [apiUrl, setApiUrl] = useState('https://margin.at'); + const [overlayEnabled, setOverlayEnabled] = useState(true); + + useEffect(() => { + checkSession(); + loadCurrentTab(); + loadTheme(); + loadSettings(); + }, []); + + useEffect(() => { + if (session?.authenticated && currentUrl) { + if (activeTab === 'page') loadAnnotations(); + else if (activeTab === 'bookmarks') loadBookmarks(); + else if (activeTab === 'highlights') loadHighlights(); + else if (activeTab === 'collections') loadCollections(); + } + }, [activeTab, session, currentUrl]); + + async function loadSettings() { + const url = await apiUrlItem.getValue(); + const overlay = await overlayEnabledItem.getValue(); + setApiUrl(url); + setOverlayEnabled(overlay); + } + + async function saveSettings() { + const cleanUrl = apiUrl.replace(/\/$/, ''); + await apiUrlItem.setValue(cleanUrl); + await overlayEnabledItem.setValue(overlayEnabled); + + const tabs = await browser.tabs.query({}); + for (const tab of tabs) { + if (tab.id) { + try { + await browser.tabs.sendMessage(tab.id, { + type: 'UPDATE_OVERLAY_VISIBILITY', + show: overlayEnabled, + }); + } catch { + /* ignore */ + } + } + } + + setShowSettings(false); + checkSession(); + } + + async function loadTheme() { + const t = await themeItem.getValue(); + setTheme(t); + applyTheme(t); + + themeItem.watch((newTheme) => { + setTheme(newTheme); + applyTheme(newTheme); + }); + } + + function applyTheme(t: string) { + document.body.classList.remove('light', 'dark'); + if (t === 'system') { + if (window.matchMedia('(prefers-color-scheme: light)').matches) { + document.body.classList.add('light'); + } + } else { + document.body.classList.add(t); + } + } + + async function handleThemeChange(newTheme: 'light' | 'dark' | 'system') { + await themeItem.setValue(newTheme); + setTheme(newTheme); + applyTheme(newTheme); + } + + async function checkSession() { + try { + const result = await sendMessage('checkSession', undefined); + setSession(result); + } catch (error) { + console.error('Session check error:', error); + setSession({ authenticated: false }); + } finally { + setLoading(false); + } + } + + async function loadCurrentTab() { + const [tab] = await browser.tabs.query({ active: true, currentWindow: true }); + if (tab?.url) { + setCurrentUrl(tab.url); + setCurrentTitle(tab.title || ''); + } + } + + async function loadAnnotations() { + if (!currentUrl) return; + setLoadingAnnotations(true); + try { + let result = await sendMessage('getCachedAnnotations', { url: currentUrl }); + + if (!result) { + result = await sendMessage('getAnnotations', { url: currentUrl }); + } + + const filtered = (result || []).filter((item: any) => item.type !== 'Bookmark'); + setAnnotations(filtered); + + const isBookmarked = (result || []).some( + (item: any) => item.type === 'Bookmark' && item.creator?.did === session?.did + ); + setBookmarked(isBookmarked); + } catch (error) { + console.error('Load annotations error:', error); + } finally { + setLoadingAnnotations(false); + } + } + + async function loadBookmarks() { + if (!session?.did) return; + setLoadingBookmarks(true); + try { + const result = await sendMessage('getUserBookmarks', { did: session.did }); + setBookmarks(result || []); + } catch (error) { + console.error('Load bookmarks error:', error); + } finally { + setLoadingBookmarks(false); + } + } + + async function loadHighlights() { + if (!session?.did) return; + setLoadingHighlights(true); + try { + const result = await sendMessage('getUserHighlights', { did: session.did }); + setHighlights(result || []); + } catch (error) { + console.error('Load highlights error:', error); + } finally { + setLoadingHighlights(false); + } + } + + async function loadCollections() { + if (!session?.did) return; + setLoadingCollections(true); + try { + const result = await sendMessage('getUserCollections', { did: session.did }); + setCollections(result || []); + } catch (error) { + console.error('Load collections error:', error); + } finally { + setLoadingCollections(false); + } + } + + async function openCollectionModal(itemUri: string) { + setCollectionModalItem(itemUri); + setContainingCollections(new Set()); + + if (collections.length === 0) { + await loadCollections(); + } + + try { + const itemCollectionUris = await sendMessage('getItemCollections', { + annotationUri: itemUri, + }); + setContainingCollections(new Set(itemCollectionUris)); + } catch (error) { + console.error('Failed to get item collections:', error); + } + } + + async function handleAddToCollection(collectionUri: string) { + if (!collectionModalItem) return; + + if (containingCollections.has(collectionUri)) { + setCollectionModalItem(null); + return; + } + + setAddingToCollection(collectionUri); + try { + const result = await sendMessage('addToCollection', { + collectionUri, + annotationUri: collectionModalItem, + }); + if (result.success) { + setContainingCollections((prev) => new Set([...prev, collectionUri])); + } else { + alert('Failed to add to collection'); + } + } catch (error) { + console.error('Add to collection error:', error); + alert('Error adding to collection'); + } finally { + setAddingToCollection(null); + } + } + + async function handlePost() { + if (!text.trim()) return; + setPosting(true); + try { + const result = await sendMessage('createAnnotation', { + url: currentUrl, + text: text.trim(), + title: currentTitle, + }); + if (result.success) { + setText(''); + loadAnnotations(); + } else { + alert('Failed to post annotation'); + } + } catch (error) { + console.error('Post error:', error); + alert('Error posting annotation'); + } finally { + setPosting(false); + } + } + + async function handleBookmark() { + setBookmarking(true); + try { + const result = await sendMessage('createBookmark', { + url: currentUrl, + title: currentTitle, + }); + if (result.success) { + setBookmarked(true); + } else { + alert('Failed to bookmark page'); + } + } catch (error) { + console.error('Bookmark error:', error); + alert('Error bookmarking page'); + } finally { + setBookmarking(false); + } + } + + function formatDate(dateString?: string) { + if (!dateString) return ''; + try { + return new Date(dateString).toLocaleDateString(); + } catch { + return dateString; + } + } + + if (loading) { + return ( +
+
+
+ ); + } + + if (!session?.authenticated) { + return ( +
+ {showSettings && ( +
+
+ Settings + +
+ +
+
+ + setApiUrl(e.target.value)} + className="w-full p-2.5 bg-[var(--bg-card)] border border-[var(--border)] rounded-lg text-sm focus:outline-none focus:border-[var(--accent)]" + placeholder="https://margin.at" + /> +
+ +
+ +
+ {(['light', 'dark', 'system'] as const).map((t) => ( + + ))} +
+
+
+ +
+ +
+
+ )} + +
+ Margin +

Sign in with AT Protocol

+

+ Connect your Bluesky account to annotate, highlight, and bookmark the web. +

+ + +
+
+ ); + } + + return ( +
+ {showSettings && ( +
+
+ Settings + +
+ +
+
+ + setApiUrl(e.target.value)} + className="w-full p-2.5 bg-[var(--bg-card)] border border-[var(--border)] rounded-lg text-sm focus:outline-none focus:border-[var(--accent)]" + placeholder="https://margin.at" + /> +

+ Change this for development or self-hosted instances +

+
+ +
+
+ +

+ Highlights, badges, and tooltips on pages +

+
+ setOverlayEnabled(e.target.checked)} + className="w-5 h-5 rounded accent-[var(--accent)]" + /> +
+ +
+ +
+ {(['light', 'dark', 'system'] as const).map((t) => ( + + ))} +
+
+
+ +
+ +
+
+ )} + +
+
+ Margin + Margin +
+
+
+ @{session.handle} +
+
+
+ +
+ {(['page', 'bookmarks', 'highlights', 'collections'] as Tab[]).map((tab) => { + const icons: Record = { + page: , + bookmarks: , + highlights: , + collections: , + }; + const labels: Record = { + page: 'Page', + bookmarks: 'Bookmarks', + highlights: 'Highlights', + collections: 'Collections', + }; + return ( + + ); + })} +
+ +
+ {activeTab === 'page' && ( +
+
+
+
+ {currentUrl ? ( + { + (e.target as HTMLImageElement).style.display = 'none'; + (e.target as HTMLImageElement).nextElementSibling?.classList.remove( + 'hidden' + ); + }} + /> + ) : null} + +
+
+
+ {currentTitle || 'Untitled'} +
+
+ {currentUrl ? new URL(currentUrl).hostname : ''} +
+
+ +
+
+ +
+
+ +
+ + `; + + composeModal.querySelector('.compose-close')?.addEventListener('click', () => { + composeModal?.remove(); + composeModal = null; + }); + + composeModal.querySelector('.btn-cancel')?.addEventListener('click', () => { + composeModal?.remove(); + composeModal = null; + }); + + const textarea = composeModal.querySelector( + '.inline-compose-textarea' + ) as HTMLTextAreaElement; + const submitBtn = composeModal.querySelector('.btn-submit') as HTMLButtonElement; + + submitBtn.addEventListener('click', async () => { + const text = textarea?.value.trim(); + if (!text) return; + + submitBtn.disabled = true; + submitBtn.textContent = 'Posting...'; + + try { + await sendMessage('createAnnotation', { + url: window.location.href, + title: document.title, + text, + selector: { type: 'TextQuoteSelector', exact: quoteText }, + }); + + showToast('Annotation created!', 'success'); + composeModal?.remove(); + composeModal = null; + + setTimeout(() => fetchAnnotations(), 500); + } catch (error) { + console.error('Failed to create annotation:', error); + showToast('Failed to create annotation', 'error'); + submitBtn.disabled = false; + submitBtn.textContent = 'Post'; + } + }); + + container.appendChild(composeModal); + setTimeout(() => textarea?.focus(), 100); + } + browser.runtime.onMessage.addListener((message: any) => { + if (message.type === 'SHOW_INLINE_ANNOTATE' && message.data?.selector?.exact) { + showComposeModal(message.data.selector.exact); + } + if (message.type === 'REFRESH_ANNOTATIONS') { + fetchAnnotations(); + } + if (message.type === 'SCROLL_TO_TEXT' && message.text) { + scrollToText(message.text); + } + if (message.type === 'GET_SELECTION') { + const selection = window.getSelection(); + const text = selection?.toString().trim() || ''; + return Promise.resolve({ text }); + } + }); + + function scrollToText(text: string) { + if (!text || text.length < 10) return; + + const searchText = text.slice(0, 150); + const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null); + + let node: Text | null; + while ((node = walker.nextNode() as Text | null)) { + const content = node.textContent || ''; + const index = content.indexOf(searchText.slice(0, 50)); + if (index !== -1) { + const range = document.createRange(); + range.setStart(node, index); + range.setEnd(node, Math.min(index + searchText.length, content.length)); + + const rect = range.getBoundingClientRect(); + const scrollY = window.scrollY + rect.top - window.innerHeight / 3; + + window.scrollTo({ top: scrollY, behavior: 'smooth' }); + + const highlight = document.createElement('mark'); + highlight.style.cssText = + 'background: #6366f1; color: white; padding: 2px 0; border-radius: 2px; transition: background 0.5s;'; + range.surroundContents(highlight); + + setTimeout(() => { + highlight.style.background = 'transparent'; + highlight.style.color = 'inherit'; + setTimeout(() => { + const parent = highlight.parentNode; + if (parent) { + parent.replaceChild( + document.createTextNode(highlight.textContent || ''), + highlight + ); + parent.normalize(); + } + }, 500); + }, 1500); + + return; + } + } + } + + function showToast(message: string, type: 'success' | 'error' = 'success') { + if (!shadowRoot) return; + + const container = shadowRoot.getElementById('margin-overlay-container'); + if (!container) return; + + container.querySelectorAll('.margin-toast').forEach((el) => el.remove()); + + const toast = document.createElement('div'); + toast.className = `margin-toast ${type === 'success' ? 'toast-success' : ''}`; + toast.innerHTML = ` + ${type === 'success' ? Icons.check : Icons.close} + ${message} + `; + + container.appendChild(toast); + + setTimeout(() => { + toast.classList.add('toast-out'); + setTimeout(() => toast.remove(), 200); + }, 2500); + } + + async function fetchAnnotations(retryCount = 0) { + if (!overlayEnabled) { + sendMessage('updateBadge', { count: 0 }); + return; + } + + try { + const _citedUrls = Array.from(document.querySelectorAll('[cite]')) + .map((el) => el.getAttribute('cite')) + .filter((url): url is string => !!url && url.startsWith('http')); + + const annotations = await sendMessage('getAnnotations', { url: window.location.href }); + + sendMessage('updateBadge', { count: annotations?.length || 0 }); + + if (annotations) { + sendMessage('cacheAnnotations', { url: window.location.href, annotations }); + } + + if (annotations && annotations.length > 0) { + renderBadges(annotations); + } else if (retryCount < 3) { + setTimeout(() => fetchAnnotations(retryCount + 1), 1000 * (retryCount + 1)); + } + } catch (error) { + console.error('Failed to fetch annotations:', error); + if (retryCount < 3) { + setTimeout(() => fetchAnnotations(retryCount + 1), 1000 * (retryCount + 1)); + } + } + } + + function renderBadges(annotations: Annotation[]) { + if (!shadowRoot) return; + + activeItems = []; + const rangesByColor: Record = {}; + + if (!cachedMatcher) { + cachedMatcher = new DOMTextMatcher(); + } + const matcher = cachedMatcher; + + annotations.forEach((item) => { + const selector = item.target?.selector || item.selector; + if (!selector?.exact) return; + + const range = matcher.findRange(selector.exact); + if (range) { + activeItems.push({ range, item }); + + const isHighlight = (item as any).type === 'Highlight'; + const defaultColor = isHighlight ? '#f59e0b' : '#6366f1'; + const color = item.color || defaultColor; + if (!rangesByColor[color]) rangesByColor[color] = []; + rangesByColor[color].push(range); + } + }); + + if (typeof CSS !== 'undefined' && CSS.highlights) { + CSS.highlights.clear(); + for (const [color, ranges] of Object.entries(rangesByColor)) { + const highlight = new Highlight(...ranges); + const safeColor = color.replace(/[^a-zA-Z0-9]/g, ''); + const name = `margin-hl-${safeColor}`; + CSS.highlights.set(name, highlight); + injectHighlightStyle(name, color); + } + } + } + + function injectHighlightStyle(name: string, color: string) { + if (injectedStyles.has(name)) return; + const style = document.createElement('style'); + style.textContent = ` + ::highlight(${name}) { + text-decoration: underline; + text-decoration-color: ${color}; + text-decoration-thickness: 2px; + text-underline-offset: 2px; + cursor: pointer; + } + `; + document.head.appendChild(style); + injectedStyles.add(name); + } + + function handleMouseMove(e: MouseEvent) { + if (!overlayEnabled || !overlayHost) return; + + const x = e.clientX; + const y = e.clientY; + + const foundItems: Array<{ range: Range; item: Annotation; rect: DOMRect }> = []; + let firstRange: Range | null = null; + + for (const { range, item } of activeItems) { + const rects = range.getClientRects(); + for (const rect of rects) { + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + let container: Node | null = range.commonAncestorContainer; + if (container.nodeType === Node.TEXT_NODE) { + container = container.parentNode; + } + + if ( + container && + ((e.target as Node).contains(container) || container.contains(e.target as Node)) + ) { + if (!firstRange) firstRange = range; + if (!foundItems.some((f) => f.item === item)) { + foundItems.push({ range, item, rect }); + } + } + break; + } + } + } + + if (foundItems.length > 0 && shadowRoot) { + document.body.style.cursor = 'pointer'; + + if (!hoverIndicator) { + const container = shadowRoot.getElementById('margin-overlay-container'); + if (container) { + hoverIndicator = document.createElement('div'); + hoverIndicator.className = 'margin-hover-indicator'; + container.appendChild(hoverIndicator); + } + } + + if (hoverIndicator && firstRange) { + const authorsMap = new Map(); + foundItems.forEach(({ item }) => { + const author = item.author || item.creator || {}; + const id = author.did || author.handle || 'unknown'; + if (!authorsMap.has(id)) { + authorsMap.set(id, author); + } + }); + + const uniqueAuthors = Array.from(authorsMap.values()); + const maxShow = 3; + const displayAuthors = uniqueAuthors.slice(0, maxShow); + const overflow = uniqueAuthors.length - maxShow; + + let html = displayAuthors + .map((author, i) => { + const avatar = author.avatar; + const handle = author.handle || 'U'; + const marginLeft = i === 0 ? '0' : '-8px'; + + if (avatar) { + return ``; + } else { + return `
${handle[0]?.toUpperCase() || 'U'}
`; + } + }) + .join(''); + + if (overflow > 0) { + html += `
+${overflow}
`; + } + + hoverIndicator.innerHTML = html; + + const firstRect = firstRange.getClientRects()[0]; + const totalWidth = + Math.min(uniqueAuthors.length, maxShow + (overflow > 0 ? 1 : 0)) * 18 + 8; + const leftPos = firstRect.left - totalWidth; + const topPos = firstRect.top + firstRect.height / 2 - 12; + + hoverIndicator.style.left = `${leftPos}px`; + hoverIndicator.style.top = `${topPos}px`; + hoverIndicator.classList.add('visible'); + } + } else { + document.body.style.cursor = ''; + if (hoverIndicator) { + hoverIndicator.classList.remove('visible'); + } + } + } + + function handleDocumentClick(e: MouseEvent) { + if (!overlayEnabled || !overlayHost) return; + + const x = e.clientX; + const y = e.clientY; + + if (popoverEl) { + const rect = popoverEl.getBoundingClientRect(); + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + return; + } + } + + if (composeModal) { + const rect = composeModal.getBoundingClientRect(); + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + return; + } + composeModal.remove(); + composeModal = null; + } + + const clickedItems: Annotation[] = []; + for (const { range, item } of activeItems) { + const rects = range.getClientRects(); + for (const rect of rects) { + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + let container: Node | null = range.commonAncestorContainer; + if (container.nodeType === Node.TEXT_NODE) { + container = container.parentNode; + } + + if ( + container && + ((e.target as Node).contains(container) || container.contains(e.target as Node)) + ) { + if (!clickedItems.includes(item)) { + clickedItems.push(item); + } + } + break; + } + } + } + + if (clickedItems.length > 0) { + e.preventDefault(); + e.stopPropagation(); + + if (popoverEl) { + const currentIds = popoverEl.dataset.itemIds; + const newIds = clickedItems + .map((i) => i.uri || i.id) + .sort() + .join(','); + if (currentIds === newIds) { + popoverEl.remove(); + popoverEl = null; + return; + } + } + + const firstItem = clickedItems[0]; + const match = activeItems.find((x) => x.item === firstItem); + if (match) { + const rects = match.range.getClientRects(); + if (rects.length > 0) { + const rect = rects[0]; + const top = rect.top + window.scrollY; + const left = rect.left + window.scrollX; + showPopover(clickedItems, top, left); + } + } + } else { + if (popoverEl) { + popoverEl.remove(); + popoverEl = null; + } + } + } + + function showPopover(items: Annotation[], top: number, left: number) { + if (!shadowRoot) return; + if (popoverEl) popoverEl.remove(); + + const container = shadowRoot.getElementById('margin-overlay-container'); + if (!container) return; + + popoverEl = document.createElement('div'); + popoverEl.className = 'margin-popover'; + + const ids = items + .map((i) => i.uri || i.id) + .sort() + .join(','); + popoverEl.dataset.itemIds = ids; + + const popWidth = 320; + const screenWidth = window.innerWidth; + let finalLeft = left; + if (left + popWidth > screenWidth) finalLeft = screenWidth - popWidth - 20; + if (finalLeft < 10) finalLeft = 10; + + popoverEl.style.top = `${top + 24}px`; + popoverEl.style.left = `${finalLeft}px`; + + const count = items.length; + const title = count === 1 ? 'Annotation' : `Annotations`; + + const contentHtml = items + .map((item) => { + const author = item.author || item.creator || {}; + const handle = author.handle || 'User'; + const avatar = author.avatar; + const text = item.body?.value || item.text || ''; + const id = item.id || item.uri; + const isHighlight = (item as any).type === 'Highlight'; + const createdAt = item.createdAt ? formatRelativeTime(item.createdAt) : ''; + + let avatarHtml = `
${handle[0]?.toUpperCase() || 'U'}
`; + if (avatar) { + avatarHtml = ``; + } + + let bodyHtml = ''; + if (isHighlight && !text) { + bodyHtml = `
${Icons.highlightMarker} Highlighted
`; + } else { + bodyHtml = `
${escapeHtml(text)}
`; + } + + return ` +
+
+ ${avatarHtml} +
+ @${handle} + ${createdAt ? `${createdAt}` : ''} +
+
+ ${bodyHtml} +
+ ${!isHighlight ? `` : ''} + +
+
+ `; + }) + .join(''); + + popoverEl.innerHTML = ` +
+ ${title} ${count} + +
+
+ ${contentHtml} +
+ `; + + popoverEl.querySelector('.popover-close')?.addEventListener('click', (e) => { + e.stopPropagation(); + popoverEl?.remove(); + popoverEl = null; + }); + + popoverEl.querySelectorAll('.btn-reply').forEach((btn) => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + const id = (btn as HTMLElement).getAttribute('data-id'); + if (id) { + window.open(`${APP_URL}/annotation/${encodeURIComponent(id)}`, '_blank'); + } + }); + }); + + popoverEl.querySelectorAll('.btn-share').forEach((btn) => { + btn.addEventListener('click', async (e) => { + e.stopPropagation(); + const id = (btn as HTMLElement).getAttribute('data-id'); + const text = (btn as HTMLElement).getAttribute('data-text'); + const url = `${APP_URL}/annotation/${encodeURIComponent(id || '')}`; + const shareText = text ? `${text}\n${url}` : url; + + try { + await navigator.clipboard.writeText(shareText); + const originalHtml = btn.innerHTML; + btn.innerHTML = `${Icons.check} Copied!`; + setTimeout(() => (btn.innerHTML = originalHtml), 2000); + } catch (err) { + console.error('Failed to copy', err); + } + }); + }); + + container.appendChild(popoverEl); + } + + function formatRelativeTime(dateStr: string): string { + const date = new Date(dateStr); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / 60000); + const diffHours = Math.floor(diffMs / 3600000); + const diffDays = Math.floor(diffMs / 86400000); + + if (diffMins < 1) return 'just now'; + if (diffMins < 60) return `${diffMins}m`; + if (diffHours < 24) return `${diffHours}h`; + if (diffDays < 7) return `${diffDays}d`; + return date.toLocaleDateString(); + } + + function escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } + + let lastUrl = window.location.href; + function checkUrlChange() { + if (window.location.href !== lastUrl) { + lastUrl = window.location.href; + onUrlChange(); + } + } + + function onUrlChange() { + if (typeof CSS !== 'undefined' && CSS.highlights) { + CSS.highlights.clear(); + } + activeItems = []; + sendMessage('updateBadge', { count: 0 }); + if (overlayEnabled) { + fetchAnnotations(); + } + } + + window.addEventListener('popstate', onUrlChange); + + const originalPushState = history.pushState; + const originalReplaceState = history.replaceState; + + history.pushState = function (...args) { + originalPushState.apply(this, args); + checkUrlChange(); + }; + + history.replaceState = function (...args) { + originalReplaceState.apply(this, args); + checkUrlChange(); + }; + + setInterval(checkUrlChange, 1000); + + window.addEventListener('load', () => { + setTimeout(() => fetchAnnotations(), 500); + }); + }, +}); diff --git a/extension/src/entrypoints/popup/index.html b/extension/src/entrypoints/popup/index.html new file mode 100644 index 0000000..fae92b6 --- /dev/null +++ b/extension/src/entrypoints/popup/index.html @@ -0,0 +1,12 @@ + + + + + + Margin + + +
+ + + diff --git a/extension/src/entrypoints/popup/main.tsx b/extension/src/entrypoints/popup/main.tsx new file mode 100644 index 0000000..1cd0d70 --- /dev/null +++ b/extension/src/entrypoints/popup/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from '@/components/popup/App'; +import '@/assets/styles.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); diff --git a/extension/src/entrypoints/sidepanel/index.html b/extension/src/entrypoints/sidepanel/index.html new file mode 100644 index 0000000..cfd9609 --- /dev/null +++ b/extension/src/entrypoints/sidepanel/index.html @@ -0,0 +1,13 @@ + + + + + + Margin + + + +
+ + + diff --git a/extension/src/entrypoints/sidepanel/main.tsx b/extension/src/entrypoints/sidepanel/main.tsx new file mode 100644 index 0000000..b2f0cb5 --- /dev/null +++ b/extension/src/entrypoints/sidepanel/main.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client'; +import App from '@/components/sidepanel/App'; +import '@/assets/styles.css'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + +); diff --git a/extension/src/utils/api.ts b/extension/src/utils/api.ts new file mode 100644 index 0000000..c790ee3 --- /dev/null +++ b/extension/src/utils/api.ts @@ -0,0 +1,304 @@ +import type { MarginSession, TextSelector } from './types'; +import { apiUrlItem } from './storage'; + +async function getApiUrl(): Promise { + return await apiUrlItem.getValue(); +} + +async function getSessionCookie(): Promise { + try { + const apiUrl = await getApiUrl(); + const cookie = await browser.cookies.get({ + url: apiUrl, + name: 'margin_session', + }); + return cookie?.value || null; + } catch (error) { + console.error('Get cookie error:', error); + return null; + } +} + +export async function checkSession(): Promise { + try { + const apiUrl = await getApiUrl(); + const cookie = await getSessionCookie(); + + if (!cookie) { + return { authenticated: false }; + } + + const res = await fetch(`${apiUrl}/auth/session`, { + headers: { + 'X-Session-Token': cookie, + }, + }); + + if (!res.ok) { + return { authenticated: false }; + } + + const sessionData = await res.json(); + + if (!sessionData.did || !sessionData.handle) { + return { authenticated: false }; + } + + return { + authenticated: true, + did: sessionData.did, + handle: sessionData.handle, + accessJwt: sessionData.accessJwt, + refreshJwt: sessionData.refreshJwt, + }; + } catch (error) { + console.error('Session check error:', error); + return { authenticated: false }; + } +} + +async function apiRequest(path: string, options: RequestInit = {}): Promise { + const apiUrl = await getApiUrl(); + const cookie = await getSessionCookie(); + + const headers: Record = { + 'Content-Type': 'application/json', + ...(options.headers as Record), + }; + + if (cookie) { + headers['X-Session-Token'] = cookie; + } + + const apiPath = path.startsWith('/api') ? path : `/api${path}`; + + const response = await fetch(`${apiUrl}${apiPath}`, { + ...options, + headers, + credentials: 'include', + }); + + return response; +} + +export async function getAnnotations(url: string, citedUrls: string[] = []) { + try { + const apiUrl = await getApiUrl(); + const uniqueUrls = [...new Set([url, ...citedUrls])]; + + const fetchPromises = uniqueUrls.map(async (u) => { + try { + const res = await fetch(`${apiUrl}/api/targets?source=${encodeURIComponent(u)}`); + if (!res.ok) return { annotations: [], highlights: [], bookmarks: [] }; + return await res.json(); + } catch { + return { annotations: [], highlights: [], bookmarks: [] }; + } + }); + + const results = await Promise.all(fetchPromises); + const allItems: any[] = []; + const seenIds = new Set(); + + results.forEach((data) => { + const items = [ + ...(data.annotations || []), + ...(data.highlights || []), + ...(data.bookmarks || []), + ]; + items.forEach((item: any) => { + const id = item.uri || item.id; + if (id && !seenIds.has(id)) { + seenIds.add(id); + allItems.push(item); + } + }); + }); + + return allItems; + } catch (error) { + console.error('Get annotations error:', error); + return []; + } +} + +export async function createAnnotation(data: { + url: string; + text: string; + title?: string; + selector?: TextSelector; +}) { + try { + const res = await apiRequest('/annotations', { + method: 'POST', + body: JSON.stringify({ + target: { + source: data.url, + selector: data.selector, + }, + body: { type: 'TextualBody', value: data.text, format: 'text/plain' }, + motivation: 'commenting', + title: data.title, + }), + }); + + if (!res.ok) { + const error = await res.text(); + return { success: false, error }; + } + + return { success: true, data: await res.json() }; + } catch (error) { + return { success: false, error: String(error) }; + } +} + +export async function createBookmark(data: { url: string; title?: string }) { + try { + const res = await apiRequest('/bookmarks', { + method: 'POST', + body: JSON.stringify({ url: data.url, title: data.title }), + }); + + if (!res.ok) { + const error = await res.text(); + return { success: false, error }; + } + + return { success: true, data: await res.json() }; + } catch (error) { + return { success: false, error: String(error) }; + } +} + +export async function createHighlight(data: { + url: string; + title?: string; + selector: TextSelector; + color?: string; +}) { + try { + const res = await apiRequest('/highlights', { + method: 'POST', + body: JSON.stringify({ + url: data.url, + title: data.title, + selector: data.selector, + color: data.color, + }), + }); + + if (!res.ok) { + const error = await res.text(); + return { success: false, error }; + } + + return { success: true, data: await res.json() }; + } catch (error) { + return { success: false, error: String(error) }; + } +} + +export async function getUserBookmarks(did: string) { + try { + const res = await apiRequest(`/users/${did}/bookmarks`); + if (!res.ok) return []; + const data = await res.json(); + return data.items || data || []; + } catch (error) { + console.error('Get bookmarks error:', error); + return []; + } +} + +export async function getUserHighlights(did: string) { + try { + const res = await apiRequest(`/users/${did}/highlights`); + if (!res.ok) return []; + const data = await res.json(); + return data.items || data || []; + } catch (error) { + console.error('Get highlights error:', error); + return []; + } +} + +export async function getUserCollections(did: string) { + try { + const res = await apiRequest(`/collections?author=${encodeURIComponent(did)}`); + if (!res.ok) return []; + const data = await res.json(); + return data.items || data || []; + } catch (error) { + console.error('Get collections error:', error); + return []; + } +} + +export async function addToCollection(collectionUri: string, annotationUri: string) { + try { + const res = await apiRequest(`/collections/${encodeURIComponent(collectionUri)}/items`, { + method: 'POST', + body: JSON.stringify({ annotationUri, position: 0 }), + }); + + if (!res.ok) { + const error = await res.text(); + return { success: false, error }; + } + + return { success: true }; + } catch (error) { + return { success: false, error: String(error) }; + } +} + +export async function getItemCollections(annotationUri: string): Promise { + try { + const res = await apiRequest( + `/collections/containing?uri=${encodeURIComponent(annotationUri)}` + ); + if (!res.ok) return []; + const data = await res.json(); + return Array.isArray(data) ? data : []; + } catch (error) { + console.error('Get item collections error:', error); + return []; + } +} + +export async function getReplies(uri: string) { + try { + const res = await apiRequest(`/annotations/${encodeURIComponent(uri)}/replies`); + if (!res.ok) return []; + const data = await res.json(); + return data.items || data || []; + } catch (error) { + console.error('Get replies error:', error); + return []; + } +} + +export async function createReply(data: { + parentUri: string; + parentCid: string; + rootUri: string; + rootCid: string; + text: string; +}) { + try { + const res = await apiRequest('/replies', { + method: 'POST', + body: JSON.stringify(data), + }); + + if (!res.ok) { + const error = await res.text(); + return { success: false, error }; + } + + return { success: true }; + } catch (error) { + return { success: false, error: String(error) }; + } +} diff --git a/extension/src/utils/messaging.ts b/extension/src/utils/messaging.ts new file mode 100644 index 0000000..7f3b41e --- /dev/null +++ b/extension/src/utils/messaging.ts @@ -0,0 +1,61 @@ +import { defineExtensionMessaging } from '@webext-core/messaging'; +import type { + MarginSession, + Annotation, + Bookmark, + Highlight, + Collection, + TextSelector, +} from './types'; + +interface ProtocolMap { + checkSession(): MarginSession; + + getAnnotations(data: { url: string }): Annotation[]; + createAnnotation(data: { url: string; text: string; title?: string; selector?: TextSelector }): { + success: boolean; + data?: Annotation; + error?: string; + }; + + createBookmark(data: { url: string; title?: string }): { + success: boolean; + data?: Bookmark; + error?: string; + }; + getUserBookmarks(data: { did: string }): Bookmark[]; + + createHighlight(data: { url: string; title?: string; selector: TextSelector; color?: string }): { + success: boolean; + data?: Highlight; + error?: string; + }; + getUserHighlights(data: { did: string }): Highlight[]; + + getUserCollections(data: { did: string }): Collection[]; + addToCollection(data: { collectionUri: string; annotationUri: string }): { + success: boolean; + error?: string; + }; + getItemCollections(data: { annotationUri: string }): string[]; + + getReplies(data: { uri: string }): Annotation[]; + createReply(data: { + parentUri: string; + parentCid: string; + rootUri: string; + rootCid: string; + text: string; + }): { success: boolean; error?: string }; + + getOverlayEnabled(): boolean; + + openAppUrl(data: { path: string }): void; + + updateBadge(data: { count: number; tabId?: number }): void; + + cacheAnnotations(data: { url: string; annotations: Annotation[] }): void; + getCachedAnnotations(data: { url: string }): Annotation[] | null; +} + +export const { sendMessage, onMessage } = defineExtensionMessaging(); diff --git a/extension/src/utils/overlay-styles.ts b/extension/src/utils/overlay-styles.ts new file mode 100644 index 0000000..ec6fbe6 --- /dev/null +++ b/extension/src/utils/overlay-styles.ts @@ -0,0 +1,576 @@ +export const overlayStyles = /* css */ ` +:host { + all: initial; + --bg-primary: #0a0a0d; + --bg-secondary: #121216; + --bg-tertiary: #1a1a1f; + --bg-card: #0f0f13; + --bg-elevated: #18181d; + --bg-hover: #1e1e24; + + --text-primary: #eaeaee; + --text-secondary: #b7b6c5; + --text-tertiary: #6e6d7a; + --border: rgba(183, 182, 197, 0.12); + + --accent: #957a86; + --accent-hover: #a98d98; + --accent-subtle: rgba(149, 122, 134, 0.15); + + --highlight-yellow: #fbbf24; + --highlight-green: #34d399; + --highlight-blue: #60a5fa; + --highlight-pink: #f472b6; + --highlight-purple: #a78bfa; +} + +:host(.light) { + --bg-primary: #f8f8fa; + --bg-secondary: #ffffff; + --bg-tertiary: #f0f0f4; + --bg-card: #ffffff; + --bg-elevated: #ffffff; + --bg-hover: #eeeef2; + + --text-primary: #18171c; + --text-secondary: #5c495a; + --text-tertiary: #8a8494; + --border: rgba(92, 73, 90, 0.12); + + --accent: #7a5f6d; + --accent-hover: #664e5b; + --accent-subtle: rgba(149, 122, 134, 0.12); +} + +.margin-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; +} + +.margin-selection-toolbar { + position: fixed; + display: flex; + align-items: center; + gap: 2px; + padding: 4px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 10px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25), 0 0 0 1px rgba(255,255,255,0.05); + z-index: 2147483647; + pointer-events: auto; + font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; + opacity: 0; + transform: translateY(8px) scale(0.95); + animation: toolbar-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; +} + +@keyframes toolbar-in { + to { opacity: 1; transform: translateY(0) scale(1); } +} + +.toolbar-btn { + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + padding: 8px 12px; + background: transparent; + border: none; + border-radius: 6px; + color: var(--text-primary); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: all 0.15s ease; + white-space: nowrap; +} + +.toolbar-btn:hover { + background: var(--bg-hover); +} + +.toolbar-btn:active { + transform: scale(0.96); +} + +.toolbar-btn svg { + width: 16px; + height: 16px; + flex-shrink: 0; +} + +.toolbar-btn.highlight-btn { + color: var(--highlight-yellow); +} + +.toolbar-btn.highlight-btn:hover { + background: rgba(251, 191, 36, 0.15); +} + +.toolbar-divider { + width: 1px; + height: 20px; + background: var(--border); + margin: 0 2px; +} + +.color-picker { + position: absolute; + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: 6px; + display: flex; + gap: 6px; + padding: 8px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 10px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25); + animation: toolbar-in 0.15s ease forwards; +} + +.color-dot { + width: 24px; + height: 24px; + border-radius: 50%; + border: 2px solid transparent; + cursor: pointer; + transition: all 0.15s ease; +} + +.color-dot:hover { + transform: scale(1.15); + border-color: var(--text-primary); +} + +.margin-popover { + position: absolute; + width: 320px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 14px; + padding: 0; + box-shadow: 0 8px 40px rgba(0, 0, 0, 0.35), 0 0 0 1px rgba(255,255,255,0.05); + display: flex; + flex-direction: column; + pointer-events: auto; + z-index: 2147483647; + font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; + color: var(--text-primary); + opacity: 0; + transform: translateY(-8px) scale(0.96); + animation: popover-in 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; + max-height: 450px; + overflow: hidden; +} + +@keyframes popover-in { + to { opacity: 1; transform: translateY(0) scale(1); } +} + +.popover-header { + padding: 12px 16px; + border-bottom: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; + background: var(--bg-primary); + border-radius: 14px 14px 0 0; +} + +.popover-title { + font-weight: 600; + font-size: 13px; + color: var(--text-primary); + display: flex; + align-items: center; + gap: 6px; +} + +.popover-count { + font-size: 11px; + color: var(--text-tertiary); + background: var(--bg-tertiary); + padding: 2px 8px; + border-radius: 10px; +} + +.popover-close { + background: none; + border: none; + color: var(--text-tertiary); + cursor: pointer; + padding: 4px; + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.15s; +} + +.popover-close:hover { + background: var(--bg-hover); + color: var(--text-primary); +} + +.popover-close svg { + width: 16px; + height: 16px; +} + +.popover-scroll-area { + overflow-y: auto; + max-height: 350px; + overscroll-behavior: contain; + scrollbar-width: thin; + scrollbar-color: var(--bg-tertiary) transparent; +} + +.popover-scroll-area::-webkit-scrollbar { + width: 6px; +} + +.popover-scroll-area::-webkit-scrollbar-track { + background: transparent; + margin: 4px 0; +} + +.popover-scroll-area::-webkit-scrollbar-thumb { + background: var(--bg-tertiary); + border-radius: 3px; +} + +.popover-scroll-area::-webkit-scrollbar-thumb:hover { + background: var(--text-tertiary); +} + +.comment-item { + padding: 14px 16px; + border-bottom: 1px solid var(--border); + transition: background 0.15s; +} + +.comment-item:hover { + background: var(--bg-hover); +} + +.comment-item:last-child { + border-bottom: none; +} + +.comment-header { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 8px; +} + +.comment-avatar { + width: 28px; + height: 28px; + border-radius: 50%; + background: linear-gradient(135deg, var(--accent), var(--accent-hover)); + display: flex; + align-items: center; + justify-content: center; + font-size: 11px; + font-weight: 600; + color: white; + flex-shrink: 0; +} + +.comment-meta { + flex: 1; + min-width: 0; +} + +.comment-handle { + font-size: 13px; + font-weight: 600; + color: var(--text-primary); +} + +.comment-time { + font-size: 11px; + color: var(--text-tertiary); +} + +.comment-text { + font-size: 13px; + line-height: 1.55; + color: var(--text-primary); +} + +.highlight-badge { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 11px; + color: var(--text-tertiary); + background: var(--bg-tertiary); + padding: 4px 10px; + border-radius: 12px; + font-weight: 500; +} + +.highlight-badge svg { + width: 12px; + height: 12px; +} + +.comment-actions { + display: flex; + gap: 4px; + margin-top: 10px; + padding-top: 10px; + border-top: 1px solid var(--border); +} + +.comment-action-btn { + background: none; + border: none; + padding: 6px 10px; + color: var(--text-tertiary); + font-size: 12px; + font-weight: 500; + cursor: pointer; + border-radius: 6px; + transition: all 0.15s; + display: flex; + align-items: center; + gap: 5px; +} + +.comment-action-btn svg { + width: 14px; + height: 14px; +} + +.comment-action-btn:hover { + background: var(--bg-tertiary); + color: var(--text-primary); +} + +.inline-compose-modal { + position: fixed; + width: 380px; + max-width: calc(100vw - 32px); + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 16px; + padding: 0; + box-sizing: border-box; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255,255,255,0.05); + z-index: 2147483647; + pointer-events: auto; + font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; + color: var(--text-primary); + animation: modal-in 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; + overflow: hidden; +} + +@keyframes modal-in { + from { opacity: 0; transform: scale(0.95) translateY(10px); } + to { opacity: 1; transform: scale(1) translateY(0); } +} + +.inline-compose-modal * { + box-sizing: border-box; +} + +.compose-header { + padding: 14px 16px; + border-bottom: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; + background: var(--bg-primary); +} + +.compose-title { + font-weight: 600; + font-size: 14px; + color: var(--text-primary); +} + +.compose-close { + background: none; + border: none; + color: var(--text-tertiary); + cursor: pointer; + padding: 4px; + border-radius: 6px; + display: flex; + transition: all 0.15s; +} + +.compose-close:hover { + background: var(--bg-hover); + color: var(--text-primary); +} + +.compose-body { + padding: 16px; +} + +.inline-compose-quote { + padding: 12px 14px; + background: var(--accent-subtle); + border-left: 3px solid var(--accent); + border-radius: 0 8px 8px 0; + font-size: 13px; + color: var(--text-secondary); + font-style: italic; + margin-bottom: 14px; + max-height: 80px; + overflow: hidden; + word-break: break-word; + line-height: 1.5; +} + +.inline-compose-textarea { + width: 100%; + min-height: 100px; + padding: 12px 14px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: 10px; + color: var(--text-primary); + font-family: inherit; + font-size: 14px; + line-height: 1.5; + resize: none; + box-sizing: border-box; + transition: border-color 0.15s; +} + +.inline-compose-textarea::placeholder { + color: var(--text-tertiary); +} + +.inline-compose-textarea:focus { + outline: none; + border-color: var(--accent); +} + +.compose-footer { + padding: 12px 16px; + border-top: 1px solid var(--border); + display: flex; + justify-content: flex-end; + gap: 8px; + background: var(--bg-primary); +} + +.btn-cancel { + padding: 9px 18px; + background: transparent; + border: 1px solid var(--border); + border-radius: 8px; + color: var(--text-secondary); + font-size: 13px; + font-weight: 500; + cursor: pointer; + transition: all 0.15s; +} + +.btn-cancel:hover { + background: var(--bg-hover); + color: var(--text-primary); + border-color: var(--border); +} + +.btn-submit { + padding: 9px 20px; + background: var(--accent); + border: none; + border-radius: 8px; + color: white; + font-size: 13px; + font-weight: 600; + cursor: pointer; + transition: all 0.15s; +} + +.btn-submit:hover { + background: var(--accent-hover); + transform: translateY(-1px); +} + +.btn-submit:active { + transform: translateY(0); +} + +.btn-submit:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; +} + +.margin-hover-indicator { + position: fixed; + display: flex; + align-items: center; + pointer-events: none; + z-index: 2147483647; + opacity: 0; + transition: opacity 0.2s ease, transform 0.2s ease; + transform: scale(0.8) translateX(4px); +} + +.margin-hover-indicator.visible { + opacity: 1; + transform: scale(1) translateX(0); +} + +.margin-toast { + position: fixed; + bottom: 24px; + left: 50%; + transform: translateX(-50%) translateY(20px); + padding: 12px 20px; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 10px; + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3); + font-family: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, sans-serif; + font-size: 13px; + font-weight: 500; + color: var(--text-primary); + z-index: 2147483647; + pointer-events: auto; + display: flex; + align-items: center; + gap: 10px; + opacity: 0; + animation: toast-in 0.3s ease forwards; +} + +@keyframes toast-in { + to { opacity: 1; transform: translateX(-50%) translateY(0); } +} + +.margin-toast.toast-out { + animation: toast-out 0.2s ease forwards; +} + +@keyframes toast-out { + to { opacity: 0; transform: translateX(-50%) translateY(10px); } +} + +.toast-icon { + width: 18px; + height: 18px; + color: var(--accent); +} + +.toast-success .toast-icon { + color: #34d399; +} +`; diff --git a/extension/src/utils/storage.ts b/extension/src/utils/storage.ts new file mode 100644 index 0000000..e1c2dc9 --- /dev/null +++ b/extension/src/utils/storage.ts @@ -0,0 +1,11 @@ +export const apiUrlItem = storage.defineItem('local:apiUrl', { + fallback: 'https://margin.at', +}); + +export const overlayEnabledItem = storage.defineItem('local:overlayEnabled', { + fallback: true, +}); + +export const themeItem = storage.defineItem<'light' | 'dark' | 'system'>('local:theme', { + fallback: 'system', +}); diff --git a/extension/src/utils/text-matcher.ts b/extension/src/utils/text-matcher.ts new file mode 100644 index 0000000..f72b7a2 --- /dev/null +++ b/extension/src/utils/text-matcher.ts @@ -0,0 +1,183 @@ +interface TextNodeIndex { + start: number; + node: Text; + length: number; +} + +interface TextPoint { + node: Text; + offset: number; +} + +export class DOMTextMatcher { + private textNodes: Text[] = []; + private corpus = ''; + private indices: TextNodeIndex[] = []; + private built = false; + + constructor() {} + + private ensureBuilt(): void { + if (!this.built) { + this.buildMap(); + this.built = true; + } + } + + private buildMap(): void { + const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, { + acceptNode: (node: Text) => { + if (!node.parentNode) return NodeFilter.FILTER_REJECT; + const parent = node.parentNode as Element; + const tag = parent.tagName; + if (['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT'].includes(tag)) { + return NodeFilter.FILTER_REJECT; + } + if (!node.textContent?.trim()) return NodeFilter.FILTER_SKIP; + const htmlParent = parent as HTMLElement; + if ( + htmlParent.style && + (htmlParent.style.display === 'none' || htmlParent.style.visibility === 'hidden') + ) { + return NodeFilter.FILTER_REJECT; + } + return NodeFilter.FILTER_ACCEPT; + }, + }); + + let currentNode: Text | null; + let index = 0; + const parts: string[] = []; + + while ((currentNode = walker.nextNode() as Text | null)) { + const text = currentNode.textContent || ''; + this.textNodes.push(currentNode); + parts.push(text); + this.indices.push({ + start: index, + node: currentNode, + length: text.length, + }); + index += text.length; + } + + this.corpus = parts.join(''); + } + + findRange(searchText: string): Range | null { + if (!searchText) return null; + + this.ensureBuilt(); + + let matchIndex = this.corpus.indexOf(searchText); + + if (matchIndex === -1) { + const normalizedSearch = searchText.replace(/\s+/g, ' ').trim(); + matchIndex = this.corpus.indexOf(normalizedSearch); + + if (matchIndex === -1) { + const fuzzyMatch = this.fuzzyFindInCorpus(searchText); + if (fuzzyMatch) { + const start = this.mapIndexToPoint(fuzzyMatch.start); + const end = this.mapIndexToPoint(fuzzyMatch.end); + if (start && end) { + const range = document.createRange(); + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + return range; + } + } + return null; + } + } + + const start = this.mapIndexToPoint(matchIndex); + const end = this.mapIndexToPoint(matchIndex + searchText.length); + + if (start && end) { + const range = document.createRange(); + range.setStart(start.node, start.offset); + range.setEnd(end.node, end.offset); + return range; + } + return null; + } + + private fuzzyFindInCorpus(searchText: string): { start: number; end: number } | null { + const searchWords = searchText + .trim() + .split(/\s+/) + .filter((w) => w.length > 0); + if (searchWords.length === 0) return null; + + const corpusLower = this.corpus.toLowerCase(); + const firstWord = searchWords[0].toLowerCase(); + let searchStart = 0; + + while (searchStart < corpusLower.length) { + const wordStart = corpusLower.indexOf(firstWord, searchStart); + if (wordStart === -1) break; + + let corpusPos = wordStart; + let matched = true; + let lastMatchEnd = wordStart; + + for (const word of searchWords) { + const wordLower = word.toLowerCase(); + while (corpusPos < corpusLower.length && /\s/.test(this.corpus[corpusPos])) { + corpusPos++; + } + const corpusSlice = corpusLower.slice(corpusPos, corpusPos + wordLower.length); + if (corpusSlice !== wordLower) { + matched = false; + break; + } + corpusPos += wordLower.length; + lastMatchEnd = corpusPos; + } + + if (matched) { + return { start: wordStart, end: lastMatchEnd }; + } + searchStart = wordStart + 1; + } + + return null; + } + + private mapIndexToPoint(corpusIndex: number): TextPoint | null { + for (const info of this.indices) { + if (corpusIndex >= info.start && corpusIndex < info.start + info.length) { + return { node: info.node, offset: corpusIndex - info.start }; + } + } + if (this.indices.length > 0) { + const last = this.indices[this.indices.length - 1]; + if (corpusIndex === last.start + last.length) { + return { node: last.node, offset: last.length }; + } + } + return null; + } +} + +export function findCanonicalUrl(range: Range): string | null { + let node: Node | null = range.commonAncestorContainer; + if (node.nodeType === Node.TEXT_NODE) { + node = node.parentNode; + } + + while (node && node !== document.body) { + const element = node as Element; + if ( + (element.tagName === 'BLOCKQUOTE' || element.tagName === 'Q') && + element.hasAttribute('cite') + ) { + if (element.contains(range.commonAncestorContainer)) { + return element.getAttribute('cite'); + } + } + node = node.parentNode; + } + return null; +} diff --git a/extension/src/utils/types.ts b/extension/src/utils/types.ts new file mode 100644 index 0000000..3bcc3dc --- /dev/null +++ b/extension/src/utils/types.ts @@ -0,0 +1,76 @@ +export interface MarginSession { + authenticated: boolean; + did?: string; + handle?: string; + accessJwt?: string; + refreshJwt?: string; +} + +export interface TextSelector { + type?: string; + exact: string; + prefix?: string; + suffix?: string; +} + +export interface Annotation { + uri?: string; + id?: string; + cid?: string; + type?: 'Annotation' | 'Bookmark' | 'Highlight'; + body?: { value: string }; + text?: string; + target?: { + source?: string; + selector?: TextSelector; + }; + selector?: TextSelector; + color?: string; + created?: string; + createdAt?: string; + creator?: Author; + author?: Author; +} + +export interface Author { + did?: string; + handle?: string; + displayName?: string; + avatar?: string; +} + +export interface Bookmark { + uri?: string; + id?: string; + source?: string; + url?: string; + title?: string; + description?: string; + image?: string; + createdAt?: string; +} + +export interface Highlight { + uri?: string; + id?: string; + target?: { + source?: string; + selector?: TextSelector; + }; + color?: string; + title?: string; + createdAt?: string; +} + +export interface Collection { + uri?: string; + id?: string; + name: string; + description?: string; + icon?: string; + createdAt?: string; + itemCount?: number; +} + +export const DEFAULT_API_URL = 'https://margin.at'; +export const APP_URL = 'https://margin.at'; diff --git a/extension/tailwind.config.js b/extension/tailwind.config.js new file mode 100644 index 0000000..e6ee84a --- /dev/null +++ b/extension/tailwind.config.js @@ -0,0 +1,12 @@ +/** @type {import('tailwindcss').Config} */ +export default { + content: ['./src/**/*.{html,js,ts,jsx,tsx}'], + theme: { + extend: { + fontFamily: { + sans: ['IBM Plex Sans', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'], + }, + }, + }, + plugins: [], +}; diff --git a/extension/tsconfig.json b/extension/tsconfig.json new file mode 100644 index 0000000..6007f8c --- /dev/null +++ b/extension/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./.wxt/tsconfig.json", + "compilerOptions": { + "jsx": "react-jsx", + "jsxImportSource": "react", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*", ".wxt/wxt.d.ts"] +} diff --git a/extension/wxt.config.ts b/extension/wxt.config.ts new file mode 100644 index 0000000..202eb07 --- /dev/null +++ b/extension/wxt.config.ts @@ -0,0 +1,87 @@ +import { defineConfig } from 'wxt'; +import { cp } from 'fs/promises'; +import { existsSync } from 'fs'; +import { resolve } from 'path'; + +export default defineConfig({ + srcDir: 'src', + modules: ['@wxt-dev/module-react'], + manifestVersion: 3, + hooks: { + 'build:done': async (wxt) => { + const publicDir = resolve(__dirname, 'public'); + const outDir = wxt.config.outDir; + + if (existsSync(publicDir)) { + await cp(publicDir, outDir, { recursive: true }); + } + }, + }, + manifest: ({ browser }) => { + const basePermissions = ['storage', 'activeTab', 'tabs', 'cookies', 'contextMenus']; + const chromePermissions = [...basePermissions, 'sidePanel']; + + return { + name: 'Margin', + description: 'Annotate and highlight any webpage, with your notes saved to the decentralized AT Protocol.', + permissions: browser === 'firefox' ? basePermissions : chromePermissions, + host_permissions: ['https://margin.at/*', '*://*/*'], + icons: { + 16: '/icons/icon-16.png', + 32: '/icons/icon-32.png', + 48: '/icons/icon-48.png', + 128: '/icons/icon-128.png', + }, + commands: { + 'open-sidebar': { + suggested_key: { + default: 'Alt+M', + mac: 'Alt+M', + }, + description: 'Open Margin sidebar', + }, + 'annotate-selection': { + suggested_key: { + default: 'Alt+A', + mac: 'Alt+A', + }, + description: 'Annotate selected text', + }, + 'highlight-selection': { + suggested_key: { + default: 'Alt+H', + mac: 'Alt+H', + }, + description: 'Highlight selected text', + }, + 'bookmark-page': { + suggested_key: { + default: 'Alt+B', + mac: 'Alt+B', + }, + description: 'Bookmark current page', + }, + }, + action: { + default_title: 'Margin', + default_popup: 'popup.html', + default_icon: { + 16: '/icons/icon-16.png', + 32: '/icons/icon-32.png', + 48: '/icons/icon-48.png', + 128: '/icons/icon-128.png', + }, + }, + ...(browser === 'chrome' ? { + side_panel: { + default_path: 'sidepanel.html', + }, + } : { + sidebar_action: { + default_title: 'Margin', + default_panel: 'sidepanel.html', + }, + }), + }; + }, +});