spot: refactor types, update wxt core, use global browser

This commit is contained in:
nick-delirium 2024-09-05 10:47:15 +02:00
parent a2b0366267
commit 4563f90eee
No known key found for this signature in database
GPG key ID: 93ABD695DF5FDBA0
8 changed files with 269 additions and 213 deletions

5
spot/declarations.d.ts vendored Normal file
View file

@ -0,0 +1,5 @@
declare global {
function defineBackground(cb: () => any): any
const chrome: typeof import('wxt/browser')['browser']
const browser: typeof import('wxt/browser')['browser']
}

View file

@ -1,7 +1,8 @@
import { WebRequest } from "webextension-polyfill";
export default defineBackground(() => {
const CHECK_INT = 60 * 1000;
const PING_INT = 30 * 1000
const PING_INT = 30 * 1000;
const messages = {
popup: {
from: {
@ -45,7 +46,7 @@ export default defineBackground(() => {
micStatus: "content:mic-status",
unmount: "content:unmount",
notification: "notif:display",
updateErrorEvents: "content:error-events"
updateErrorEvents: "content:error-events",
},
},
injected: {
@ -140,12 +141,12 @@ export default defineBackground(() => {
function setJWTToken(token: string) {
jwtToken = token;
if (token && token.length) {
chrome.storage.local.set({ jwtToken: token });
void browser.storage.local.set({ jwtToken: token });
void browser.runtime.sendMessage({
type: messages.popup.loginExist,
});
} else {
chrome.storage.local.remove("jwtToken");
void browser.storage.local.remove("jwtToken");
void browser.runtime.sendMessage({
type: messages.popup.to.noLogin,
});
@ -165,7 +166,7 @@ export default defineBackground(() => {
let slackChannels: { name: string; webhookId: number }[] = [];
const refreshToken = async () => {
const data = await chrome.storage.local.get(["jwtToken", "settings"])
const data = await browser.storage.local.get(["jwtToken", "settings"]);
if (!data.settings) {
return;
}
@ -185,7 +186,7 @@ export default defineBackground(() => {
},
});
if (!resp.ok) {
chrome.storage.local.remove("jwtToken");
void browser.storage.local.remove("jwtToken");
setJWTToken("");
void browser.runtime.sendMessage({
type: messages.popup.to.noLogin,
@ -216,13 +217,14 @@ export default defineBackground(() => {
};
let refreshInt: any;
let pingInt: any;
chrome.storage.local.get(["jwtToken", "settings"]).then(async (data: any) => {
browser.storage.local
.get(["jwtToken", "settings"])
.then(async (data: any) => {
if (!data.settings) {
chrome.storage.local.set({ settings });
void browser.storage.local.set({ settings });
return;
}
const newObj = Object.assign(settings, data.settings);
settings = newObj;
settings = Object.assign(settings, data.settings);
if (!data.jwtToken) {
console.error("No JWT token found in storage");
@ -249,14 +251,13 @@ export default defineBackground(() => {
if (!pingInt) {
pingInt = setInterval(() => {
void pingJWT();
}, PING_INT)
}, PING_INT);
}
}
});
async function pingJWT(): Promise<void> {
const data = await chrome.storage.local.get(["jwtToken", "settings"])
console.log(data, 'ping')
const data = await browser.storage.local.get(["jwtToken", "settings"]);
if (!data.settings) {
return;
}
@ -275,16 +276,17 @@ export default defineBackground(() => {
headers: {
Authorization: `Bearer ${jwtToken}`,
},
})
});
if (!r.ok) {
void refreshToken()
void refreshToken();
}
} catch (e) {
void refreshToken()
void refreshToken();
}
}
let lastReq: Record<string, any> | null = null;
// @ts-ignore
browser.runtime.onMessage.addListener((request, sender, respond) => {
if (request.type === messages.content.from.contentReady) {
if (sender?.tab?.id) {
@ -303,7 +305,7 @@ export default defineBackground(() => {
activeTabId: null,
area: null,
recording: REC_STATE.stopped,
audioPerm: request.permissions ? request.mic ? 2 : 1 : 0,
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
};
if (request.area === "tab") {
browser.tabs
@ -321,7 +323,7 @@ export default defineBackground(() => {
area: request.area,
mic: request.mic,
audioId: request.selectedAudioDevice,
audioPerm: request.permissions ? request.mic ? 2 : 1 : 0,
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
});
});
} else {
@ -330,13 +332,13 @@ export default defineBackground(() => {
area: request.area,
mic: request.mic,
audioId: request.selectedAudioDevice,
audioPerm: request.permissions ? request.mic ? 2 : 1 : 0,
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
});
}
}
if (request.type === messages.content.from.countEnd) {
if (!jwtToken) {
chrome.storage.local.get("jwtToken", (data: any) => {
browser.storage.local.get("jwtToken").then((data: any) => {
if (!data.jwtToken) {
console.error("No JWT token found");
void browser.runtime.sendMessage({
@ -369,6 +371,7 @@ export default defineBackground(() => {
settings.consoleLogs,
() => recordingState.recording,
);
// @ts-ignore this is false positive
respond(true);
}
if (!recordingState.activeTabId) {
@ -407,6 +410,7 @@ export default defineBackground(() => {
onStop = hook;
},
).then(() => {
// @ts-ignore this is false positive
respond(true);
});
return true;
@ -433,7 +437,8 @@ export default defineBackground(() => {
});
}
if (request.type === messages.content.from.checkNewTab) {
chrome.storage.local.get("settings", (data: any) => {
browser.storage.local.get("settings").then((data: any) => {
// @ts-ignore this is false positive
respond(Boolean(data.settings.openInNewTab));
});
@ -462,9 +467,9 @@ export default defineBackground(() => {
}
if (request.type === messages.content.from.setLoginToken) {
setJWTToken(request.token);
chrome.storage.local.get("settings", (data: any) => {
browser.storage.local.get("settings").then((data: any) => {
if (!data.settings) {
chrome.storage.local.set({ settings });
void browser.storage.local.set({ settings });
return;
}
if (!refreshInt) {
@ -475,7 +480,7 @@ export default defineBackground(() => {
if (!pingInt) {
pingInt = setInterval(() => {
void pingJWT();
}, PING_INT)
}, PING_INT);
}
});
}
@ -484,7 +489,7 @@ export default defineBackground(() => {
clearInterval(refreshInt);
}
if (pingInt) {
clearInterval(pingInt)
clearInterval(pingInt);
}
setJWTToken("");
}
@ -497,14 +502,15 @@ export default defineBackground(() => {
if (request.type === messages.popup.from.updateSettings) {
const updatedObject = Object.assign(settings, request.settings);
settings = updatedObject;
if ('ingestPoint' in request.settings) {
setJWTToken("")
if ("ingestPoint" in request.settings) {
setJWTToken("");
}
chrome.storage.local.set({ settings: updatedObject });
void browser.storage.local.set({ settings: updatedObject });
}
if (request.type === messages.content.from.checkRecStatus) {
const id = request.tabId;
if (recordingState.area === "tab" && id !== recordingState.activeTabId) {
// @ts-ignore this is false positive
respond({ status: false });
} else {
browser.runtime
@ -513,6 +519,7 @@ export default defineBackground(() => {
target: "offscreen",
})
.then((r) => {
// @ts-ignore this is false positive
respond({ ...r, state: recordingState.recording });
});
}
@ -586,31 +593,36 @@ export default defineBackground(() => {
activeTabId: null,
area: null,
recording: REC_STATE.stopped,
audioPerm: lastReq.permissions,
audioPerm: lastReq!.permissions,
};
void sendToActiveTab({
type: "content:mount",
area: lastReq.area,
mic: lastReq.mic,
audioId: lastReq.selectedAudioDevice,
audioPerm: lastReq.permissions,
area: lastReq!.area,
mic: lastReq!.mic,
audioId: lastReq!.selectedAudioDevice,
audioPerm: lastReq!.permissions,
});
}
if (request.type === messages.content.from.getErrorEvents) {
const logs = finalSpotObj.logs.filter(
(log) => log.level === "error",
).map(l => ({ title: 'JS Error', time: (l.time - finalSpotObj.startTs)/1000 }))
const network = finalSpotObj.network.filter(
(net) => net.statusCode >= 400 || net.error,
).map(n => ({ title: 'Network Error', time: (n.time - finalSpotObj.startTs)/1000 }))
const logs = finalSpotObj.logs
.filter((log) => log.level === "error")
.map((l) => ({
title: "JS Error",
time: (l.time - finalSpotObj.startTs) / 1000,
}));
const network = finalSpotObj.network
.filter((net) => net.statusCode >= 400 || net.error)
.map((n) => ({
title: "Network Error",
time: (n.time - finalSpotObj.startTs) / 1000,
}));
const errorData = [...logs, ...network]
.sort((a, b) => a.time - b.time)
const errorData = [...logs, ...network].sort((a, b) => a.time - b.time);
void sendToActiveTab({
type: messages.content.to.updateErrorEvents,
errorData,
})
});
}
if (request.type === "ort:stop") {
browser.runtime
@ -621,8 +633,10 @@ export default defineBackground(() => {
.then((r) => {
if (r.status === "full") {
finalSpotObj.duration = r.duration;
// @ts-ignore this is false positive
respond(r);
} else {
// @ts-ignore this is false positive
respond({ status: r.status });
}
});
@ -633,7 +647,7 @@ export default defineBackground(() => {
}
if (request.type === "offscr:video-data-chunk") {
finalSpotObj.duration = request.duration;
sendToActiveTab({
void sendToActiveTab({
type: "content:video-chunk",
data: request.data,
index: request.index,
@ -666,7 +680,7 @@ export default defineBackground(() => {
type: "content:mic-status",
micStatus: micStatus === "on",
});
chrome.runtime.sendMessage({
void browser.runtime.sendMessage({
type: messages.popup.to.micStatus,
status: false,
});
@ -681,7 +695,7 @@ export default defineBackground(() => {
type: "content:mic-status",
micStatus: micStatus === "on",
});
chrome.runtime.sendMessage({
void browser.runtime.sendMessage({
type: messages.popup.to.micStatus,
status: true,
});
@ -712,7 +726,7 @@ export default defineBackground(() => {
finalVideoBase64 += request.part;
finalReady = request.index === request.total - 1;
const getPlatformData = async () => {
const vendor = await chrome.runtime.getPlatformInfo();
const vendor = await browser.runtime.getPlatformInfo();
const platform = `${vendor.os} ${vendor.arch}`;
return { platform };
};
@ -782,7 +796,8 @@ export default defineBackground(() => {
const ingestUrl = safeApiUrl(settings.ingestPoint);
const dataUrl = `${ingestUrl}/spot/v1/spots`;
refreshToken().then((r) => {
refreshToken()
.then((r) => {
if (!r) {
void sendToActiveTab({
type: messages.content.to.notification,
@ -822,10 +837,12 @@ export default defineBackground(() => {
});
}
const { id, mobURL, videoURL } = resp;
const link = settings.ingestPoint.includes("api.openreplay.com")
const link = settings.ingestPoint.includes(
"api.openreplay.com",
)
? "https://app.openreplay.com"
: settings.ingestPoint;
chrome.tabs.create({
void browser.tabs.create({
url: `${link}/view-spot/${id}`,
active: settings.openInNewTab,
});
@ -850,7 +867,7 @@ export default defineBackground(() => {
body: blob,
});
Promise.all([mPromise, vPromise])
.then(async (r) => {
.then(async () => {
const uploadedUrl = `${safeApiUrl(settings.ingestPoint)}/spot/v1/spots/${id}/uploaded`;
void fetch(uploadedUrl, {
method: "POST",
@ -872,12 +889,12 @@ export default defineBackground(() => {
finalSpotObj = defaultSpotObj;
});
})
.catch(e => {
.catch((e) => {
void sendToActiveTab({
type: messages.content.to.notification,
message: `Error saving Spot: ${e.message}`,
});
})
});
});
}
@ -897,11 +914,17 @@ export default defineBackground(() => {
});
void initializeOffscreenDocument();
type TrackedRequest =
type TrackedRequest = {
statusCode: number;
requestHeaders: Record<string, string>;
responseHeaders: Record<string, string>;
} & (
| WebRequest.OnBeforeRequestDetailsType
| WebRequest.OnBeforeSendHeadersDetailsType
| WebRequest.OnCompletedDetailsType
| WebRequest.OnErrorOccurredDetailsType;
| WebRequest.OnErrorOccurredDetailsType
| WebRequest.OnResponseStartedDetailsType
);
interface SpotNetworkRequest {
encodedBodySize: number;
@ -922,20 +945,6 @@ export default defineBackground(() => {
startTs: number;
duration: number;
})[] = [];
const processedRequests: SpotNetworkRequest[] = [];
function parseBody(body: any): string {
if (body instanceof ArrayBuffer) {
return "Binary ArrayBuffer omitted";
}
if (body instanceof Blob) {
return "Binary Blob omitted";
}
try {
return JSON.stringify(body);
} catch (e) {
return "Failed to parse request body";
}
}
function filterHeaders(headers: Record<string, string>) {
const filteredHeaders: Record<string, string> = {};
const privateHs = [
@ -1065,7 +1074,6 @@ export default defineBackground(() => {
};
function startTrackingNetwork() {
rawRequests.length = 0;
processedRequests.length = 0;
browser.webRequest.onBeforeRequest.addListener(
// @ts-ignore
trackOnBefore,
@ -1159,8 +1167,7 @@ export default defineBackground(() => {
[key: string]: any;
}) {
try {
const resp = await browser.runtime.sendMessage(message);
return resp;
return await browser.runtime.sendMessage(message);
} catch (e) {
console.error("Sending to offscreen", e);
}
@ -1366,7 +1373,7 @@ export default defineBackground(() => {
const decodeJwt = (jwt: string): any => {
const base64Url = jwt.split(".")[1];
if (!base64Url) {
return { exp: 0 }
return { exp: 0 };
}
const base64 = base64Url.replace("-", "+").replace("_", "/");
return JSON.parse(atob(base64));
@ -1383,7 +1390,7 @@ export default defineBackground(() => {
return request.statusCode;
}
if (request.error) {
return 0
return 0;
}
return 200;
}

View file

@ -29,7 +29,7 @@ interface IControlsBox {
getInitState: () => string;
onRestart: () => void;
getErrorEvents: () => Promise<any>;
getAudioPerm: () => number,
getAudioPerm: () => 0 | 1 | 2;
}
function ControlsBox({
@ -59,24 +59,37 @@ function ControlsBox({
const onTimerEnd = async (proceed?: boolean) => {
if (!proceed) {
onClose(false);
return changeState(STATES.idle)
return changeState(STATES.idle);
}
let tries = 0;
// changeState(STATES.idle);
await callRecording();
let int = setInterval(() => {
const state = getInitState();
tries++;
if (tries > 200) {
clearInterval(int);
changeState(STATES.idle);
}
if (state !== "count") {
clearInterval(int);
changeState(STATES.recording);
}
}, 100);
}, 50);
};
return (
<div class={"controls"}>
{boxState() === STATES.saving ? (
<SavingControls getErrorEvents={getErrorEvents} getVideoData={getVideoData} onClose={onClose} />
<SavingControls
getErrorEvents={getErrorEvents}
getVideoData={getVideoData}
onClose={onClose}
/>
) : null}
{boxState() === STATES.count ? (
<Countdown getAudioPerm={getAudioPerm} onEnd={onTimerEnd} />
) : null}
{boxState() === STATES.count ? <Countdown getAudioPerm={getAudioPerm} onEnd={onTimerEnd} /> : null}
{boxState() === STATES.recording ? (
<RecordingControls
getAudioPerm={getAudioPerm}

View file

@ -2,7 +2,7 @@ import { createSignal, onCleanup, onMount } from "solid-js";
function Countdown(props: {
onEnd: (proceed?: boolean) => void;
getAudioPerm: () => number;
getAudioPerm: () => 0 | 1 | 2;
}) {
const [count, setCount] = createSignal(3);
@ -39,8 +39,8 @@ function Countdown(props: {
const audioPrompt = {
0: "Microphone permission isn't granted yet.",
1: "Microphone access is enabled. Unmute anytime to add voice over.",
2: "Microphone is enabled."
}
2: "Microphone is enabled.",
};
return (
<div class="modal-overlay">

View file

@ -14,7 +14,7 @@ interface ISavingControls {
comment?: string;
useHook?: boolean;
thumbnail?: string;
crop?: [number, number];
crop: [number, number] | null;
},
) => void;
getVideoData: () => Promise<any>;
@ -51,7 +51,9 @@ function SavingControls({
const [endPos, setEndPos] = createSignal(100);
const [dragging, setDragging] = createSignal<string | null>(null);
const [isTyping, setIsTyping] = createSignal(false);
const [errorEvents, setErrorEvents] = createSignal([]);
const [errorEvents, setErrorEvents] = createSignal<
{ title: string; time: number }[]
>([]);
createEffect(() => {
setTrimBounds([0, 0]);
@ -226,7 +228,7 @@ function SavingControls({
}
setDuration(videoDuration);
setErrorEvents(
errorEvents.filter((ev: { time: number }) => ev.time < videoDuration),
errorEvents().filter((ev: { time: number }) => ev.time < videoDuration),
);
void generateThumbnail();
};

View file

@ -21,8 +21,8 @@ export default defineContentScript({
position: "inline",
anchor: "body",
append: "first",
onMount: (container,s,host) => {
Object.assign(host.style, { visibility: 'visible', display: 'block' });
onMount: (container, s, host) => {
Object.assign(host.style, { visibility: "visible", display: "block" });
return render(
() => (
@ -66,8 +66,9 @@ export default defineContentScript({
});
};
// no perm - muted - unmuted
let audioPerm = 0;
const getAudioPerm = () => audioPerm
type AudioPermState = 0 | 1 | 2;
let audioPerm: AudioPermState = 0;
const getAudioPerm = (): AudioPermState => audioPerm;
let clockStart = 0;
let recState = "stopped";
const getClockStart = () => {
@ -186,7 +187,7 @@ export default defineContentScript({
return;
}
const { name, comment, useHook, thumbnail, crop, blob } = spotObj;
const videoData = await convertBlobToBase64(blob);
const videoData = await convertBlobToBase64(blob!);
const resolution = `${window.screen.width}x${window.screen.height}`;
const browserVersion = getChromeFullVersion();
const spot = {
@ -302,6 +303,7 @@ export default defineContentScript({
}
void browser.runtime.sendMessage({ type: "ort:content-ready" });
// @ts-ignore false positive
browser.runtime.onMessage.addListener((message: any, resp) => {
if (message.type === "content:mount") {
if (recState === "count") return;

View file

@ -31,6 +31,6 @@
"@wxt-dev/module-solid": "^1.1.2",
"daisyui": "^4.12.10",
"typescript": "^5.4.5",
"wxt": "0.19.8"
"wxt": "0.19.9"
}
}

View file

@ -941,11 +941,36 @@
dependencies:
"@babel/types" "^7.20.7"
"@types/chrome@^0.0.269":
version "0.0.269"
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.269.tgz#5bc2a536bb72a3332119742f31b42b5250d39905"
integrity sha512-vF7x8YywnhXX2F06njQ/OE7a3Qeful43C5GUOsUksXWk89WoSFUU3iLeZW8lDpVO9atm8iZIEiLQTRC3H7NOXQ==
dependencies:
"@types/filesystem" "*"
"@types/har-format" "*"
"@types/estree@1.0.5", "@types/estree@^1.0.0":
version "1.0.5"
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
"@types/filesystem@*":
version "0.0.36"
resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.36.tgz#7227c2d76bfed1b21819db310816c7821d303857"
integrity sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==
dependencies:
"@types/filewriter" "*"
"@types/filewriter@*":
version "0.0.33"
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.33.tgz#d9d611db9d9cd99ae4e458de420eeb64ad604ea8"
integrity sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==
"@types/har-format@*":
version "1.2.15"
resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.15.tgz#f352493638c2f89d706438a19a9eb300b493b506"
integrity sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==
"@types/http-cache-semantics@^4.0.2":
version "4.0.4"
resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz"
@ -2100,9 +2125,9 @@ execa@^8.0.1:
signal-exit "^4.1.0"
strip-final-newline "^3.0.0"
execa@^9.3.0:
execa@^9.3.1:
version "9.3.1"
resolved "https://registry.npmjs.org/execa/-/execa-9.3.1.tgz"
resolved "https://registry.yarnpkg.com/execa/-/execa-9.3.1.tgz#09c86ab4dc2ef3de6d34f6568f4bad76ded4fded"
integrity sha512-gdhefCCNy/8tpH/2+ajP9IQc14vXchNdd0weyzSJEFURhRMGncQ+zKFxwjAufIewPEJm9BPOaJnvg2UtlH2gPQ==
dependencies:
"@sindresorhus/merge-streams" "^4.0.0"
@ -3855,9 +3880,9 @@ ora@^6.3.1:
strip-ansi "^7.0.1"
wcwidth "^1.0.1"
ora@^8.0.1:
ora@^8.1.0:
version "8.1.0"
resolved "https://registry.npmjs.org/ora/-/ora-8.1.0.tgz"
resolved "https://registry.yarnpkg.com/ora/-/ora-8.1.0.tgz#c3db2f9f83a2bec9e8ab71fe3b9ae234d65ca3a8"
integrity sha512-GQEkNkH/GHOhPFXcqZs3IDahXEQcQxsSjEkK4KvEEST4t7eNzoMjxTzef+EZ+JluDEV+Raoi3WQ2CflnRdSVnQ==
dependencies:
chalk "^5.3.0"
@ -4981,9 +5006,9 @@ undici-types@~6.19.2:
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz"
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
unimport@^3.9.1:
unimport@^3.11.1:
version "3.11.1"
resolved "https://registry.npmjs.org/unimport/-/unimport-3.11.1.tgz"
resolved "https://registry.yarnpkg.com/unimport/-/unimport-3.11.1.tgz#b750eb69fbacf481e000829a79eb9da19919f33e"
integrity sha512-DuB1Uoq01LrrXTScxnwOoMSlTXxyKcULguFxbLrMDFcE/CO0ZWHpEiyhovN0mycPt7K6luAHe8laqvwvuoeUPg==
dependencies:
"@rollup/pluginutils" "^5.1.0"
@ -5306,12 +5331,13 @@ ws@8.18.0:
resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz"
integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
wxt@0.19.8:
version "0.19.8"
resolved "https://registry.yarnpkg.com/wxt/-/wxt-0.19.8.tgz#b07b98d95a34e5e2d916c3a6a53520e0d0b1b66d"
integrity sha512-Z3LxRuM8rTZ9VOZnQ2DjtRz3uLpZpFzTfBjRVgEOHv1kf/7sRVdeKCY4pUmtimgfR2/NGclYAbCfAVTYQJg0GA==
wxt@0.19.9:
version "0.19.9"
resolved "https://registry.yarnpkg.com/wxt/-/wxt-0.19.9.tgz#b8f7f838cab00d66f4ee22f483c49ad8f6527af8"
integrity sha512-XUbF4JNyx2jTDpXwx2c/esaJcUD2Dr482C2GGenkGRMH2UnerzOIchGCtaa1hb2U8eAed7Akda0yRoMJU0uxUw==
dependencies:
"@aklinker1/rollup-plugin-visualizer" "5.12.0"
"@types/chrome" "^0.0.269"
"@types/webextension-polyfill" "^0.10.7"
"@webext-core/fake-browser" "^1.3.1"
"@webext-core/isolated-element" "^1.1.2"
@ -5325,7 +5351,7 @@ wxt@0.19.8:
defu "^6.1.4"
dequal "^2.0.3"
esbuild "^0.23.0"
execa "^9.3.0"
execa "^9.3.1"
fast-glob "^3.3.2"
filesize "^10.1.4"
fs-extra "^11.2.0"
@ -5344,11 +5370,12 @@ wxt@0.19.8:
nypm "^0.3.9"
ohash "^1.1.3"
open "^10.1.0"
ora "^8.0.1"
ora "^8.1.0"
picocolors "^1.0.1"
prompts "^2.4.2"
publish-browser-extension "^2.1.3"
unimport "^3.9.1"
scule "^1.3.0"
unimport "^3.11.1"
vite "^5.3.5"
vite-node "^2.0.4"
web-ext-run "^0.2.1"