/** @typedef {{ name: string; value: string; domain: string; path: string; expires: number; httpOnly: boolean; secure: boolean; sameSite: string }} PlaywrightCookie */ const COOKIE_DOMAINS = ["threads.com", "instagram.com", "facebook.com"]; function mapSameSite(sameSite) { if (sameSite === "no_restriction") return "None"; if (sameSite === "lax") return "Lax"; if (sameSite === "strict") return "Strict"; return "Lax"; } /** @param {chrome.cookies.Cookie} cookie */ function toPlaywrightCookie(cookie) { return { name: cookie.name, value: cookie.value, domain: cookie.domain, path: cookie.path || "/", expires: cookie.expirationDate ?? -1, httpOnly: cookie.httpOnly ?? false, secure: cookie.secure ?? false, sameSite: mapSameSite(cookie.sameSite), }; } export async function collectThreadsCookies() { /** @type {PlaywrightCookie[]} */ const merged = []; const seen = new Set(); for (const domain of COOKIE_DOMAINS) { const batch = await chrome.cookies.getAll({ domain }); for (const cookie of batch) { const key = `${cookie.domain}|${cookie.path}|${cookie.name}`; if (seen.has(key)) continue; seen.add(key); merged.push(toPlaywrightCookie(cookie)); } } return merged; } export async function collectThreadsLocalStorage() { const tabs = await chrome.tabs.query({ url: ["https://www.threads.com/*", "https://threads.com/*", "https://www.threads.net/*"], }); if (!tabs.length || tabs[0].id == null) { return []; } const [injection] = await chrome.scripting.executeScript({ target: { tabId: tabs[0].id }, func: () => { const localStorageItems = []; for (let i = 0; i < localStorage.length; i += 1) { const name = localStorage.key(i); if (!name) continue; localStorageItems.push({ name, value: localStorage.getItem(name) ?? "" }); } return { origin: location.origin, localStorage: localStorageItems }; }, }); const payload = injection?.result; if (!payload || !Array.isArray(payload.localStorage)) { return []; } return [payload]; } export async function buildStorageState() { const cookies = await collectThreadsCookies(); const origins = await collectThreadsLocalStorage(); if (!cookies.length) { throw new Error("找不到 Threads / Instagram cookies。請先在 Chrome 登入 threads.com"); } return JSON.stringify({ cookies, origins }); }