diff --git a/.output/chrome-mv3/background.js b/.output/chrome-mv3/background.js new file mode 100644 index 0000000..31af0ff --- /dev/null +++ b/.output/chrome-mv3/background.js @@ -0,0 +1 @@ +var background=(function(){"use strict";const t=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome;function i(r){return r==null||typeof r=="function"?{main:r}:r}const a=i(()=>{console.log("Claude Conversation Exporter background script loaded"),t.runtime.onInstalled.addListener(()=>{console.log("Claude Conversation Exporter installed"),(async()=>{try{const r=await t.tabs.query({url:"https://claude.ai/*"});for(const e of r)if(e.id)try{await t.scripting.executeScript({target:{tabId:e.id},files:["content-scripts/content.js"]})}catch(n){console.log("Could not inject into tab",e.id,n)}}catch(r){console.error("Error querying or injecting tabs:",r)}})()}),t.runtime.onMessage.addListener((r,e)=>r.action==="ensureContentScript"?(async()=>{try{const c=(await t.tabs.query({active:!0,currentWindow:!0}))[0];return c?.id?(await t.scripting.executeScript({target:{tabId:c.id},files:["content-scripts/content.js"]}),{success:!0}):{success:!1,error:"No active tab found"}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Unknown error"}}})():!1)});function d(){}function o(r,...e){}const u={debug:(...r)=>o(console.debug,...r),log:(...r)=>o(console.log,...r),warn:(...r)=>o(console.warn,...r),error:(...r)=>o(console.error,...r)};let s;try{s=a.main(),s instanceof Promise&&console.warn("The background's main() function return a promise, but it must be synchronous")}catch(r){throw u.error("The background crashed on startup!"),r}return s})(); diff --git a/.output/chrome-mv3/chunks/popup-BzajcGsb.js b/.output/chrome-mv3/chunks/popup-BzajcGsb.js new file mode 100644 index 0000000..0d1f308 --- /dev/null +++ b/.output/chrome-mv3/chunks/popup-BzajcGsb.js @@ -0,0 +1 @@ +(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))c(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&c(o)}).observe(document,{childList:!0,subtree:!0});function t(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function c(r){if(r.ep)return;r.ep=!0;const s=t(r);fetch(r.href,s)}})();try{}catch(n){console.error("[wxt] Failed to initialize plugins",n)}const p=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome,u=p;async function f(){return(await u.storage.sync.get(["organizationId"])).organizationId}async function g(){const e=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!e?.url)return null;const t=new URL(e.url);return/\/chat\/([a-f0-9-]+)/.exec(t.pathname)?.[1]??null}function l(n,e="info"){const t=document.getElementById("status");t&&(t.className=`status ${e}`,t.textContent=n,e==="success"&&setTimeout(()=>{t.textContent="",t.className=""},3e3))}function i(n){return document.getElementById(n)}async function w(){if(!await f()){const e=i("setupNotice");e&&(e.style.display="block");const t=i("exportCurrent"),c=i("exportAll");t&&(t.disabled=!0),c&&(c.disabled=!0)}}function h(){i("openOptions")?.addEventListener("click",e=>{e.preventDefault(),u.runtime.openOptionsPage()})}async function m(){const n=i("exportCurrent");if(n){n.disabled=!0,l("Fetching conversation...","info");try{const e=await f(),t=await g();if(!e)throw new Error("Organization ID not configured. Click the setup link above to configure it.");if(!t)throw new Error("Could not detect a conversation ID. Make sure you are on a Claude.ai conversation page.");const r=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!r?.url?.includes("claude.ai"))throw new Error("Please navigate to a Claude.ai conversation page first.");if(!r.id)throw new Error("Could not identify active tab.");const s=i("format"),o=i("includeMetadata");try{const a=await u.tabs.sendMessage(r.id,{action:"exportConversation",conversationId:t,orgId:e,format:s?.value??"json",includeMetadata:o?.checked??!0});if(a?.success)l("Conversation exported successfully!","success");else{const d=a?.error??"Export failed";console.error("Export failed:",d,a?.details),l(d,"error")}}catch(a){const d=a instanceof Error?a.message:String(a);throw d.includes("connection")||d.includes("Receiving end")?new Error("Cannot connect to page. Please ensure you are on a Claude.ai conversation page (https://claude.ai/chat/...) and refresh if needed."):a}}catch(e){const t=e instanceof Error?e.message:"Unknown error occurred";l(t,"error")}finally{n.disabled=!1}}}function b(){u.tabs.create({url:u.runtime.getURL("browse.html")})}async function v(){const n=i("exportAll");if(n){n.disabled=!0,l("Fetching all conversations...","info");try{const e=await f();if(!e)throw new Error("Organization ID not configured. Click the setup link above to configure it.");const c=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!c?.url?.includes("claude.ai"))throw new Error('Please navigate to a Claude.ai page first, or use "Browse All Conversations" instead.');if(!c.id)throw new Error("Could not identify active tab.");const r=i("format"),s=i("includeMetadata");try{const o=await u.tabs.sendMessage(c.id,{action:"exportAllConversations",orgId:e,format:r?.value??"json",includeMetadata:s?.checked??!0});if(o?.success)o.warnings?l(o.warnings,"info"):l(`Exported ${o.count??0} conversations!`,"success");else{const a=o?.error??"Export failed";console.error("Export failed:",a,o?.details),l(a,"error")}}catch(o){const a=o instanceof Error?o.message:String(o);throw a.includes("connection")||a.includes("Receiving end")?new Error('Cannot connect to page. This feature requires a Claude.ai page (https://claude.ai/chat/... or similar). Try "Browse All Conversations" instead - it works from any tab.'):o}}catch(e){const t=e instanceof Error?e.message:"Unknown error occurred";l(t,"error")}finally{n.disabled=!1}}}document.addEventListener("DOMContentLoaded",()=>{w(),h();const n=i("exportCurrent"),e=i("browseConversations"),t=i("exportAll");n?.addEventListener("click",()=>void m()),e?.addEventListener("click",b),t?.addEventListener("click",()=>void v())}); diff --git a/.output/chrome-mv3/content-scripts/content.js b/.output/chrome-mv3/content-scripts/content.js new file mode 100644 index 0000000..4fe5211 --- /dev/null +++ b/.output/chrome-mv3/content-scripts/content.js @@ -0,0 +1,27 @@ +var content=(function(){"use strict";const v=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome;function A(t){return t}const E=[{date:new Date("2024-01-01"),model:"claude-3-sonnet-20240229"},{date:new Date("2024-06-20"),model:"claude-3-5-sonnet-20240620"},{date:new Date("2024-10-22"),model:"claude-3-5-sonnet-20241022"},{date:new Date("2025-02-29"),model:"claude-3-7-sonnet-20250219"},{date:new Date("2025-05-14"),model:"claude-sonnet-4-20250514"},{date:new Date("2025-09-29"),model:"claude-sonnet-4-5-20250929"}];function g(t){if(t.model)return t.model;const n=new Date(t.created_at);for(let e=E.length-1;e>=0;e--){const r=E[e];if(r&&n>=r.date)return r.model}return E[0]?.model}function _(t){if(!t.chat_messages||!t.current_leaf_message_uuid)return[];const n=new Map;t.chat_messages.forEach(o=>{n.set(o.uuid,o)});const e=[];let r=t.current_leaf_message_uuid;for(;r&&n.has(r);){const o=n.get(r);if(!o||(e.unshift(o),r=o.parent_message_uuid,r&&!n.has(r)))break}return e}function C(t){let n="";if(t.content)for(const e of t.content)e.text&&(n+=e.text);else t.text&&(n=t.text);return n}function I(t,n){let e=`# ${t.name||"Untitled Conversation"} + +`;n&&(e+=`**Created:** ${new Date(t.created_at).toLocaleString()} +`,e+=`**Updated:** ${new Date(t.updated_at).toLocaleString()} +`,e+=`**Model:** ${g(t)} + +`,e+=`--- + +`);const r=_(t);for(const o of r){const i=o.sender==="human"?"**You**":"**Claude**";e+=`${i}: + +`;const s=C(o);s&&(e+=`${s} + +`),n&&o.created_at&&(e+=`*${new Date(o.created_at).toLocaleString()}* + +`),e+=`--- + +`}return e}function k(t,n){let e="";n&&(e+=`${t.name||"Untitled Conversation"} +`,e+=`Created: ${new Date(t.created_at).toLocaleString()} +`,e+=`Updated: ${new Date(t.updated_at).toLocaleString()} +`,e+=`Model: ${g(t)} + +`,e+=`--- + +`);const r=_(t);let o=!1,i=!1;for(const s of r){const c=C(s);let a;s.sender==="human"?(a=o?"H":"Human",o=!0):(a=i?"A":"Assistant",i=!0),e+=`${a}: ${c} + +`}return e.trim()}function S(t,n,e="application/json"){const r=new Blob([t],{type:e}),o=URL.createObjectURL(r),i=document.createElement("a");i.href=o,i.download=n,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(o)}function h(t,n,e){const r=t.replace(/[^a-z0-9]/gi,"_").toLowerCase().substring(0,50),o=n==="json"?"json":n==="markdown"?"md":"txt",i=e?`_${e.substring(0,8)}`:"";return`${r}${i}.${o}`}const M={matches:["https://claude.ai/*"],cssInjectionMode:"ui",main(){console.log("Claude Conversation Exporter content script loaded");async function t(o,i){const s=`https://claude.ai/api/organizations/${o}/chat_conversations/${i}?tree=True&rendering_mode=messages&render_all_tools=true`,c=await fetch(s,{credentials:"include",headers:{Accept:"application/json"}});if(!c.ok)throw new Error(`Failed to fetch conversation: ${c.status}`);return await c.json()}async function n(o){const i=`https://claude.ai/api/organizations/${o}/chat_conversations`,s=await fetch(i,{credentials:"include",headers:{Accept:"application/json"}});if(!s.ok)throw new Error(`Failed to fetch conversations: ${s.status}`);return await s.json()}async function e(o,i,s,c){console.log("Fetching conversation:",i);const a=await t(o,i);console.log("Conversation data fetched successfully:",a);const f=g(a);a.model=f;let l,d,u;switch(s){case"markdown":l=I(a,c),d=h(a.name||"untitled","markdown",a.uuid),u="text/markdown";break;case"text":l=k(a,c),d=h(a.name||"untitled","text",a.uuid),u="text/plain";break;default:l=JSON.stringify(a,null,2),d=h(a.name||"untitled","json",a.uuid),u="application/json"}console.log("Downloading file:",d),S(l,d,u)}async function r(o,i,s){const c=await n(o);if(console.log(`Fetched ${c.length} conversations`),i==="json"){const l=`claude-all-conversations-${new Date().toISOString().split("T")[0]??"export"}.json`;return console.log("Downloading all conversations as JSON:",l),S(JSON.stringify(c,null,2),l,"application/json"),{count:c.length}}let a=0;const f=[];for(const l of c)try{console.log(`Fetching full conversation ${a+1}/${c.length}: ${l.uuid}`);const d=await t(o,l.uuid);d.model=g(d);let u,x,T;i==="markdown"?(u=I(d,s),x=h(l.name||"untitled","markdown",l.uuid),T="text/markdown"):(u=k(d,s),x=h(l.name||"untitled","text",l.uuid),T="text/plain"),S(u,x,T),a++,await new Promise(F=>setTimeout(F,500))}catch(d){const u=d instanceof Error?d.message:"Unknown error";console.error(`Failed to export conversation ${l.uuid}:`,u),f.push(`${l.name||l.uuid}: ${u}`)}return f.length>0?(console.warn("Some conversations failed to export:",f),{count:a,warnings:`Exported ${a}/${c.length} conversations. Some failed: ${f.join("; ")}`}):{count:a}}(async()=>v.runtime.onMessage.addListener((o,i)=>o.action==="exportConversation"?(console.log("Export conversation request received:",o),(async()=>{try{return await e(o.orgId,o.conversationId,o.format,o.includeMetadata),{success:!0}}catch(s){const c=s instanceof Error?s.message:"Unknown error",a=s instanceof Error?s.stack:void 0;return console.error("Export conversation error:",s),{success:!1,error:c,details:a}}})()):o.action==="exportAllConversations"?(console.log("Export all conversations request received:",o),(async()=>{try{const s=await r(o.orgId,o.format,o.includeMetadata);return{success:!0,count:s.count,warnings:s.warnings}}catch(s){const c=s instanceof Error?s.message:"Unknown error",a=s instanceof Error?s.stack:void 0;return console.error("Export all conversations error:",s),{success:!1,error:c,details:a}}})()):!1))()}};function m(t,...n){}const y={debug:(...t)=>m(console.debug,...t),log:(...t)=>m(console.log,...t),warn:(...t)=>m(console.warn,...t),error:(...t)=>m(console.error,...t)};class b extends Event{constructor(n,e){super(b.EVENT_NAME,{}),this.newUrl=n,this.oldUrl=e}static EVENT_NAME=$("wxt:locationchange")}function $(t){return`${v?.runtime?.id}:content:${t}`}function L(t){let n,e;return{run(){n==null&&(e=new URL(location.href),n=t.setInterval(()=>{let r=new URL(location.href);r.href!==e.href&&(window.dispatchEvent(new b(r,e)),e=r)},1e3))}}}class w{constructor(n,e){this.contentScriptName=n,this.options=e,this.abortController=new AbortController,this.isTopFrame?(this.listenForNewerScripts({ignoreFirstEvent:!0}),this.stopOldScripts()):this.listenForNewerScripts()}static SCRIPT_STARTED_MESSAGE_TYPE=$("wxt:content-script-started");isTopFrame=window.self===window.top;abortController;locationWatcher=L(this);receivedMessageIds=new Set;get signal(){return this.abortController.signal}abort(n){return this.abortController.abort(n)}get isInvalid(){return v.runtime.id==null&&this.notifyInvalidated(),this.signal.aborted}get isValid(){return!this.isInvalid}onInvalidated(n){return this.signal.addEventListener("abort",n),()=>this.signal.removeEventListener("abort",n)}block(){return new Promise(()=>{})}setInterval(n,e){const r=setInterval(()=>{this.isValid&&n()},e);return this.onInvalidated(()=>clearInterval(r)),r}setTimeout(n,e){const r=setTimeout(()=>{this.isValid&&n()},e);return this.onInvalidated(()=>clearTimeout(r)),r}requestAnimationFrame(n){const e=requestAnimationFrame((...r)=>{this.isValid&&n(...r)});return this.onInvalidated(()=>cancelAnimationFrame(e)),e}requestIdleCallback(n,e){const r=requestIdleCallback((...o)=>{this.signal.aborted||n(...o)},e);return this.onInvalidated(()=>cancelIdleCallback(r)),r}addEventListener(n,e,r,o){e==="wxt:locationchange"&&this.isValid&&this.locationWatcher.run(),n.addEventListener?.(e.startsWith("wxt:")?$(e):e,r,{...o,signal:this.signal})}notifyInvalidated(){this.abort("Content script context invalidated"),y.debug(`Content script "${this.contentScriptName}" context invalidated`)}stopOldScripts(){window.postMessage({type:w.SCRIPT_STARTED_MESSAGE_TYPE,contentScriptName:this.contentScriptName,messageId:Math.random().toString(36).slice(2)},"*")}verifyScriptStartedEvent(n){const e=n.data?.type===w.SCRIPT_STARTED_MESSAGE_TYPE,r=n.data?.contentScriptName===this.contentScriptName,o=!this.receivedMessageIds.has(n.data?.messageId);return e&&r&&o}listenForNewerScripts(n){let e=!0;const r=o=>{if(this.verifyScriptStartedEvent(o)){this.receivedMessageIds.add(o.data.messageId);const i=e;if(e=!1,i&&n?.ignoreFirstEvent)return;this.notifyInvalidated()}};addEventListener("message",r),this.onInvalidated(()=>removeEventListener("message",r))}}function U(){}function p(t,...n){}const D={debug:(...t)=>p(console.debug,...t),log:(...t)=>p(console.log,...t),warn:(...t)=>p(console.warn,...t),error:(...t)=>p(console.error,...t)};return(async()=>{try{const{main:t,...n}=M,e=new w("content",n);return await t(e)}catch(t){throw D.error('The content script "content" crashed on startup!',t),t}})()})(); +content; \ No newline at end of file diff --git a/.output/chrome-mv3/content-styles.css b/.output/chrome-mv3/content-styles.css new file mode 100644 index 0000000..cdd2461 --- /dev/null +++ b/.output/chrome-mv3/content-styles.css @@ -0,0 +1,22 @@ +/* Optional: Add a floating export button on Claude.ai pages */ +.claude-exporter-button { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 9999; + background: #5436da; + color: white; + border: none; + border-radius: 50%; + width: 60px; + height: 60px; + font-size: 24px; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + transition: all 0.3s; +} + +.claude-exporter-button:hover { + background: #4329b8; + transform: scale(1.1); +} diff --git a/.output/chrome-mv3/icon128.png b/.output/chrome-mv3/icon128.png new file mode 100644 index 0000000..23a9b5a Binary files /dev/null and b/.output/chrome-mv3/icon128.png differ diff --git a/.output/chrome-mv3/icon16.png b/.output/chrome-mv3/icon16.png new file mode 100644 index 0000000..06b49c2 Binary files /dev/null and b/.output/chrome-mv3/icon16.png differ diff --git a/.output/chrome-mv3/icon48.png b/.output/chrome-mv3/icon48.png new file mode 100644 index 0000000..6bad8be Binary files /dev/null and b/.output/chrome-mv3/icon48.png differ diff --git a/.output/chrome-mv3/manifest.json b/.output/chrome-mv3/manifest.json new file mode 100644 index 0000000..a3e61fb --- /dev/null +++ b/.output/chrome-mv3/manifest.json @@ -0,0 +1 @@ +{"manifest_version":3,"name":"Claude Conversation Exporter","description":"Export your Claude.ai conversations with full message history","version":"1.0.0","permissions":["activeTab","storage"],"host_permissions":["https://claude.ai/*"],"background":{"service_worker":"background.js"},"action":{"default_title":"Claude Conversation Exporter","default_popup":"popup.html"},"content_scripts":[{"matches":["https://claude.ai/*"],"js":["content-scripts/content.js"]}]} \ No newline at end of file diff --git a/.output/chrome-mv3/popup-header.png b/.output/chrome-mv3/popup-header.png new file mode 100644 index 0000000..de149e6 Binary files /dev/null and b/.output/chrome-mv3/popup-header.png differ diff --git a/.output/chrome-mv3/popup.html b/.output/chrome-mv3/popup.html new file mode 100644 index 0000000..524cc2b --- /dev/null +++ b/.output/chrome-mv3/popup.html @@ -0,0 +1,119 @@ + + + + + + Claude Conversation Exporter + + + + +
+ Claude Conversation Exporter +
+ +
+ + +
+ + + +
+ + + + + +
+
+ + + diff --git a/.output/firefox-mv2/background.js b/.output/firefox-mv2/background.js new file mode 100644 index 0000000..31af0ff --- /dev/null +++ b/.output/firefox-mv2/background.js @@ -0,0 +1 @@ +var background=(function(){"use strict";const t=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome;function i(r){return r==null||typeof r=="function"?{main:r}:r}const a=i(()=>{console.log("Claude Conversation Exporter background script loaded"),t.runtime.onInstalled.addListener(()=>{console.log("Claude Conversation Exporter installed"),(async()=>{try{const r=await t.tabs.query({url:"https://claude.ai/*"});for(const e of r)if(e.id)try{await t.scripting.executeScript({target:{tabId:e.id},files:["content-scripts/content.js"]})}catch(n){console.log("Could not inject into tab",e.id,n)}}catch(r){console.error("Error querying or injecting tabs:",r)}})()}),t.runtime.onMessage.addListener((r,e)=>r.action==="ensureContentScript"?(async()=>{try{const c=(await t.tabs.query({active:!0,currentWindow:!0}))[0];return c?.id?(await t.scripting.executeScript({target:{tabId:c.id},files:["content-scripts/content.js"]}),{success:!0}):{success:!1,error:"No active tab found"}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Unknown error"}}})():!1)});function d(){}function o(r,...e){}const u={debug:(...r)=>o(console.debug,...r),log:(...r)=>o(console.log,...r),warn:(...r)=>o(console.warn,...r),error:(...r)=>o(console.error,...r)};let s;try{s=a.main(),s instanceof Promise&&console.warn("The background's main() function return a promise, but it must be synchronous")}catch(r){throw u.error("The background crashed on startup!"),r}return s})(); diff --git a/.output/firefox-mv2/chunks/popup-BzajcGsb.js b/.output/firefox-mv2/chunks/popup-BzajcGsb.js new file mode 100644 index 0000000..0d1f308 --- /dev/null +++ b/.output/firefox-mv2/chunks/popup-BzajcGsb.js @@ -0,0 +1 @@ +(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))c(r);new MutationObserver(r=>{for(const s of r)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&c(o)}).observe(document,{childList:!0,subtree:!0});function t(r){const s={};return r.integrity&&(s.integrity=r.integrity),r.referrerPolicy&&(s.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?s.credentials="include":r.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function c(r){if(r.ep)return;r.ep=!0;const s=t(r);fetch(r.href,s)}})();try{}catch(n){console.error("[wxt] Failed to initialize plugins",n)}const p=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome,u=p;async function f(){return(await u.storage.sync.get(["organizationId"])).organizationId}async function g(){const e=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!e?.url)return null;const t=new URL(e.url);return/\/chat\/([a-f0-9-]+)/.exec(t.pathname)?.[1]??null}function l(n,e="info"){const t=document.getElementById("status");t&&(t.className=`status ${e}`,t.textContent=n,e==="success"&&setTimeout(()=>{t.textContent="",t.className=""},3e3))}function i(n){return document.getElementById(n)}async function w(){if(!await f()){const e=i("setupNotice");e&&(e.style.display="block");const t=i("exportCurrent"),c=i("exportAll");t&&(t.disabled=!0),c&&(c.disabled=!0)}}function h(){i("openOptions")?.addEventListener("click",e=>{e.preventDefault(),u.runtime.openOptionsPage()})}async function m(){const n=i("exportCurrent");if(n){n.disabled=!0,l("Fetching conversation...","info");try{const e=await f(),t=await g();if(!e)throw new Error("Organization ID not configured. Click the setup link above to configure it.");if(!t)throw new Error("Could not detect a conversation ID. Make sure you are on a Claude.ai conversation page.");const r=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!r?.url?.includes("claude.ai"))throw new Error("Please navigate to a Claude.ai conversation page first.");if(!r.id)throw new Error("Could not identify active tab.");const s=i("format"),o=i("includeMetadata");try{const a=await u.tabs.sendMessage(r.id,{action:"exportConversation",conversationId:t,orgId:e,format:s?.value??"json",includeMetadata:o?.checked??!0});if(a?.success)l("Conversation exported successfully!","success");else{const d=a?.error??"Export failed";console.error("Export failed:",d,a?.details),l(d,"error")}}catch(a){const d=a instanceof Error?a.message:String(a);throw d.includes("connection")||d.includes("Receiving end")?new Error("Cannot connect to page. Please ensure you are on a Claude.ai conversation page (https://claude.ai/chat/...) and refresh if needed."):a}}catch(e){const t=e instanceof Error?e.message:"Unknown error occurred";l(t,"error")}finally{n.disabled=!1}}}function b(){u.tabs.create({url:u.runtime.getURL("browse.html")})}async function v(){const n=i("exportAll");if(n){n.disabled=!0,l("Fetching all conversations...","info");try{const e=await f();if(!e)throw new Error("Organization ID not configured. Click the setup link above to configure it.");const c=(await u.tabs.query({active:!0,currentWindow:!0}))[0];if(!c?.url?.includes("claude.ai"))throw new Error('Please navigate to a Claude.ai page first, or use "Browse All Conversations" instead.');if(!c.id)throw new Error("Could not identify active tab.");const r=i("format"),s=i("includeMetadata");try{const o=await u.tabs.sendMessage(c.id,{action:"exportAllConversations",orgId:e,format:r?.value??"json",includeMetadata:s?.checked??!0});if(o?.success)o.warnings?l(o.warnings,"info"):l(`Exported ${o.count??0} conversations!`,"success");else{const a=o?.error??"Export failed";console.error("Export failed:",a,o?.details),l(a,"error")}}catch(o){const a=o instanceof Error?o.message:String(o);throw a.includes("connection")||a.includes("Receiving end")?new Error('Cannot connect to page. This feature requires a Claude.ai page (https://claude.ai/chat/... or similar). Try "Browse All Conversations" instead - it works from any tab.'):o}}catch(e){const t=e instanceof Error?e.message:"Unknown error occurred";l(t,"error")}finally{n.disabled=!1}}}document.addEventListener("DOMContentLoaded",()=>{w(),h();const n=i("exportCurrent"),e=i("browseConversations"),t=i("exportAll");n?.addEventListener("click",()=>void m()),e?.addEventListener("click",b),t?.addEventListener("click",()=>void v())}); diff --git a/.output/firefox-mv2/content-scripts/content.js b/.output/firefox-mv2/content-scripts/content.js new file mode 100644 index 0000000..4fe5211 --- /dev/null +++ b/.output/firefox-mv2/content-scripts/content.js @@ -0,0 +1,27 @@ +var content=(function(){"use strict";const v=globalThis.browser?.runtime?.id?globalThis.browser:globalThis.chrome;function A(t){return t}const E=[{date:new Date("2024-01-01"),model:"claude-3-sonnet-20240229"},{date:new Date("2024-06-20"),model:"claude-3-5-sonnet-20240620"},{date:new Date("2024-10-22"),model:"claude-3-5-sonnet-20241022"},{date:new Date("2025-02-29"),model:"claude-3-7-sonnet-20250219"},{date:new Date("2025-05-14"),model:"claude-sonnet-4-20250514"},{date:new Date("2025-09-29"),model:"claude-sonnet-4-5-20250929"}];function g(t){if(t.model)return t.model;const n=new Date(t.created_at);for(let e=E.length-1;e>=0;e--){const r=E[e];if(r&&n>=r.date)return r.model}return E[0]?.model}function _(t){if(!t.chat_messages||!t.current_leaf_message_uuid)return[];const n=new Map;t.chat_messages.forEach(o=>{n.set(o.uuid,o)});const e=[];let r=t.current_leaf_message_uuid;for(;r&&n.has(r);){const o=n.get(r);if(!o||(e.unshift(o),r=o.parent_message_uuid,r&&!n.has(r)))break}return e}function C(t){let n="";if(t.content)for(const e of t.content)e.text&&(n+=e.text);else t.text&&(n=t.text);return n}function I(t,n){let e=`# ${t.name||"Untitled Conversation"} + +`;n&&(e+=`**Created:** ${new Date(t.created_at).toLocaleString()} +`,e+=`**Updated:** ${new Date(t.updated_at).toLocaleString()} +`,e+=`**Model:** ${g(t)} + +`,e+=`--- + +`);const r=_(t);for(const o of r){const i=o.sender==="human"?"**You**":"**Claude**";e+=`${i}: + +`;const s=C(o);s&&(e+=`${s} + +`),n&&o.created_at&&(e+=`*${new Date(o.created_at).toLocaleString()}* + +`),e+=`--- + +`}return e}function k(t,n){let e="";n&&(e+=`${t.name||"Untitled Conversation"} +`,e+=`Created: ${new Date(t.created_at).toLocaleString()} +`,e+=`Updated: ${new Date(t.updated_at).toLocaleString()} +`,e+=`Model: ${g(t)} + +`,e+=`--- + +`);const r=_(t);let o=!1,i=!1;for(const s of r){const c=C(s);let a;s.sender==="human"?(a=o?"H":"Human",o=!0):(a=i?"A":"Assistant",i=!0),e+=`${a}: ${c} + +`}return e.trim()}function S(t,n,e="application/json"){const r=new Blob([t],{type:e}),o=URL.createObjectURL(r),i=document.createElement("a");i.href=o,i.download=n,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(o)}function h(t,n,e){const r=t.replace(/[^a-z0-9]/gi,"_").toLowerCase().substring(0,50),o=n==="json"?"json":n==="markdown"?"md":"txt",i=e?`_${e.substring(0,8)}`:"";return`${r}${i}.${o}`}const M={matches:["https://claude.ai/*"],cssInjectionMode:"ui",main(){console.log("Claude Conversation Exporter content script loaded");async function t(o,i){const s=`https://claude.ai/api/organizations/${o}/chat_conversations/${i}?tree=True&rendering_mode=messages&render_all_tools=true`,c=await fetch(s,{credentials:"include",headers:{Accept:"application/json"}});if(!c.ok)throw new Error(`Failed to fetch conversation: ${c.status}`);return await c.json()}async function n(o){const i=`https://claude.ai/api/organizations/${o}/chat_conversations`,s=await fetch(i,{credentials:"include",headers:{Accept:"application/json"}});if(!s.ok)throw new Error(`Failed to fetch conversations: ${s.status}`);return await s.json()}async function e(o,i,s,c){console.log("Fetching conversation:",i);const a=await t(o,i);console.log("Conversation data fetched successfully:",a);const f=g(a);a.model=f;let l,d,u;switch(s){case"markdown":l=I(a,c),d=h(a.name||"untitled","markdown",a.uuid),u="text/markdown";break;case"text":l=k(a,c),d=h(a.name||"untitled","text",a.uuid),u="text/plain";break;default:l=JSON.stringify(a,null,2),d=h(a.name||"untitled","json",a.uuid),u="application/json"}console.log("Downloading file:",d),S(l,d,u)}async function r(o,i,s){const c=await n(o);if(console.log(`Fetched ${c.length} conversations`),i==="json"){const l=`claude-all-conversations-${new Date().toISOString().split("T")[0]??"export"}.json`;return console.log("Downloading all conversations as JSON:",l),S(JSON.stringify(c,null,2),l,"application/json"),{count:c.length}}let a=0;const f=[];for(const l of c)try{console.log(`Fetching full conversation ${a+1}/${c.length}: ${l.uuid}`);const d=await t(o,l.uuid);d.model=g(d);let u,x,T;i==="markdown"?(u=I(d,s),x=h(l.name||"untitled","markdown",l.uuid),T="text/markdown"):(u=k(d,s),x=h(l.name||"untitled","text",l.uuid),T="text/plain"),S(u,x,T),a++,await new Promise(F=>setTimeout(F,500))}catch(d){const u=d instanceof Error?d.message:"Unknown error";console.error(`Failed to export conversation ${l.uuid}:`,u),f.push(`${l.name||l.uuid}: ${u}`)}return f.length>0?(console.warn("Some conversations failed to export:",f),{count:a,warnings:`Exported ${a}/${c.length} conversations. Some failed: ${f.join("; ")}`}):{count:a}}(async()=>v.runtime.onMessage.addListener((o,i)=>o.action==="exportConversation"?(console.log("Export conversation request received:",o),(async()=>{try{return await e(o.orgId,o.conversationId,o.format,o.includeMetadata),{success:!0}}catch(s){const c=s instanceof Error?s.message:"Unknown error",a=s instanceof Error?s.stack:void 0;return console.error("Export conversation error:",s),{success:!1,error:c,details:a}}})()):o.action==="exportAllConversations"?(console.log("Export all conversations request received:",o),(async()=>{try{const s=await r(o.orgId,o.format,o.includeMetadata);return{success:!0,count:s.count,warnings:s.warnings}}catch(s){const c=s instanceof Error?s.message:"Unknown error",a=s instanceof Error?s.stack:void 0;return console.error("Export all conversations error:",s),{success:!1,error:c,details:a}}})()):!1))()}};function m(t,...n){}const y={debug:(...t)=>m(console.debug,...t),log:(...t)=>m(console.log,...t),warn:(...t)=>m(console.warn,...t),error:(...t)=>m(console.error,...t)};class b extends Event{constructor(n,e){super(b.EVENT_NAME,{}),this.newUrl=n,this.oldUrl=e}static EVENT_NAME=$("wxt:locationchange")}function $(t){return`${v?.runtime?.id}:content:${t}`}function L(t){let n,e;return{run(){n==null&&(e=new URL(location.href),n=t.setInterval(()=>{let r=new URL(location.href);r.href!==e.href&&(window.dispatchEvent(new b(r,e)),e=r)},1e3))}}}class w{constructor(n,e){this.contentScriptName=n,this.options=e,this.abortController=new AbortController,this.isTopFrame?(this.listenForNewerScripts({ignoreFirstEvent:!0}),this.stopOldScripts()):this.listenForNewerScripts()}static SCRIPT_STARTED_MESSAGE_TYPE=$("wxt:content-script-started");isTopFrame=window.self===window.top;abortController;locationWatcher=L(this);receivedMessageIds=new Set;get signal(){return this.abortController.signal}abort(n){return this.abortController.abort(n)}get isInvalid(){return v.runtime.id==null&&this.notifyInvalidated(),this.signal.aborted}get isValid(){return!this.isInvalid}onInvalidated(n){return this.signal.addEventListener("abort",n),()=>this.signal.removeEventListener("abort",n)}block(){return new Promise(()=>{})}setInterval(n,e){const r=setInterval(()=>{this.isValid&&n()},e);return this.onInvalidated(()=>clearInterval(r)),r}setTimeout(n,e){const r=setTimeout(()=>{this.isValid&&n()},e);return this.onInvalidated(()=>clearTimeout(r)),r}requestAnimationFrame(n){const e=requestAnimationFrame((...r)=>{this.isValid&&n(...r)});return this.onInvalidated(()=>cancelAnimationFrame(e)),e}requestIdleCallback(n,e){const r=requestIdleCallback((...o)=>{this.signal.aborted||n(...o)},e);return this.onInvalidated(()=>cancelIdleCallback(r)),r}addEventListener(n,e,r,o){e==="wxt:locationchange"&&this.isValid&&this.locationWatcher.run(),n.addEventListener?.(e.startsWith("wxt:")?$(e):e,r,{...o,signal:this.signal})}notifyInvalidated(){this.abort("Content script context invalidated"),y.debug(`Content script "${this.contentScriptName}" context invalidated`)}stopOldScripts(){window.postMessage({type:w.SCRIPT_STARTED_MESSAGE_TYPE,contentScriptName:this.contentScriptName,messageId:Math.random().toString(36).slice(2)},"*")}verifyScriptStartedEvent(n){const e=n.data?.type===w.SCRIPT_STARTED_MESSAGE_TYPE,r=n.data?.contentScriptName===this.contentScriptName,o=!this.receivedMessageIds.has(n.data?.messageId);return e&&r&&o}listenForNewerScripts(n){let e=!0;const r=o=>{if(this.verifyScriptStartedEvent(o)){this.receivedMessageIds.add(o.data.messageId);const i=e;if(e=!1,i&&n?.ignoreFirstEvent)return;this.notifyInvalidated()}};addEventListener("message",r),this.onInvalidated(()=>removeEventListener("message",r))}}function U(){}function p(t,...n){}const D={debug:(...t)=>p(console.debug,...t),log:(...t)=>p(console.log,...t),warn:(...t)=>p(console.warn,...t),error:(...t)=>p(console.error,...t)};return(async()=>{try{const{main:t,...n}=M,e=new w("content",n);return await t(e)}catch(t){throw D.error('The content script "content" crashed on startup!',t),t}})()})(); +content; \ No newline at end of file diff --git a/.output/firefox-mv2/content-styles.css b/.output/firefox-mv2/content-styles.css new file mode 100644 index 0000000..cdd2461 --- /dev/null +++ b/.output/firefox-mv2/content-styles.css @@ -0,0 +1,22 @@ +/* Optional: Add a floating export button on Claude.ai pages */ +.claude-exporter-button { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 9999; + background: #5436da; + color: white; + border: none; + border-radius: 50%; + width: 60px; + height: 60px; + font-size: 24px; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + transition: all 0.3s; +} + +.claude-exporter-button:hover { + background: #4329b8; + transform: scale(1.1); +} diff --git a/.output/firefox-mv2/icon128.png b/.output/firefox-mv2/icon128.png new file mode 100644 index 0000000..23a9b5a Binary files /dev/null and b/.output/firefox-mv2/icon128.png differ diff --git a/.output/firefox-mv2/icon16.png b/.output/firefox-mv2/icon16.png new file mode 100644 index 0000000..06b49c2 Binary files /dev/null and b/.output/firefox-mv2/icon16.png differ diff --git a/.output/firefox-mv2/icon48.png b/.output/firefox-mv2/icon48.png new file mode 100644 index 0000000..6bad8be Binary files /dev/null and b/.output/firefox-mv2/icon48.png differ diff --git a/.output/firefox-mv2/manifest.json b/.output/firefox-mv2/manifest.json new file mode 100644 index 0000000..20b3240 --- /dev/null +++ b/.output/firefox-mv2/manifest.json @@ -0,0 +1 @@ +{"manifest_version":2,"name":"Claude Conversation Exporter","description":"Export your Claude.ai conversations with full message history","version":"1.0.0","permissions":["activeTab","storage","https://claude.ai/*"],"background":{"scripts":["background.js"]},"browser_action":{"default_title":"Claude Conversation Exporter","default_popup":"popup.html"},"content_scripts":[{"matches":["https://claude.ai/*"],"js":["content-scripts/content.js"]}]} \ No newline at end of file diff --git a/.output/firefox-mv2/popup-header.png b/.output/firefox-mv2/popup-header.png new file mode 100644 index 0000000..de149e6 Binary files /dev/null and b/.output/firefox-mv2/popup-header.png differ diff --git a/.output/firefox-mv2/popup.html b/.output/firefox-mv2/popup.html new file mode 100644 index 0000000..524cc2b --- /dev/null +++ b/.output/firefox-mv2/popup.html @@ -0,0 +1,119 @@ + + + + + + Claude Conversation Exporter + + + + +
+ Claude Conversation Exporter +
+ +
+ + +
+ + + +
+ + + + + +
+
+ + + diff --git a/.wxt/eslintrc-auto-import.json b/.wxt/eslintrc-auto-import.json new file mode 100644 index 0000000..1419a27 --- /dev/null +++ b/.wxt/eslintrc-auto-import.json @@ -0,0 +1,49 @@ +{ + "globals": { + "AutoMount": true, + "AutoMountOptions": true, + "Browser": true, + "ContentScriptAnchoredOptions": true, + "ContentScriptAppendMode": true, + "ContentScriptContext": true, + "ContentScriptInlinePositioningOptions": true, + "ContentScriptModalPositioningOptions": true, + "ContentScriptOverlayAlignment": true, + "ContentScriptOverlayPositioningOptions": true, + "ContentScriptPositioningOptions": true, + "ContentScriptUi": true, + "ContentScriptUiOptions": true, + "IframeContentScriptUi": true, + "IframeContentScriptUiOptions": true, + "InjectScriptOptions": true, + "IntegratedContentScriptUi": true, + "IntegratedContentScriptUiOptions": true, + "InvalidMatchPattern": true, + "MatchPattern": true, + "MigrationError": true, + "ScriptPublicPath": true, + "ShadowRootContentScriptUi": true, + "ShadowRootContentScriptUiOptions": true, + "StopAutoMount": true, + "StorageArea": true, + "StorageAreaChanges": true, + "StorageItemKey": true, + "WxtAppConfig": true, + "WxtStorage": true, + "WxtStorageItem": true, + "WxtWindowEventMap": true, + "browser": true, + "createIframeUi": true, + "createIntegratedUi": true, + "createShadowRootUi": true, + "defineAppConfig": true, + "defineBackground": true, + "defineContentScript": true, + "defineUnlistedScript": true, + "defineWxtPlugin": true, + "fakeBrowser": true, + "injectScript": true, + "storage": true, + "useAppConfig": true + } +} diff --git a/.wxt/tsconfig.json b/.wxt/tsconfig.json new file mode 100644 index 0000000..899f31c --- /dev/null +++ b/.wxt/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "strict": true, + "skipLibCheck": true, + "paths": { + "@": [".."], + "@/*": ["../*"], + "~": [".."], + "~/*": ["../*"], + "@@": [".."], + "@@/*": ["../*"], + "~~": [".."], + "~~/*": ["../*"] + } + }, + "include": [ + "../**/*", + "./wxt.d.ts" + ], + "exclude": ["../.output"] +} \ No newline at end of file diff --git a/build-check.sh b/build-check.sh deleted file mode 100755 index f4ce515..0000000 --- a/build-check.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e - -echo "Building Firefox extension..." -cd /home/jasonross/workspace/Claude-Conversation-Exporter-Firefox-TS - -# Run TypeScript compiler -echo "Running TypeScript compiler..." -npx tsc --noEmit - -# Run Vite build -echo "Running Vite build..." -npx vite build --mode firefox - -# Check if content script was built correctly -echo "" -echo "Checking content script..." -CONTENT_SIZE=$(stat -f%z dist/firefox/src/content.js 2>/dev/null || stat -c%s dist/firefox/src/content.js 2>/dev/null) -echo "Content script size: $CONTENT_SIZE bytes" - -if [ "$CONTENT_SIZE" -lt 100 ]; then - echo "❌ ERROR: Content script is too small! ($CONTENT_SIZE bytes)" - echo "Content of content.js:" - cat dist/firefox/src/content.js -else - echo "✅ Content script built successfully" -fi - -echo "" -echo "Build complete!" -ls -lh dist/firefox/src/*.js diff --git a/build-chrome.sh b/build-chrome.sh deleted file mode 100755 index d3bbc20..0000000 --- a/build-chrome.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -# Build script for Chrome extension -# This script builds the content script separately as an IIFE to avoid -# the broken dynamic import loader that the vite-plugin-web-extension creates - -set -e - -echo "Building Chrome extension..." - -# Step 1: Build content script separately as IIFE -echo "Step 1: Building content script..." -npx vite build --config vite.content-chrome.config.ts - -# Step 2: Build main extension with vite-plugin-web-extension -echo "Step 2: Building main extension..." -BROWSER=chrome npx vite build --mode chrome - -# Step 3: Copy the IIFE content script over the stub -echo "Step 3: Replacing content script stub with IIFE bundle..." -cp dist-temp-content-chrome/content.js dist/chrome/src/chrome/scripts/content.js - -# Step 3.5: Fix serviceWorker.js import path (make it relative) -echo "Step 3.5: Fixing serviceWorker.js import path..." -sed -i 's|"/src/|"./src/|g' dist/chrome/serviceWorker.js - -# Step 4: Copy icon files -echo "Step 4: Copying icon files..." -mkdir -p dist/chrome/src -cp src/icon16.png dist/chrome/src/ -cp src/icon48.png dist/chrome/src/ -cp src/icon128.png dist/chrome/src/ - -# Step 5: Copy popup header image -echo "Step 5: Copying popup header..." -mkdir -p dist/chrome/src/chrome/scripts -cp src/popup-header.png dist/chrome/src/chrome/scripts/ - -echo "Chrome build complete!" -echo "Load unpacked extension from: dist/chrome/" diff --git a/build-firefox.sh b/build-firefox.sh deleted file mode 100755 index 4a471da..0000000 --- a/build-firefox.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -set -e - -cd /home/jasonross/workspace/Claude-Conversation-Exporter-Firefox-TS - -echo "Building content script separately..." -npx vite build --config vite.content-firefox.config.ts - -echo "Building main extension..." -npx vite build --mode firefox - -echo "Copying content script to dist..." -cp dist-temp-content-firefox/content.js dist/firefox/src/firefox/scripts/content.js -rm -rf dist-temp-content-firefox - -echo "Copying icon files..." -mkdir -p dist/firefox/src -cp src/icon16.png dist/firefox/src/ -cp src/icon48.png dist/firefox/src/ -cp src/icon128.png dist/firefox/src/ - -echo "Copying popup header..." -mkdir -p dist/firefox/src/firefox/scripts -cp src/popup-header.png dist/firefox/src/firefox/scripts/ - -echo "" -echo "Checking content script..." -CONTENT_SIZE=$(stat -c%s dist/firefox/src/firefox/scripts/content.js 2>/dev/null || stat -f%z dist/firefox/src/firefox/scripts/content.js) -echo "Content script size: $CONTENT_SIZE bytes" - -if [ "$CONTENT_SIZE" -gt 1000 ]; then - echo "✅ Content script built successfully!" -else - echo "❌ ERROR: Content script is too small" -fi - -echo "" -echo "Build complete!" diff --git a/convert-to-chrome.sh b/convert-to-chrome.sh deleted file mode 100755 index 503cffd..0000000 --- a/convert-to-chrome.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# Script to convert Firefox browser.* API calls to Chrome chrome.* API calls -# This creates Chrome-specific versions of the extension scripts - -set -e - -echo "Converting Firefox scripts to Chrome API..." - -# Files to convert -FILES=("popup.ts" "options.ts" "browse.ts" "content.ts" "background.ts") - -for file in "${FILES[@]}"; do - echo "Converting $file..." - - # Copy file to Chrome directory - cp "src/$file" "src/chrome/scripts/$file" - - # Convert browser.* calls to chrome.* - # This uses sed to replace browser API calls with chrome API calls - # and wraps Promise-based calls with callbacks - - sed -i 's/browser\.storage\.sync\.get/chrome.storage.sync.get/g' "src/chrome/scripts/$file" - sed -i 's/browser\.storage\.sync\.set/chrome.storage.sync.set/g' "src/chrome/scripts/$file" - sed -i 's/browser\.tabs\.query/chrome.tabs.query/g' "src/chrome/scripts/$file" - sed -i 's/browser\.tabs\.sendMessage/chrome.tabs.sendMessage/g' "src/chrome/scripts/$file" - sed -i 's/browser\.tabs\.create/chrome.tabs.create/g' "src/chrome/scripts/$file" - sed -i 's/browser\.runtime\.sendMessage/chrome.runtime.sendMessage/g' "src/chrome/scripts/$file" - sed -i 's/browser\.runtime\.getURL/chrome.runtime.getURL/g' "src/chrome/scripts/$file" - sed -i 's/browser\.runtime\.onMessage/chrome.runtime.onMessage/g' "src/chrome/scripts/$file" - - echo "✅ Converted $file" -done - -# Copy Firefox scripts to firefox directory -echo "Copying Firefox scripts..." -for file in "${FILES[@]}"; do - cp "src/$file" "src/firefox/scripts/$file" - echo "✅ Copied $file to Firefox directory" -done - -echo "" -echo "Conversion complete!" -echo "Chrome scripts: src/chrome/scripts/" -echo "Firefox scripts: src/firefox/scripts/" diff --git a/entrypoints/background.ts b/entrypoints/background.ts new file mode 100644 index 0000000..566af69 --- /dev/null +++ b/entrypoints/background.ts @@ -0,0 +1,81 @@ +/** + * Background script for Claude Conversation Exporter + * Handles extension lifecycle events and content script injection + */ + +import { defineBackground as wxtDefineBackground } from 'wxt/utils/define-background'; +import type { ExtensionMessage } from '../src/types'; + +export default wxtDefineBackground(() => { + console.log('Claude Conversation Exporter background script loaded'); + + /** + * Handle extension installation + */ + browser.runtime.onInstalled.addListener(() => { + console.log('Claude Conversation Exporter installed'); + + // Inject content script into already-open Claude.ai tabs + void (async () => { + try { + const tabs = await browser.tabs.query({ url: 'https://claude.ai/*' }); + + for (const tab of tabs) { + if (tab.id) { + try { + await browser.scripting.executeScript({ + target: { tabId: tab.id }, + files: ['content-scripts/content.js'], + }); + } catch (err) { + console.log('Could not inject into tab', tab.id, err); + } + } + } + } catch (err) { + console.error('Error querying or injecting tabs:', err); + } + })(); + }); + + /** + * Handle messages from popup or other extension components + */ + browser.runtime.onMessage.addListener( + (request: ExtensionMessage, _sender: browser.runtime.MessageSender) => { + if (request.action === 'ensureContentScript') { + return (async () => { + try { + const tabs = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + + const activeTab = tabs[0]; + if (activeTab?.id) { + await browser.scripting.executeScript({ + target: { tabId: activeTab.id }, + files: ['content-scripts/content.js'], + }); + + return { success: true }; + } + + return { + success: false, + error: 'No active tab found', + }; + } catch (err) { + return { + success: false, + error: err instanceof Error ? err.message : 'Unknown error', + }; + } + })(); + } + + // Return false to indicate no response will be sent + return false; + } + ); +}); diff --git a/entrypoints/content.ts b/entrypoints/content.ts new file mode 100644 index 0000000..8032468 --- /dev/null +++ b/entrypoints/content.ts @@ -0,0 +1,255 @@ +/** + * Content script for Claude Conversation Exporter + * Runs on claude.ai pages to handle conversation exports + */ + +import { defineContentScript as wxtDefineContentScript } from 'wxt/utils/define-content-script'; +import type { + Conversation, + ConversationListItem, + ExtensionMessage, + ExportFormat, +} from '../src/types'; +import { + convertToMarkdown, + convertToText, + downloadFile, + generateFilename, + inferModel, +} from '../src/utils'; + +export default wxtDefineContentScript({ + matches: ['https://claude.ai/*'], + cssInjectionMode: 'ui', + main() { + console.log('Claude Conversation Exporter content script loaded'); + + /** + * Fetch a single conversation from Claude API + */ + async function fetchConversation( + orgId: string, + conversationId: string + ): Promise { + const url = `https://claude.ai/api/organizations/${orgId}/chat_conversations/${conversationId}?tree=True&rendering_mode=messages&render_all_tools=true`; + + const response = await fetch(url, { + credentials: 'include', + headers: { + Accept: 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch conversation: ${response.status}`); + } + + return (await response.json()) as Conversation; + } + + /** + * Fetch all conversations from Claude API + */ + async function fetchAllConversations(orgId: string): Promise { + const url = `https://claude.ai/api/organizations/${orgId}/chat_conversations`; + + const response = await fetch(url, { + credentials: 'include', + headers: { + Accept: 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch conversations: ${response.status}`); + } + + return (await response.json()) as ConversationListItem[]; + } + + /** + * Export a single conversation + */ + async function exportConversation( + orgId: string, + conversationId: string, + format: ExportFormat, + includeMetadata: boolean + ): Promise { + console.log('Fetching conversation:', conversationId); + const data = await fetchConversation(orgId, conversationId); + + console.log('Conversation data fetched successfully:', data); + + // Infer model if null + const modelName = inferModel(data); + data.model = modelName; + + let content: string; + let filename: string; + let type: string; + + switch (format) { + case 'markdown': + content = convertToMarkdown(data, includeMetadata); + filename = generateFilename(data.name || 'untitled', 'markdown', data.uuid); + type = 'text/markdown'; + break; + case 'text': + content = convertToText(data, includeMetadata); + filename = generateFilename(data.name || 'untitled', 'text', data.uuid); + type = 'text/plain'; + break; + default: + content = JSON.stringify(data, null, 2); + filename = generateFilename(data.name || 'untitled', 'json', data.uuid); + type = 'application/json'; + } + + console.log('Downloading file:', filename); + downloadFile(content, filename, type); + } + + /** + * Export all conversations + */ + async function exportAllConversations( + orgId: string, + format: ExportFormat, + includeMetadata: boolean + ): Promise<{ count: number; warnings?: string }> { + const conversations = await fetchAllConversations(orgId); + console.log(`Fetched ${conversations.length} conversations`); + + if (format === 'json') { + // For JSON, export as a single file with all conversations + const filename = `claude-all-conversations-${ + new Date().toISOString().split('T')[0] ?? 'export' + }.json`; + console.log('Downloading all conversations as JSON:', filename); + downloadFile( + JSON.stringify(conversations, null, 2), + filename, + 'application/json' + ); + return { count: conversations.length }; + } + + // For other formats, create individual files + let count = 0; + const errors: string[] = []; + + for (const conv of conversations) { + try { + console.log( + `Fetching full conversation ${count + 1}/${conversations.length}: ${conv.uuid}` + ); + const fullConv = await fetchConversation(orgId, conv.uuid); + + // Infer model if null + fullConv.model = inferModel(fullConv); + + let content: string; + let filename: string; + let type: string; + + if (format === 'markdown') { + content = convertToMarkdown(fullConv, includeMetadata); + filename = generateFilename(conv.name || 'untitled', 'markdown', conv.uuid); + type = 'text/markdown'; + } else { + content = convertToText(fullConv, includeMetadata); + filename = generateFilename(conv.name || 'untitled', 'text', conv.uuid); + type = 'text/plain'; + } + + downloadFile(content, filename, type); + count++; + + // Add a small delay to avoid overwhelming the API + await new Promise((resolve) => setTimeout(resolve, 500)); + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error'; + console.error(`Failed to export conversation ${conv.uuid}:`, errorMsg); + errors.push(`${conv.name || conv.uuid}: ${errorMsg}`); + } + } + + if (errors.length > 0) { + console.warn('Some conversations failed to export:', errors); + return { + count, + warnings: `Exported ${count}/${conversations.length} conversations. Some failed: ${errors.join('; ')}`, + }; + } + + return { count }; + } + + /** + * Handle messages from popup or background script + */ + (async () => { + browser.runtime.onMessage.addListener( + (request: ExtensionMessage, _sender: browser.runtime.MessageSender) => { + if (request.action === 'exportConversation') { + console.log('Export conversation request received:', request); + + return (async () => { + try { + await exportConversation( + request.orgId, + request.conversationId, + request.format, + request.includeMetadata + ); + return { success: true }; + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error'; + const errorStack = error instanceof Error ? error.stack : undefined; + console.error('Export conversation error:', error); + return { + success: false, + error: errorMsg, + details: errorStack, + }; + } + })(); + } + + if (request.action === 'exportAllConversations') { + console.log('Export all conversations request received:', request); + + return (async () => { + try { + const result = await exportAllConversations( + request.orgId, + request.format, + request.includeMetadata + ); + return { + success: true, + count: result.count, + warnings: result.warnings, + }; + } catch (error) { + const errorMsg = error instanceof Error ? error.message : 'Unknown error'; + const errorStack = error instanceof Error ? error.stack : undefined; + console.error('Export all conversations error:', error); + return { + success: false, + error: errorMsg, + details: errorStack, + }; + } + })(); + } + + // Return false to indicate no response will be sent + return false; + } + ); + })(); + }, +} as const); + diff --git a/entrypoints/popup/index.html b/entrypoints/popup/index.html new file mode 100644 index 0000000..65630d9 --- /dev/null +++ b/entrypoints/popup/index.html @@ -0,0 +1,123 @@ + + + + + + Claude Conversation Exporter + + + +
+ Claude Conversation Exporter +
+ +
+ + +
+ + + +
+ + + + + +
+
+ + + + diff --git a/entrypoints/popup/main.ts b/entrypoints/popup/main.ts new file mode 100644 index 0000000..122f7e8 --- /dev/null +++ b/entrypoints/popup/main.ts @@ -0,0 +1,257 @@ +/** + * Popup script for Claude Conversation Exporter + * Handles the extension popup UI and user interactions + */ + +import type { ExtensionResponse } from '../../src/types'; + +/** + * Get organization ID from storage + */ +async function getOrgId(): Promise { + const result = await browser.storage.sync.get(['organizationId']); + return result['organizationId'] as string | undefined; +} + +/** + * Get current conversation ID from active tab URL + */ +async function getCurrentConversationId(): Promise { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tab = tabs[0]; + + if (!tab?.url) { + return null; + } + + const url = new URL(tab.url); + const match = /\/chat\/([a-f0-9-]+)/.exec(url.pathname); + return match?.[1] ?? null; +} + +/** + * Show status message to user + */ +function showStatus(message: string, type: 'info' | 'success' | 'error' = 'info'): void { + const statusEl = document.getElementById('status'); + if (!statusEl) return; + + statusEl.className = `status ${type}`; + statusEl.textContent = message; + + if (type === 'success') { + setTimeout(() => { + statusEl.textContent = ''; + statusEl.className = ''; + }, 3000); + } +} + +/** + * Get HTML element by ID with type checking + */ +function getElement(id: string): T | null { + return document.getElementById(id) as T | null; +} + +/** + * Check if org ID is configured on popup load + */ +async function initializePopup(): Promise { + const orgId = await getOrgId(); + + if (!orgId) { + const setupNotice = getElement('setupNotice'); + if (setupNotice) { + setupNotice.style.display = 'block'; + } + + const exportCurrentBtn = getElement('exportCurrent'); + const exportAllBtn = getElement('exportAll'); + + if (exportCurrentBtn) exportCurrentBtn.disabled = true; + if (exportAllBtn) exportAllBtn.disabled = true; + } +} + +/** + * Handle options link click + */ +function setupOptionsLink(): void { + const openOptionsBtn = getElement('openOptions'); + openOptionsBtn?.addEventListener('click', (e) => { + e.preventDefault(); + void browser.runtime.openOptionsPage(); + }); +} + +/** + * Handle export current conversation + */ +async function handleExportCurrent(): Promise { + const button = getElement('exportCurrent'); + if (!button) return; + + button.disabled = true; + showStatus('Fetching conversation...', 'info'); + + try { + const orgId = await getOrgId(); + const conversationId = await getCurrentConversationId(); + + if (!orgId) { + throw new Error( + 'Organization ID not configured. Click the setup link above to configure it.' + ); + } + + if (!conversationId) { + throw new Error( + 'Could not detect a conversation ID. Make sure you are on a Claude.ai conversation page.' + ); + } + + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tab = tabs[0]; + + // Check if we're on Claude.ai + if (!tab?.url?.includes('claude.ai')) { + throw new Error('Please navigate to a Claude.ai conversation page first.'); + } + + if (!tab.id) { + throw new Error('Could not identify active tab.'); + } + + const formatSelect = getElement('format'); + const metadataCheck = getElement('includeMetadata'); + + try { + const response = (await browser.tabs.sendMessage(tab.id, { + action: 'exportConversation', + conversationId, + orgId, + format: formatSelect?.value ?? 'json', + includeMetadata: metadataCheck?.checked ?? true, + })) as ExtensionResponse; + + if (response?.success) { + showStatus('Conversation exported successfully!', 'success'); + } else { + const errorMsg = response?.error ?? 'Export failed'; + console.error('Export failed:', errorMsg, response?.details); + showStatus(errorMsg, 'error'); + } + } catch (sendError) { + // Handle "Could not establish connection" error + const errorMsg = sendError instanceof Error ? sendError.message : String(sendError); + if (errorMsg.includes('connection') || errorMsg.includes('Receiving end')) { + throw new Error( + 'Cannot connect to page. Please ensure you are on a Claude.ai conversation page (https://claude.ai/chat/...) and refresh if needed.' + ); + } + throw sendError; + } + } catch (error) { + const message = error instanceof Error ? error.message : 'Unknown error occurred'; + showStatus(message, 'error'); + } finally { + button.disabled = false; + } +} + +/** + * Handle browse conversations button + */ +function handleBrowseConversations(): void { + void browser.tabs.create({ url: browser.runtime.getURL('browse.html') }); +} + +/** + * Handle export all conversations + */ +async function handleExportAll(): Promise { + const button = getElement('exportAll'); + if (!button) return; + + button.disabled = true; + showStatus('Fetching all conversations...', 'info'); + + try { + const orgId = await getOrgId(); + + if (!orgId) { + throw new Error( + 'Organization ID not configured. Click the setup link above to configure it.' + ); + } + + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + const tab = tabs[0]; + + // Check if we're on Claude.ai + if (!tab?.url?.includes('claude.ai')) { + throw new Error( + 'Please navigate to a Claude.ai page first, or use "Browse All Conversations" instead.' + ); + } + + if (!tab.id) { + throw new Error('Could not identify active tab.'); + } + + const formatSelect = getElement('format'); + const metadataCheck = getElement('includeMetadata'); + + try { + const response = (await browser.tabs.sendMessage(tab.id, { + action: 'exportAllConversations', + orgId, + format: formatSelect?.value ?? 'json', + includeMetadata: metadataCheck?.checked ?? true, + })) as ExtensionResponse; + + if (response?.success) { + if (response.warnings) { + showStatus(response.warnings, 'info'); + } else { + showStatus(`Exported ${response.count ?? 0} conversations!`, 'success'); + } + } else { + const errorMsg = response?.error ?? 'Export failed'; + console.error('Export failed:', errorMsg, response?.details); + showStatus(errorMsg, 'error'); + } + } catch (sendError) { + // Handle "Could not establish connection" error + const errorMsg = sendError instanceof Error ? sendError.message : String(sendError); + if (errorMsg.includes('connection') || errorMsg.includes('Receiving end')) { + throw new Error( + 'Cannot connect to page. This feature requires a Claude.ai page (https://claude.ai/chat/... or similar). Try "Browse All Conversations" instead - it works from any tab.' + ); + } + throw sendError; + } + } catch (error) { + const message = error instanceof Error ? error.message : 'Unknown error occurred'; + showStatus(message, 'error'); + } finally { + button.disabled = false; + } +} + +/** + * Initialize popup when DOM is loaded + */ +document.addEventListener('DOMContentLoaded', () => { + void initializePopup(); + setupOptionsLink(); + + const exportCurrentBtn = getElement('exportCurrent'); + const browseBtn = getElement('browseConversations'); + const exportAllBtn = getElement('exportAll'); + + exportCurrentBtn?.addEventListener('click', () => void handleExportCurrent()); + browseBtn?.addEventListener('click', handleBrowseConversations); + exportAllBtn?.addEventListener('click', () => void handleExportAll()); +}); diff --git a/package.json b/package.json index 02e5381..ba5dd09 100644 --- a/package.json +++ b/package.json @@ -4,24 +4,25 @@ "description": "Export your Claude.ai conversations in various formats - Chrome and Firefox extension with TypeScript support", "type": "module", "scripts": { - "build": "tsc && vite build", - "build:firefox": "bash build-firefox.sh", - "build:chrome": "bash build-chrome.sh", - "dev": "vite build --watch", - "dev:firefox": "vite build --mode firefox --watch", - "dev:chrome": "vite build --mode chrome --watch", - "type-check": "tsc --noEmit", - "lint": "eslint src/**/*.ts", - "lint:fix": "eslint src/**/*.ts --fix", - "format": "prettier --check \"src/**/*.{ts,html,css,json}\"", - "format:fix": "prettier --write \"src/**/*.{ts,html,css,json}\"", + "dev": "wxt", + "dev:firefox": "wxt -b firefox", + "dev:chrome": "wxt -b chrome", + "build": "wxt build", + "build:firefox": "wxt build -b firefox", + "build:chrome": "wxt build -b chrome", + "zip": "wxt zip", + "zip:firefox": "wxt zip -b firefox", + "zip:chrome": "wxt zip -b chrome", + "type-check": "wxt type-check", + "lint": "eslint entrypoints/**/*.ts src/**/*.ts", + "lint:fix": "eslint entrypoints/**/*.ts src/**/*.ts --fix", + "format": "prettier --check \"**/*.{ts,html,css,json}\"", + "format:fix": "prettier --write \"**/*.{ts,html,css,json}\"", "test": "vitest run", "test:ui": "vitest run --ui", "test:coverage": "vitest run --coverage", - "check": "pnpm type-check && pnpm lint && pnpm format && pnpm test:run", - "firefox:run": "web-ext run --source-dir=dist/firefox --start-url https://claude.ai", - "chrome:run": "echo 'Load dist/chrome in chrome://extensions with Developer Mode enabled'", - "clean": "rm -rf dist" + "check": "pnpm type-check && pnpm lint && pnpm format && pnpm test", + "clean": "rm -rf .wxt .output dist" }, "keywords": [ "claude", @@ -37,7 +38,6 @@ "packageManager": "pnpm@10.18.1", "devDependencies": { "@eslint/js": "^9.38.0", - "@samrum/vite-plugin-web-extension": "^5.1.1", "@types/chrome": "^0.1.24", "@types/firefox-webext-browser": "^143.0.0", "@types/jszip": "^3.4.0", @@ -53,10 +53,9 @@ "prettier": "^3.6.2", "typescript": "^5.9.3", "typescript-eslint": "^8.46.1", - "vite": "^7.1.10", - "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.2.4", - "web-ext": "^9.0.0" + "web-ext": "^9.0.0", + "wxt": "^0.20.11" }, "dependencies": { "jszip": "^3.10.1" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b55901..bb84584 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,9 +15,6 @@ importers: '@eslint/js': specifier: ^9.38.0 version: 9.38.0 - '@samrum/vite-plugin-web-extension': - specifier: ^5.1.1 - version: 5.1.1(vite@7.1.10(@types/node@24.8.1)) '@types/chrome': specifier: ^0.1.24 version: 0.1.24 @@ -29,10 +26,10 @@ importers: version: 3.4.1 '@typescript-eslint/eslint-plugin': specifier: ^8.46.1 - version: 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0)(typescript@5.9.3))(eslint@9.38.0)(typescript@5.9.3) + version: 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.46.1 - version: 8.46.1(eslint@9.38.0)(typescript@5.9.3) + version: 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) '@vitest/coverage-v8': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) @@ -41,13 +38,13 @@ importers: version: 3.2.4(vitest@3.2.4) eslint: specifier: ^9.38.0 - version: 9.38.0 + version: 9.38.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@9.38.0) + version: 10.1.8(eslint@9.38.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.5.4 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.38.0))(eslint@9.38.0)(prettier@3.6.2) + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1))(prettier@3.6.2) happy-dom: specifier: ^20.0.5 version: 20.0.5 @@ -62,22 +59,32 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.46.1 - version: 8.46.1(eslint@9.38.0)(typescript@5.9.3) - vite: - specifier: ^7.1.10 - version: 7.1.10(@types/node@24.8.1) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.3)(vite@7.1.10(@types/node@24.8.1)) + version: 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jsdom@27.0.1(postcss@8.5.6)) + version: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6)) web-ext: specifier: ^9.0.0 version: 9.0.0 + wxt: + specifier: ^0.20.11 + version: 0.20.11(@types/node@24.8.1)(jiti@2.6.1)(rollup@4.52.5) packages: + '@1natsu/wait-element@4.1.2': + resolution: {integrity: sha512-qWxSJD+Q5b8bKOvESFifvfZ92DuMsY+03SBNjTO34ipJLP6mZ9yK4bQz/vlh48aEQXoJfaZBqUwKL5BdI5iiWw==} + + '@aklinker1/rollup-plugin-visualizer@5.12.0': + resolution: {integrity: sha512-X24LvEGw6UFmy0lpGJDmXsMyBD58XmX1bbwsaMLhNoM+UMQfQ3b2RtC+nz4b/NoRK5r6QJSKJHBNVeUdwqybaQ==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rollup: + optional: true + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -108,6 +115,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/runtime@7.28.2': + resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.4': resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} @@ -402,6 +413,14 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -413,6 +432,9 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -571,18 +593,9 @@ packages: cpu: [x64] os: [win32] - '@samrum/vite-plugin-web-extension@5.1.1': - resolution: {integrity: sha512-ZpmAN5bGaPouW8iwwCpz5UpvAHGG5f1poxtvjych/C7BIg0A1D8IM9ewacBO3odf5iuuPZIA0SFdgwtgHozueA==} - engines: {node: '>=16.0.0'} - peerDependencies: - vite: ^4.0.3 || ^5.0.0 - '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} - '@types/chrome@0.0.233': - resolution: {integrity: sha512-T3HUW8LDhHfYPbUkOZilhnqX04sZqEFIQO0OIG8byZ7PBIk2jYys1AkNg56UbtKbsh3dABmOniK+0Q3oyo7Sxg==} - '@types/chrome@0.1.24': resolution: {integrity: sha512-9iO9HL2bMeGS4C8m6gNFWUyuPE5HEUFk+rGh+7oriUjg+ata4Fc9PoVlu8xvGm7yoo3AmS3J6fAjoFj61NL2rw==} @@ -592,9 +605,6 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@types/etag@1.8.4': - resolution: {integrity: sha512-f1z/UMth8gQ6636NBqhFmJ3zES7EuDcUnV6K1gl1osHp+85KPKX+VixYWUpqLkw1fftCagyHJjJOZjZkEi2rHw==} - '@types/filesystem@0.0.36': resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} @@ -734,6 +744,21 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@webext-core/fake-browser@1.3.2': + resolution: {integrity: sha512-jFyPWWz+VkHAC9DRIiIPOyu6X/KlC8dYqSKweHz6tsDb86QawtVgZSpYcM+GOQBlZc5DHFo92jJ7cIq4uBnU0A==} + + '@webext-core/isolated-element@1.1.2': + resolution: {integrity: sha512-CNHYhsIR8TPkPb+4yqTIuzaGnVn/Fshev5fyoPW+/8Cyc93tJbCjP9PC1XSK6fDWu+xASdPHLZaoa2nWAYoxeQ==} + + '@webext-core/match-patterns@1.0.3': + resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==} + + '@wxt-dev/browser@0.1.4': + resolution: {integrity: sha512-9x03I15i79XU8qYwjv4le0K2HdMl/Yga2wUBSoUbcrCnamv8P3nvuYxREQ9C5QY/qPAfeEVdAtaTrS3KWak71g==} + + '@wxt-dev/storage@1.2.6': + resolution: {integrity: sha512-f6AknnpJvhNHW4s0WqwSGCuZAj0fjP3EVNPBO5kB30pY+3Zt/nqZGqJN6FgBLCSkYjPJ8VL1hNX5LMVmvxQoDw==} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -786,6 +811,10 @@ packages: ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-escapes@7.1.1: + resolution: {integrity: sha512-Zhl0ErHcSRUaVfGUeUdDuLgpkEo8KIFjB4Y9uAc46ScOpdDiU1Dbyplh7qWJeJ/ZHpbyMSM26+X3BySgnIz40Q==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -820,6 +849,9 @@ packages: ast-v8-to-istanbul@0.3.7: resolution: {integrity: sha512-kr1Hy6YRZBkGQSb6puP+D6FQ59Cx4m0siYhAxygMCAgadiWQ6oxAxQXHOMvJx67SJ63jRoVIIg5eXzUbbct1ww==} + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -866,6 +898,14 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + c12@3.3.1: + resolution: {integrity: sha512-LcWQ01LT9tkoUINHgpIOv3mMs+Abv7oVCrtpMRi1PaapVEpWoMga5WuT7/DqFTu7URP9ftbOmimNw1KNIGh9DQ==} + peerDependencies: + magicast: ^0.3.5 + peerDependenciesMeta: + magicast: + optional: true + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -901,15 +941,38 @@ packages: resolution: {integrity: sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==} engines: {node: '>=20.18.1'} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + chrome-launcher@1.2.0: resolution: {integrity: sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q==} engines: {node: '>=12.13.0'} hasBin: true + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -925,6 +988,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + columnify@1.6.0: resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==} engines: {node: '>=8.0.0'} @@ -948,6 +1014,12 @@ packages: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} @@ -955,9 +1027,9 @@ packages: resolution: {integrity: sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==} engines: {node: '>=18'} - content-security-policy-parser@0.4.1: - resolution: {integrity: sha512-NNJS8XPnx3OKr/CUOSwDSJw+lWTrZMYnclLKj0Y9CYOfJNJTWLFGPg3u2hYgbXMXKVRkZR2fbyReNQ1mUff/Qg==} - engines: {node: '>=8.0.0'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -977,6 +1049,9 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} + cssom@0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + cssstyle@5.3.1: resolution: {integrity: sha512-g5PC9Aiph9eiczFpcgUhd9S4UUO3F+LHGRIi5NUMZ+4xtoIYbHNZwZnWA2JsFGe8OU8nl4WyaEFiZuGuxlutJQ==} engines: {node: '>=20'} @@ -1039,10 +1114,24 @@ packages: defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + define-lazy-prop@3.0.0: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -1064,6 +1153,18 @@ packages: resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} engines: {node: '>=18'} + dotenv-expand@12.0.3: + resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dotenv@17.2.3: + resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + engines: {node: '>=12'} + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -1087,6 +1188,13 @@ packages: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} @@ -1110,6 +1218,10 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true @@ -1199,14 +1311,16 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1259,6 +1373,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + filesize@11.0.13: + resolution: {integrity: sha512-mYJ/qXKvREuO0uH8LTQJ6v7GsUvVOguqxg2VTwQUkyTPXXRRWPdjuUPVqdBrJQhvci48OHlNGRnux+Slr2Rnvw==} + engines: {node: '>= 10.8.0'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1291,6 +1409,14 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + form-data-encoder@4.1.0: + resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} + engines: {node: '>= 18'} + + formdata-node@6.0.3: + resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} + engines: {node: '>= 18'} + fs-extra@11.3.2: resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} engines: {node: '>=14.14'} @@ -1315,6 +1441,13 @@ packages: resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} engines: {node: '>=18'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + + giget@2.0.0: + resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} + hasBin: true + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -1346,9 +1479,6 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - graceful-fs@4.2.10: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} @@ -1372,6 +1502,9 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -1379,6 +1512,9 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-escaper@3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + htmlparser2@10.0.0: resolution: {integrity: sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==} @@ -1414,6 +1550,9 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -1444,6 +1583,9 @@ packages: resolution: {integrity: sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==} engines: {node: '>=0.10.0'} + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} @@ -1462,6 +1604,14 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1480,6 +1630,10 @@ packages: resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} engines: {node: '>=18'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-npm@6.1.0: resolution: {integrity: sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1496,13 +1650,29 @@ packages: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-primitive@3.0.1: + resolution: {integrity: sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==} + engines: {node: '>=0.10.0'} + is-relative@0.1.3: resolution: {integrity: sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==} engines: {node: '>=0.10.0'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-utf8@0.2.1: resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} @@ -1523,6 +1693,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -1542,6 +1716,10 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + jose@5.9.6: resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} @@ -1570,6 +1748,10 @@ packages: json-merge-patch@1.0.2: resolution: {integrity: sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==} + json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1579,6 +1761,11 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} @@ -1588,6 +1775,10 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + ky@1.12.0: resolution: {integrity: sha512-YRLmSUHCwOJRBMArtqMRLOmO7fewn3yOoui6aB8ERkRVXupa0UiaQaKbIXteMt4jUElhbdqTMsLFHs8APxxUoQ==} engines: {node: '>=18'} @@ -1606,6 +1797,27 @@ packages: lighthouse-logger@2.0.2: resolution: {integrity: sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==} + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + linkedom@0.18.12: + resolution: {integrity: sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==} + engines: {node: '>=16'} + peerDependencies: + canvas: '>= 2' + peerDependenciesMeta: + canvas: + optional: true + + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} + engines: {node: '>=18.0.0'} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1613,6 +1825,14 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -1636,6 +1856,9 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + many-keys-map@2.0.1: + resolution: {integrity: sha512-DHnZAD4phTbZ+qnJdjoNEVU1NecYoSdbOOoVmTDH46AuxDkEVh3MxTVpXq10GtcTC6mndN9dkv1rNfpjRcLnOw==} + marky@1.3.0: resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} @@ -1650,6 +1873,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1664,6 +1895,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -1675,6 +1909,10 @@ packages: resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + nano-spawn@1.0.3: + resolution: {integrity: sha512-jtpsQDetTnvS2Ts1fiRdci5rx0VYws5jGyC+4IYOTnIQ/wwdf6JdomlHBwqC3bJYOvaKu0C2GSZ1A60anrYpaA==} + engines: {node: '>=20.17'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1683,6 +1921,9 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -1690,9 +1931,24 @@ packages: node-notifier@10.0.1: resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nypm@0.6.2: + resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + on-exit-leak-free@2.1.2: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} @@ -1700,14 +1956,26 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + open@10.2.0: resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} engines: {node: '>=18'} + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + os-shim@0.1.3: resolution: {integrity: sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==} engines: {node: '>= 0.4.0'} @@ -1734,6 +2002,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + parse-json@8.3.0: resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} engines: {node: '>=18'} @@ -1776,6 +2048,9 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + perfect-debounce@2.0.0: + resolution: {integrity: sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1797,6 +2072,16 @@ packages: resolution: {integrity: sha512-+YIodBB9sxcWeR8PrXC2K3gEDyfkUuVEITOcbqrfcj+z5QW4ioIcqZfYFbrLTYLsmAwunbS7nfU/dpBB6PZc1g==} hasBin: true + pino@9.7.0: + resolution: {integrity: sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg==} + hasBin: true + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -1824,9 +2109,17 @@ packages: resolution: {integrity: sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==} engines: {node: '>=6'} + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + publish-browser-extension@3.0.3: + resolution: {integrity: sha512-cBINZCkLo7YQaGoUvEHthZ0sDzgJQht28IS+SFMT2omSNhGsPiVNRkWir3qLiTrhGhW9Ci2KVHpA1QAMoBdL2g==} + hasBin: true + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1835,12 +2128,18 @@ packages: resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} engines: {node: '>=12.20'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + rc9@2.1.2: + resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -1848,6 +2147,10 @@ packages: readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} @@ -1872,10 +2175,17 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -1913,6 +2223,9 @@ packages: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -1923,6 +2236,10 @@ packages: engines: {node: '>=10'} hasBin: true + set-value@4.1.0: + resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} + engines: {node: '>=11.0'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -1951,6 +2268,17 @@ packages: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} @@ -1965,6 +2293,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + spawn-sync@1.0.15: resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} @@ -1981,6 +2313,10 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2024,6 +2360,10 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-json-comments@5.0.2: + resolution: {integrity: sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==} + engines: {node: '>=14.16'} + strip-json-comments@5.0.3: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} @@ -2064,6 +2404,9 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -2113,15 +2456,8 @@ packages: peerDependencies: typescript: '>=4.8.4' - tsconfck@3.1.6: - resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -2131,6 +2467,10 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -2150,6 +2490,12 @@ packages: engines: {node: '>=14.17'} hasBin: true + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uhyphen@0.2.0: + resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} + undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -2160,10 +2506,22 @@ packages: resolution: {integrity: sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==} engines: {node: '>=20.18.1'} + unimport@5.5.0: + resolution: {integrity: sha512-/JpWMG9s1nBSlXJAQ8EREFTFy3oy6USFd8T6AoBaw1q2GGcF4R9yp3ofg32UODZlYEO5VD0EWE1RpI9XDWyPYg==} + engines: {node: '>=18.12.0'} + universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + + unplugin@2.3.10: + resolution: {integrity: sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==} + engines: {node: '>=18.12.0'} + upath@2.0.1: resolution: {integrity: sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==} engines: {node: '>=4'} @@ -2187,14 +2545,6 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite-tsconfig-paths@5.1.4: - resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true - vite@7.1.10: resolution: {integrity: sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2274,6 +2624,10 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-ext-run@0.2.4: + resolution: {integrity: sha512-rQicL7OwuqWdQWI33JkSXKcp7cuv1mJG8u3jRQwx/8aDsmhbTHs9ZRmNYOL+LX0wX8edIEQX8jj4bB60GoXtKA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + web-ext@9.0.0: resolution: {integrity: sha512-QheVP1seAMB5EOnTxlR8mOgQU85ik44K6FedEzqmOEq9kpCy1NrycekMw1mk8qwlkeN0RbJmEK65NIDCRthy1Q==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -2283,6 +2637,9 @@ packages: resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -2361,6 +2718,10 @@ packages: resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} engines: {node: '>=18'} + wxt@0.20.11: + resolution: {integrity: sha512-DqqHc/5COs8GR21ii99bANXf/mu6zuDpiXFV1YKNsqO5/PvkrCx5arY0aVPL5IATsuacAnNzdj4eMc1qbzS53Q==} + hasBin: true + xdg-basedir@5.1.0: resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} engines: {node: '>=12'} @@ -2402,8 +2763,25 @@ packages: zip-dir@2.0.0: resolution: {integrity: sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==} + zod@4.1.12: + resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + snapshots: + '@1natsu/wait-element@4.1.2': + dependencies: + defu: 6.1.4 + many-keys-map: 2.0.1 + + '@aklinker1/rollup-plugin-visualizer@5.12.0(rollup@4.52.5)': + dependencies: + open: 8.4.2 + picomatch: 2.3.1 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.52.5 + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -2441,6 +2819,8 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/runtime@7.28.2': {} + '@babel/runtime@7.28.4': {} '@babel/types@7.28.4': @@ -2573,9 +2953,9 @@ snapshots: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0)': + '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@2.6.1))': dependencies: - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} @@ -2660,6 +3040,12 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -2676,6 +3062,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} @@ -2784,25 +3175,10 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true - '@samrum/vite-plugin-web-extension@5.1.1(vite@7.1.10(@types/node@24.8.1))': - dependencies: - '@types/chrome': 0.0.233 - '@types/etag': 1.8.4 - content-security-policy-parser: 0.4.1 - etag: 1.8.1 - fs-extra: 11.3.2 - magic-string: 0.30.19 - vite: 7.1.10(@types/node@24.8.1) - '@types/chai@5.2.2': dependencies: '@types/deep-eql': 4.0.2 - '@types/chrome@0.0.233': - dependencies: - '@types/filesystem': 0.0.36 - '@types/har-format': 1.2.16 - '@types/chrome@0.1.24': dependencies: '@types/filesystem': 0.0.36 @@ -2812,10 +3188,6 @@ snapshots: '@types/estree@1.0.8': {} - '@types/etag@1.8.4': - dependencies: - '@types/node': 24.8.1 - '@types/filesystem@0.0.36': dependencies: '@types/filewriter': 0.0.33 @@ -2848,15 +3220,15 @@ snapshots: dependencies: '@types/node': 24.8.1 - '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0)(typescript@5.9.3))(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.46.1 - '@typescript-eslint/type-utils': 8.46.1(eslint@9.38.0)(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/type-utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.1 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -2865,14 +3237,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.46.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.46.1 '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.46.1 debug: 4.4.3 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2895,13 +3267,13 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/type-utils@8.46.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.3 - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.3) typescript: 5.9.3 transitivePeerDependencies: @@ -2925,13 +3297,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.46.1(eslint@9.38.0)(typescript@5.9.3)': + '@typescript-eslint/utils@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) '@typescript-eslint/scope-manager': 8.46.1 '@typescript-eslint/types': 8.46.1 '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -2958,7 +3330,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jsdom@27.0.1(postcss@8.5.6)) + vitest: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6)) transitivePeerDependencies: - supports-color @@ -2970,13 +3342,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.10(@types/node@24.8.1))': + '@vitest/mocker@3.2.4(vite@7.1.10(@types/node@24.8.1)(jiti@2.6.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.19 optionalDependencies: - vite: 7.1.10(@types/node@24.8.1) + vite: 7.1.10(@types/node@24.8.1)(jiti@2.6.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -3007,7 +3379,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jsdom@27.0.1(postcss@8.5.6)) + vitest: 3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6)) '@vitest/utils@3.2.4': dependencies: @@ -3015,6 +3387,27 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 + '@webext-core/fake-browser@1.3.2': + dependencies: + lodash.merge: 4.6.2 + + '@webext-core/isolated-element@1.1.2': + dependencies: + is-potential-custom-element-name: 1.0.1 + + '@webext-core/match-patterns@1.0.3': {} + + '@wxt-dev/browser@0.1.4': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.16 + + '@wxt-dev/storage@1.2.6': + dependencies: + '@wxt-dev/browser': 0.1.4 + async-mutex: 0.5.0 + dequal: 2.0.3 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -3088,6 +3481,10 @@ snapshots: dependencies: string-width: 4.2.3 + ansi-escapes@7.1.1: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -3112,6 +3509,10 @@ snapshots: estree-walker: 3.0.3 js-tokens: 9.0.1 + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + async@3.2.6: {} atomic-sleep@1.0.0: {} @@ -3163,6 +3564,23 @@ snapshots: dependencies: run-applescript: 7.1.0 + c12@3.3.1(magicast@0.3.5): + dependencies: + chokidar: 4.0.3 + confbox: 0.2.2 + defu: 6.1.4 + dotenv: 17.2.3 + exsolve: 1.0.7 + 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 + optionalDependencies: + magicast: 0.3.5 + cac@6.7.14: {} callsites@3.1.0: {} @@ -3209,6 +3627,10 @@ snapshots: undici: 7.16.0 whatwg-mimetype: 4.0.0 + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + chrome-launcher@1.2.0: dependencies: '@types/node': 24.8.1 @@ -3218,8 +3640,25 @@ snapshots: transitivePeerDependencies: - supports-color + ci-info@4.3.1: {} + + citty@0.1.6: + dependencies: + consola: 3.4.2 + cli-boxes@3.0.0: {} + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-spinners@2.9.2: {} + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -3234,6 +3673,8 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + columnify@1.6.0: dependencies: strip-ansi: 6.0.1 @@ -3256,6 +3697,10 @@ snapshots: readable-stream: 2.3.8 typedarray: 0.0.6 + confbox@0.1.8: {} + + confbox@0.2.2: {} + config-chain@1.1.13: dependencies: ini: 1.3.8 @@ -3268,7 +3713,7 @@ snapshots: graceful-fs: 4.2.11 xdg-basedir: 5.1.0 - content-security-policy-parser@0.4.1: {} + consola@3.4.2: {} core-util-is@1.0.3: {} @@ -3293,6 +3738,8 @@ snapshots: css-what@6.2.2: {} + cssom@0.5.0: {} + cssstyle@5.3.1(postcss@8.5.6): dependencies: '@asamuzakjp/css-color': 4.0.5 @@ -3339,8 +3786,16 @@ snapshots: dependencies: clone: 1.0.4 + define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + defu@6.1.4: {} + + dequal@2.0.3: {} + + destr@2.0.5: {} + doctrine@3.0.0: dependencies: esutils: 2.0.3 @@ -3367,6 +3822,14 @@ snapshots: dependencies: type-fest: 4.41.0 + dotenv-expand@12.0.3: + dependencies: + dotenv: 16.6.1 + + dotenv@16.6.1: {} + + dotenv@17.2.3: {} + eastasianwidth@0.2.0: {} emoji-regex@10.6.0: {} @@ -3384,6 +3847,12 @@ snapshots: entities@6.0.1: {} + environment@1.1.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + es-module-lexer@1.7.0: {} es6-error@4.1.1: {} @@ -3423,22 +3892,24 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@9.38.0): + escape-string-regexp@5.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)): dependencies: - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) eslint-plugin-no-unsanitized@4.1.4(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.38.0))(eslint@9.38.0)(prettier@3.6.2): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1))(prettier@3.6.2): dependencies: - eslint: 9.38.0 + eslint: 9.38.0(jiti@2.6.1) prettier: 3.6.2 prettier-linter-helpers: 1.0.0 synckit: 0.11.11 optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.38.0) + eslint-config-prettier: 10.1.8(eslint@9.38.0(jiti@2.6.1)) eslint-scope@7.2.2: dependencies: @@ -3497,9 +3968,9 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@9.38.0: + eslint@9.38.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.1 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.1 @@ -3533,6 +4004,8 @@ snapshots: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 transitivePeerDependencies: - supports-color @@ -3566,10 +4039,12 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} + eventemitter3@5.0.1: {} expect-type@1.2.2: {} + exsolve@1.0.7: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -3614,6 +4089,8 @@ snapshots: dependencies: flat-cache: 4.0.1 + filesize@11.0.13: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -3651,6 +4128,10 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data-encoder@4.1.0: {} + + formdata-node@6.0.3: {} + fs-extra@11.3.2: dependencies: graceful-fs: 4.2.11 @@ -3675,6 +4156,17 @@ snapshots: get-east-asian-width@1.4.0: {} + get-port-please@3.2.0: {} + + giget@2.0.0: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.4 + node-fetch-native: 1.6.7 + nypm: 0.6.2 + pathe: 2.0.3 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -3713,8 +4205,6 @@ snapshots: globals@14.0.0: {} - globrex@0.1.2: {} - graceful-fs@4.2.10: {} graceful-fs@4.2.11: {} @@ -3733,12 +4223,16 @@ snapshots: has-flag@4.0.0: {} + hookable@5.5.3: {} + html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 html-escaper@2.0.2: {} + html-escaper@3.0.3: {} + htmlparser2@10.0.0: dependencies: domelementtype: 2.3.0 @@ -3777,6 +4271,8 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + import-meta-resolve@4.2.0: {} + imurmurhash@0.1.4: {} index-to-position@1.2.0: {} @@ -3798,6 +4294,8 @@ snapshots: dependencies: is-relative: 0.1.3 + is-arrayish@0.2.1: {} + is-docker@2.2.1: {} is-docker@3.0.0: {} @@ -3806,6 +4304,12 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.4.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -3821,6 +4325,8 @@ snapshots: global-directory: 4.0.1 is-path-inside: 4.0.0 + is-interactive@2.0.0: {} + is-npm@6.1.0: {} is-number@7.0.0: {} @@ -3829,10 +4335,20 @@ snapshots: is-path-inside@4.0.0: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-potential-custom-element-name@1.0.1: {} + is-primitive@3.0.1: {} + is-relative@0.1.3: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-utf8@0.2.1: {} is-wsl@2.2.0: @@ -3849,6 +4365,8 @@ snapshots: isexe@2.0.0: {} + isobject@3.0.1: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -3876,6 +4394,8 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 + jiti@2.6.1: {} + jose@5.9.6: {} js-tokens@4.0.0: {} @@ -3920,12 +4440,16 @@ snapshots: dependencies: fast-deep-equal: 3.1.3 + json-parse-even-better-errors@3.0.2: {} + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} json-stable-stringify-without-jsonify@1.0.1: {} + json5@2.2.3: {} + jsonfile@6.2.0: dependencies: universalify: 2.0.1 @@ -3943,6 +4467,8 @@ snapshots: dependencies: json-buffer: 3.0.1 + kleur@3.0.3: {} + ky@1.12.0: {} latest-version@9.0.0: @@ -3965,12 +4491,50 @@ snapshots: transitivePeerDependencies: - supports-color + lines-and-columns@2.0.4: {} + + linkedom@0.18.12: + dependencies: + css-select: 5.2.2 + cssom: 0.5.0 + html-escaper: 3.0.3 + htmlparser2: 10.0.0 + uhyphen: 0.2.0 + + 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.2 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 lodash.merge@4.6.2: {} + log-symbols@6.0.0: + dependencies: + chalk: 5.6.2 + is-unicode-supported: 1.3.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.1.1 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.2 + wrap-ansi: 9.0.2 + loupe@3.2.1: {} lru-cache@10.4.3: {} @@ -3993,6 +4557,8 @@ snapshots: make-error@1.3.6: {} + many-keys-map@2.0.1: {} + marky@1.3.0: {} mdn-data@2.12.2: {} @@ -4004,6 +4570,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mimic-function@5.0.1: {} + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -4016,6 +4588,13 @@ snapshots: minipass@7.1.2: {} + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + mrmime@2.0.1: {} ms@2.1.3: {} @@ -4027,10 +4606,14 @@ snapshots: array-union: 3.0.1 minimatch: 3.1.2 + nano-spawn@1.0.3: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} + node-fetch-native@1.6.7: {} + node-forge@1.3.1: {} node-notifier@10.0.1: @@ -4042,16 +4625,38 @@ snapshots: uuid: 8.3.2 which: 2.0.2 + normalize-path@3.0.0: {} + nth-check@2.1.1: dependencies: boolbase: 1.0.0 + nypm@0.6.2: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 2.3.0 + tinyexec: 1.0.1 + + ofetch@1.4.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.1 + + ohash@2.0.11: {} + on-exit-leak-free@2.1.2: {} once@1.4.0: dependencies: wrappy: 1.0.2 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + open@10.2.0: dependencies: default-browser: 5.2.1 @@ -4059,6 +4664,12 @@ snapshots: is-inside-container: 1.0.0 wsl-utils: 0.1.0 + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -4068,6 +4679,18 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.2 + os-shim@0.1.3: {} p-limit@3.1.0: @@ -4093,6 +4716,14 @@ snapshots: dependencies: callsites: 3.1.0 + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.4 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + parse-json@8.3.0: dependencies: '@babel/code-frame': 7.27.1 @@ -4133,6 +4764,8 @@ snapshots: pend@1.2.0: {} + perfect-debounce@2.0.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -4159,6 +4792,32 @@ snapshots: sonic-boom: 4.2.0 thread-stream: 3.1.0 + pino@9.7.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -4181,18 +4840,41 @@ snapshots: dependencies: make-error: 1.3.6 + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + proto-list@1.2.4: {} + 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: 4.1.12 + punycode@2.3.1: {} pupa@3.3.0: dependencies: escape-goat: 4.0.0 + quansync@0.2.11: {} + queue-microtask@1.2.3: {} quick-format-unescaped@4.0.4: {} + rc9@2.1.2: + dependencies: + defu: 6.1.4 + destr: 2.0.5 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -4210,6 +4892,8 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readdirp@4.1.2: {} + real-require@0.2.0: {} registry-auth-token@5.1.0: @@ -4226,8 +4910,15 @@ snapshots: resolve-from@4.0.0: {} + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + reusify@1.1.0: {} + rfdc@1.4.1: {} + rimraf@3.0.2: dependencies: glob: 7.2.3 @@ -4280,10 +4971,17 @@ snapshots: dependencies: xmlchars: 2.2.0 + scule@1.3.0: {} + semver@7.7.2: {} semver@7.7.3: {} + set-value@4.1.0: + dependencies: + is-plain-object: 2.0.4 + is-primitive: 3.0.1 + setimmediate@1.0.5: {} shebang-command@2.0.0: @@ -4306,6 +5004,18 @@ snapshots: mrmime: 2.0.1 totalist: 3.0.1 + sisteransi@1.0.5: {} + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 @@ -4319,6 +5029,8 @@ snapshots: source-map@0.6.1: {} + source-map@0.7.6: {} + spawn-sync@1.0.15: dependencies: concat-stream: 1.6.2 @@ -4334,6 +5046,8 @@ snapshots: std-env@3.10.0: {} + stdin-discarder@0.2.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -4379,6 +5093,8 @@ snapshots: strip-json-comments@3.1.1: {} + strip-json-comments@5.0.2: {} + strip-json-comments@5.0.3: {} strip-literal@3.1.0: @@ -4415,6 +5131,8 @@ snapshots: tinyexec@0.3.2: {} + tinyexec@1.0.1: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -4452,9 +5170,7 @@ snapshots: dependencies: typescript: 5.9.3 - tsconfck@3.1.6(typescript@5.9.3): - optionalDependencies: - typescript: 5.9.3 + tslib@2.8.1: {} type-check@0.4.0: dependencies: @@ -4462,31 +5178,66 @@ snapshots: type-fest@0.20.2: {} + type-fest@3.13.1: {} + type-fest@4.41.0: {} typedarray@0.0.6: {} - typescript-eslint@8.46.1(eslint@9.38.0)(typescript@5.9.3): + typescript-eslint@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0)(typescript@5.9.3))(eslint@9.38.0)(typescript@5.9.3) - '@typescript-eslint/parser': 8.46.1(eslint@9.38.0)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.46.1(@typescript-eslint/parser@8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.46.1(typescript@5.9.3) - '@typescript-eslint/utils': 8.46.1(eslint@9.38.0)(typescript@5.9.3) - eslint: 9.38.0 + '@typescript-eslint/utils': 8.46.1(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.38.0(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.9.3: {} + ufo@1.6.1: {} + + uhyphen@0.2.0: {} + undici-types@6.21.0: {} undici-types@7.14.0: {} undici@7.16.0: {} + unimport@5.5.0: + dependencies: + acorn: 8.15.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.1.2 + magic-string: 0.30.19 + mlly: 1.8.0 + pathe: 2.0.3 + picomatch: 4.0.3 + pkg-types: 2.3.0 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.15 + unplugin: 2.3.10 + unplugin-utils: 0.3.1 + universalify@2.0.1: {} + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.3 + + unplugin@2.3.10: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + upath@2.0.1: {} update-notifier@7.3.1: @@ -4510,13 +5261,13 @@ snapshots: uuid@8.3.2: {} - vite-node@3.2.4(@types/node@24.8.1): + vite-node@3.2.4(@types/node@24.8.1)(jiti@2.6.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.10(@types/node@24.8.1) + vite: 7.1.10(@types/node@24.8.1)(jiti@2.6.1) transitivePeerDependencies: - '@types/node' - jiti @@ -4531,18 +5282,7 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.10(@types/node@24.8.1)): - dependencies: - debug: 4.4.3 - globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.9.3) - optionalDependencies: - vite: 7.1.10(@types/node@24.8.1) - transitivePeerDependencies: - - supports-color - - typescript - - vite@7.1.10(@types/node@24.8.1): + vite@7.1.10(@types/node@24.8.1)(jiti@2.6.1): dependencies: esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) @@ -4553,12 +5293,13 @@ snapshots: optionalDependencies: '@types/node': 24.8.1 fsevents: 2.3.3 + jiti: 2.6.1 - vitest@3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jsdom@27.0.1(postcss@8.5.6)): + vitest@3.2.4(@types/node@24.8.1)(@vitest/ui@3.2.4)(happy-dom@20.0.5)(jiti@2.6.1)(jsdom@27.0.1(postcss@8.5.6)): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.10(@types/node@24.8.1)) + '@vitest/mocker': 3.2.4(vite@7.1.10(@types/node@24.8.1)(jiti@2.6.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -4576,8 +5317,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.10(@types/node@24.8.1) - vite-node: 3.2.4(@types/node@24.8.1) + vite: 7.1.10(@types/node@24.8.1)(jiti@2.6.1) + vite-node: 3.2.4(@types/node@24.8.1)(jiti@2.6.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.8.1 @@ -4611,6 +5352,31 @@ snapshots: dependencies: defaults: 1.0.4 + 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 + transitivePeerDependencies: + - supports-color + web-ext@9.0.0: dependencies: '@babel/runtime': 7.28.4 @@ -4649,6 +5415,8 @@ snapshots: webidl-conversions@8.0.0: {} + webpack-virtual-modules@0.6.2: {} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 @@ -4714,6 +5482,69 @@ snapshots: dependencies: is-wsl: 3.1.0 + wxt@0.20.11(@types/node@24.8.1)(jiti@2.6.1)(rollup@4.52.5): + dependencies: + '@1natsu/wait-element': 4.1.2 + '@aklinker1/rollup-plugin-visualizer': 5.12.0(rollup@4.52.5) + '@webext-core/fake-browser': 1.3.2 + '@webext-core/isolated-element': 1.1.2 + '@webext-core/match-patterns': 1.0.3 + '@wxt-dev/browser': 0.1.4 + '@wxt-dev/storage': 1.2.6 + async-mutex: 0.5.0 + c12: 3.3.1(magicast@0.3.5) + cac: 6.7.14 + chokidar: 4.0.3 + ci-info: 4.3.1 + consola: 3.4.2 + defu: 6.1.4 + dotenv: 17.2.3 + dotenv-expand: 12.0.3 + esbuild: 0.25.11 + fast-glob: 3.3.3 + filesize: 11.0.13 + fs-extra: 11.3.2 + get-port-please: 3.2.0 + giget: 2.0.0 + hookable: 5.5.3 + import-meta-resolve: 4.2.0 + is-wsl: 3.1.0 + json5: 2.2.3 + jszip: 3.10.1 + linkedom: 0.18.12 + magicast: 0.3.5 + minimatch: 10.0.3 + nano-spawn: 1.0.3 + normalize-path: 3.0.0 + nypm: 0.6.2 + ohash: 2.0.11 + open: 10.2.0 + ora: 8.2.0 + perfect-debounce: 2.0.0 + picocolors: 1.1.1 + prompts: 2.4.2 + publish-browser-extension: 3.0.3 + scule: 1.3.0 + unimport: 5.5.0 + vite: 7.1.10(@types/node@24.8.1)(jiti@2.6.1) + vite-node: 3.2.4(@types/node@24.8.1)(jiti@2.6.1) + web-ext-run: 0.2.4 + transitivePeerDependencies: + - '@types/node' + - canvas + - jiti + - less + - lightningcss + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + xdg-basedir@5.1.0: {} xml-name-validator@5.0.0: {} @@ -4752,3 +5583,5 @@ snapshots: dependencies: async: 3.2.6 jszip: 3.10.1 + + zod@4.1.12: {} diff --git a/public/content-styles.css b/public/content-styles.css new file mode 100644 index 0000000..cdd2461 --- /dev/null +++ b/public/content-styles.css @@ -0,0 +1,22 @@ +/* Optional: Add a floating export button on Claude.ai pages */ +.claude-exporter-button { + position: fixed; + bottom: 20px; + right: 20px; + z-index: 9999; + background: #5436da; + color: white; + border: none; + border-radius: 50%; + width: 60px; + height: 60px; + font-size: 24px; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + transition: all 0.3s; +} + +.claude-exporter-button:hover { + background: #4329b8; + transform: scale(1.1); +} diff --git a/public/icon128.png b/public/icon128.png new file mode 100644 index 0000000..23a9b5a Binary files /dev/null and b/public/icon128.png differ diff --git a/public/icon16.png b/public/icon16.png new file mode 100644 index 0000000..06b49c2 Binary files /dev/null and b/public/icon16.png differ diff --git a/public/icon48.png b/public/icon48.png new file mode 100644 index 0000000..6bad8be Binary files /dev/null and b/public/icon48.png differ diff --git a/public/popup-header.png b/public/popup-header.png new file mode 100644 index 0000000..de149e6 Binary files /dev/null and b/public/popup-header.png differ diff --git a/src/chrome/scripts/popup.ts b/src/chrome/scripts/popup.ts index 57ceb8a..cbec0b7 100644 --- a/src/chrome/scripts/popup.ts +++ b/src/chrome/scripts/popup.ts @@ -170,7 +170,9 @@ async function handleExportCurrent(): Promise { * Handle browse conversations button */ function handleBrowseConversations(): void { - void chrome.tabs.create({ url: chrome.runtime.getURL('src/chrome/scripts/browse.html') }); + void chrome.tabs.create({ + url: chrome.runtime.getURL('src/chrome/scripts/browse.html'), + }); } /** diff --git a/src/firefox/scripts/popup.ts b/src/firefox/scripts/popup.ts index 97b1ef7..88dd716 100644 --- a/src/firefox/scripts/popup.ts +++ b/src/firefox/scripts/popup.ts @@ -168,7 +168,9 @@ async function handleExportCurrent(): Promise { * Handle browse conversations button */ function handleBrowseConversations(): void { - void browser.tabs.create({ url: browser.runtime.getURL('src/firefox/scripts/browse.html') }); + void browser.tabs.create({ + url: browser.runtime.getURL('src/firefox/scripts/browse.html'), + }); } /** diff --git a/tsconfig.json b/tsconfig.json index 496b7df..0f776db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,25 +38,13 @@ /* Path Mapping */ "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": ["entrypoints/*"], + "~/*": ["src/*"] }, /* Browser Extension Types */ "types": ["firefox-webext-browser", "vitest/globals"] }, - "include": [ - "src/**/*.ts", - "vite.config.ts", - "vite.content.config.ts", - "vite.content-chrome.config.ts", - "vite.content-firefox.config.ts", - "eslint.config.js" - ], - "exclude": [ - "node_modules", - "dist", - "src/**/*.js", - "src/chrome/scripts/**/*", - "src/firefox/scripts/**/*" - ] + "include": ["entrypoints/**/*.ts", "src/**/*.ts", "wxt.config.ts", "*.config.ts", ".wxt/types/**/*.d.ts"], + "exclude": ["node_modules", "dist", ".wxt/**/*", "!.wxt/types/**/*.d.ts"] } diff --git a/type-check/.wxt/tsconfig.json b/type-check/.wxt/tsconfig.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/type-check/.wxt/tsconfig.json @@ -0,0 +1 @@ +{} diff --git a/vite.config.ts b/vite.config.ts deleted file mode 100644 index 324b038..0000000 --- a/vite.config.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { defineConfig } from 'vite'; -import webExtension from '@samrum/vite-plugin-web-extension'; -import tsconfigPaths from 'vite-tsconfig-paths'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; -import { readFileSync } from 'fs'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -// Determine target platform from mode or environment -function getTargetFromMode(mode: string): 'firefox' | 'chrome' { - return mode === 'firefox' ? 'firefox' : 'chrome'; -} - -export default defineConfig(({ mode }) => { - const target = getTargetFromMode(mode); - const manifestPath = resolve(__dirname, `src/${target}/manifest.json`); - const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as Record< - string, - unknown - >; - - return { - plugins: [ - tsconfigPaths(), - webExtension({ - manifest, - useDynamicUrlWebAccessibleResources: false, - additionalInputs: { - html: [ - `src/${target}/scripts/browse.html`, - `src/${target}/scripts/options.html`, - ], - scripts: [`src/${target}/scripts/content.ts`], - }, - }), - ], - resolve: { - alias: { - '@': resolve(__dirname, 'src'), - }, - }, - build: { - outDir: `dist/${target}`, - emptyOutDir: true, - sourcemap: true, - rollupOptions: { - output: { - entryFileNames: '[name].js', - chunkFileNames: '[name].js', - assetFileNames: '[name].[ext]', - }, - }, - }, - test: { - globals: true, - environment: 'happy-dom', - setupFiles: ['./src/tests/setup.ts'], - include: ['src/tests/**/*.test.ts'], - coverage: { - provider: 'v8', - reporter: ['text', 'json', 'html'], - exclude: [ - 'node_modules/', - 'dist/', - 'src/tests/', - '**/*.d.ts', - '**/*.config.*', - '**/mockData', - ], - }, - }, - }; -}); diff --git a/vite.content-chrome.config.ts b/vite.content-chrome.config.ts deleted file mode 100644 index 47b7ff2..0000000 --- a/vite.content-chrome.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineConfig } from 'vite'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export default defineConfig({ - build: { - outDir: 'dist-temp-content-chrome', - emptyOutDir: true, - lib: { - entry: resolve(__dirname, 'src/chrome/scripts/content.ts'), - name: 'ContentScript', - formats: ['iife'], - fileName: () => 'content.js', - }, - rollupOptions: { - output: { - extend: true, - }, - }, - }, -}); diff --git a/vite.content-firefox.config.ts b/vite.content-firefox.config.ts deleted file mode 100644 index 84b9097..0000000 --- a/vite.content-firefox.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineConfig } from 'vite'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export default defineConfig({ - build: { - outDir: 'dist-temp-content-firefox', - emptyOutDir: true, - lib: { - entry: resolve(__dirname, 'src/firefox/scripts/content.ts'), - name: 'ContentScript', - formats: ['iife'], - fileName: () => 'content.js', - }, - rollupOptions: { - output: { - extend: true, - }, - }, - }, -}); diff --git a/vite.content.config.ts b/vite.content.config.ts deleted file mode 100644 index fbb126f..0000000 --- a/vite.content.config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { defineConfig } from 'vite'; -import { resolve, dirname } from 'path'; -import { fileURLToPath } from 'url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); - -export default defineConfig({ - build: { - outDir: 'dist-temp-content', - emptyOutDir: true, - lib: { - entry: resolve(__dirname, 'src/content.ts'), - name: 'ContentScript', - formats: ['iife'], - fileName: () => 'content.js', - }, - rollupOptions: { - output: { - extend: true, - }, - }, - }, -}); diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..9d9fbf8 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,31 @@ +/// +import { defineConfig } from 'vitest/config'; +import { resolve } from 'path'; + +export default defineConfig({ + resolve: { + alias: { + '~': resolve(__dirname, 'src'), + }, + }, + test: { + globals: true, + environment: 'happy-dom', + setupFiles: ['./src/tests/setup.ts'], + include: ['src/tests/**/*.test.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: [ + 'node_modules/', + 'dist/', + '.wxt/', + '.output/', + 'src/tests/', + '**/*.d.ts', + '**/*.config.*', + '**/mockData', + ], + }, + }, +}); diff --git a/wxt.config.ts b/wxt.config.ts new file mode 100644 index 0000000..a06f485 --- /dev/null +++ b/wxt.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from 'wxt'; +import { resolve } from 'path'; + +// https://wxt.dev/api/config.html +export default defineConfig({ + manifest: { + name: 'Claude Conversation Exporter', + description: 'Export your Claude.ai conversations with full message history', + permissions: ['activeTab', 'storage'], + host_permissions: ['https://claude.ai/*'], + }, + imports: false, + vite: () => ({ + resolve: { + alias: { + '~': resolve(__dirname, 'src'), + }, + }, + }), + runner: { + startUrls: ['https://claude.ai'], + }, +});