spot: refactor types, update wxt core, use global browser
This commit is contained in:
parent
a2b0366267
commit
4563f90eee
8 changed files with 269 additions and 213 deletions
5
spot/declarations.d.ts
vendored
Normal file
5
spot/declarations.d.ts
vendored
Normal 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']
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { WebRequest } from "webextension-polyfill";
|
import { WebRequest } from "webextension-polyfill";
|
||||||
|
|
||||||
export default defineBackground(() => {
|
export default defineBackground(() => {
|
||||||
const CHECK_INT = 60 * 1000;
|
const CHECK_INT = 60 * 1000;
|
||||||
const PING_INT = 30 * 1000
|
const PING_INT = 30 * 1000;
|
||||||
const messages = {
|
const messages = {
|
||||||
popup: {
|
popup: {
|
||||||
from: {
|
from: {
|
||||||
|
|
@ -45,7 +46,7 @@ export default defineBackground(() => {
|
||||||
micStatus: "content:mic-status",
|
micStatus: "content:mic-status",
|
||||||
unmount: "content:unmount",
|
unmount: "content:unmount",
|
||||||
notification: "notif:display",
|
notification: "notif:display",
|
||||||
updateErrorEvents: "content:error-events"
|
updateErrorEvents: "content:error-events",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
injected: {
|
injected: {
|
||||||
|
|
@ -140,12 +141,12 @@ export default defineBackground(() => {
|
||||||
function setJWTToken(token: string) {
|
function setJWTToken(token: string) {
|
||||||
jwtToken = token;
|
jwtToken = token;
|
||||||
if (token && token.length) {
|
if (token && token.length) {
|
||||||
chrome.storage.local.set({ jwtToken: token });
|
void browser.storage.local.set({ jwtToken: token });
|
||||||
void browser.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
type: messages.popup.loginExist,
|
type: messages.popup.loginExist,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
chrome.storage.local.remove("jwtToken");
|
void browser.storage.local.remove("jwtToken");
|
||||||
void browser.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
type: messages.popup.to.noLogin,
|
type: messages.popup.to.noLogin,
|
||||||
});
|
});
|
||||||
|
|
@ -165,7 +166,7 @@ export default defineBackground(() => {
|
||||||
|
|
||||||
let slackChannels: { name: string; webhookId: number }[] = [];
|
let slackChannels: { name: string; webhookId: number }[] = [];
|
||||||
const refreshToken = async () => {
|
const refreshToken = async () => {
|
||||||
const data = await chrome.storage.local.get(["jwtToken", "settings"])
|
const data = await browser.storage.local.get(["jwtToken", "settings"]);
|
||||||
if (!data.settings) {
|
if (!data.settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +186,7 @@ export default defineBackground(() => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
chrome.storage.local.remove("jwtToken");
|
void browser.storage.local.remove("jwtToken");
|
||||||
setJWTToken("");
|
setJWTToken("");
|
||||||
void browser.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
type: messages.popup.to.noLogin,
|
type: messages.popup.to.noLogin,
|
||||||
|
|
@ -216,13 +217,14 @@ export default defineBackground(() => {
|
||||||
};
|
};
|
||||||
let refreshInt: any;
|
let refreshInt: any;
|
||||||
let pingInt: 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) {
|
if (!data.settings) {
|
||||||
chrome.storage.local.set({ settings });
|
void browser.storage.local.set({ settings });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const newObj = Object.assign(settings, data.settings);
|
settings = Object.assign(settings, data.settings);
|
||||||
settings = newObj;
|
|
||||||
|
|
||||||
if (!data.jwtToken) {
|
if (!data.jwtToken) {
|
||||||
console.error("No JWT token found in storage");
|
console.error("No JWT token found in storage");
|
||||||
|
|
@ -249,14 +251,13 @@ export default defineBackground(() => {
|
||||||
if (!pingInt) {
|
if (!pingInt) {
|
||||||
pingInt = setInterval(() => {
|
pingInt = setInterval(() => {
|
||||||
void pingJWT();
|
void pingJWT();
|
||||||
}, PING_INT)
|
}, PING_INT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function pingJWT(): Promise<void> {
|
async function pingJWT(): Promise<void> {
|
||||||
const data = await chrome.storage.local.get(["jwtToken", "settings"])
|
const data = await browser.storage.local.get(["jwtToken", "settings"]);
|
||||||
console.log(data, 'ping')
|
|
||||||
if (!data.settings) {
|
if (!data.settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -275,16 +276,17 @@ export default defineBackground(() => {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${jwtToken}`,
|
Authorization: `Bearer ${jwtToken}`,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
if (!r.ok) {
|
if (!r.ok) {
|
||||||
void refreshToken()
|
void refreshToken();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
void refreshToken()
|
void refreshToken();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastReq: Record<string, any> | null = null;
|
let lastReq: Record<string, any> | null = null;
|
||||||
|
// @ts-ignore
|
||||||
browser.runtime.onMessage.addListener((request, sender, respond) => {
|
browser.runtime.onMessage.addListener((request, sender, respond) => {
|
||||||
if (request.type === messages.content.from.contentReady) {
|
if (request.type === messages.content.from.contentReady) {
|
||||||
if (sender?.tab?.id) {
|
if (sender?.tab?.id) {
|
||||||
|
|
@ -303,7 +305,7 @@ export default defineBackground(() => {
|
||||||
activeTabId: null,
|
activeTabId: null,
|
||||||
area: null,
|
area: null,
|
||||||
recording: REC_STATE.stopped,
|
recording: REC_STATE.stopped,
|
||||||
audioPerm: request.permissions ? request.mic ? 2 : 1 : 0,
|
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
|
||||||
};
|
};
|
||||||
if (request.area === "tab") {
|
if (request.area === "tab") {
|
||||||
browser.tabs
|
browser.tabs
|
||||||
|
|
@ -321,7 +323,7 @@ export default defineBackground(() => {
|
||||||
area: request.area,
|
area: request.area,
|
||||||
mic: request.mic,
|
mic: request.mic,
|
||||||
audioId: request.selectedAudioDevice,
|
audioId: request.selectedAudioDevice,
|
||||||
audioPerm: request.permissions ? request.mic ? 2 : 1 : 0,
|
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -330,13 +332,13 @@ export default defineBackground(() => {
|
||||||
area: request.area,
|
area: request.area,
|
||||||
mic: request.mic,
|
mic: request.mic,
|
||||||
audioId: request.selectedAudioDevice,
|
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 (request.type === messages.content.from.countEnd) {
|
||||||
if (!jwtToken) {
|
if (!jwtToken) {
|
||||||
chrome.storage.local.get("jwtToken", (data: any) => {
|
browser.storage.local.get("jwtToken").then((data: any) => {
|
||||||
if (!data.jwtToken) {
|
if (!data.jwtToken) {
|
||||||
console.error("No JWT token found");
|
console.error("No JWT token found");
|
||||||
void browser.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
|
|
@ -369,6 +371,7 @@ export default defineBackground(() => {
|
||||||
settings.consoleLogs,
|
settings.consoleLogs,
|
||||||
() => recordingState.recording,
|
() => recordingState.recording,
|
||||||
);
|
);
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond(true);
|
respond(true);
|
||||||
}
|
}
|
||||||
if (!recordingState.activeTabId) {
|
if (!recordingState.activeTabId) {
|
||||||
|
|
@ -407,6 +410,7 @@ export default defineBackground(() => {
|
||||||
onStop = hook;
|
onStop = hook;
|
||||||
},
|
},
|
||||||
).then(() => {
|
).then(() => {
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond(true);
|
respond(true);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -433,7 +437,8 @@ export default defineBackground(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (request.type === messages.content.from.checkNewTab) {
|
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));
|
respond(Boolean(data.settings.openInNewTab));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -462,9 +467,9 @@ export default defineBackground(() => {
|
||||||
}
|
}
|
||||||
if (request.type === messages.content.from.setLoginToken) {
|
if (request.type === messages.content.from.setLoginToken) {
|
||||||
setJWTToken(request.token);
|
setJWTToken(request.token);
|
||||||
chrome.storage.local.get("settings", (data: any) => {
|
browser.storage.local.get("settings").then((data: any) => {
|
||||||
if (!data.settings) {
|
if (!data.settings) {
|
||||||
chrome.storage.local.set({ settings });
|
void browser.storage.local.set({ settings });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!refreshInt) {
|
if (!refreshInt) {
|
||||||
|
|
@ -475,7 +480,7 @@ export default defineBackground(() => {
|
||||||
if (!pingInt) {
|
if (!pingInt) {
|
||||||
pingInt = setInterval(() => {
|
pingInt = setInterval(() => {
|
||||||
void pingJWT();
|
void pingJWT();
|
||||||
}, PING_INT)
|
}, PING_INT);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -484,7 +489,7 @@ export default defineBackground(() => {
|
||||||
clearInterval(refreshInt);
|
clearInterval(refreshInt);
|
||||||
}
|
}
|
||||||
if (pingInt) {
|
if (pingInt) {
|
||||||
clearInterval(pingInt)
|
clearInterval(pingInt);
|
||||||
}
|
}
|
||||||
setJWTToken("");
|
setJWTToken("");
|
||||||
}
|
}
|
||||||
|
|
@ -497,14 +502,15 @@ export default defineBackground(() => {
|
||||||
if (request.type === messages.popup.from.updateSettings) {
|
if (request.type === messages.popup.from.updateSettings) {
|
||||||
const updatedObject = Object.assign(settings, request.settings);
|
const updatedObject = Object.assign(settings, request.settings);
|
||||||
settings = updatedObject;
|
settings = updatedObject;
|
||||||
if ('ingestPoint' in request.settings) {
|
if ("ingestPoint" in request.settings) {
|
||||||
setJWTToken("")
|
setJWTToken("");
|
||||||
}
|
}
|
||||||
chrome.storage.local.set({ settings: updatedObject });
|
void browser.storage.local.set({ settings: updatedObject });
|
||||||
}
|
}
|
||||||
if (request.type === messages.content.from.checkRecStatus) {
|
if (request.type === messages.content.from.checkRecStatus) {
|
||||||
const id = request.tabId;
|
const id = request.tabId;
|
||||||
if (recordingState.area === "tab" && id !== recordingState.activeTabId) {
|
if (recordingState.area === "tab" && id !== recordingState.activeTabId) {
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond({ status: false });
|
respond({ status: false });
|
||||||
} else {
|
} else {
|
||||||
browser.runtime
|
browser.runtime
|
||||||
|
|
@ -513,6 +519,7 @@ export default defineBackground(() => {
|
||||||
target: "offscreen",
|
target: "offscreen",
|
||||||
})
|
})
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond({ ...r, state: recordingState.recording });
|
respond({ ...r, state: recordingState.recording });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -586,31 +593,36 @@ export default defineBackground(() => {
|
||||||
activeTabId: null,
|
activeTabId: null,
|
||||||
area: null,
|
area: null,
|
||||||
recording: REC_STATE.stopped,
|
recording: REC_STATE.stopped,
|
||||||
audioPerm: lastReq.permissions,
|
audioPerm: lastReq!.permissions,
|
||||||
};
|
};
|
||||||
void sendToActiveTab({
|
void sendToActiveTab({
|
||||||
type: "content:mount",
|
type: "content:mount",
|
||||||
area: lastReq.area,
|
area: lastReq!.area,
|
||||||
mic: lastReq.mic,
|
mic: lastReq!.mic,
|
||||||
audioId: lastReq.selectedAudioDevice,
|
audioId: lastReq!.selectedAudioDevice,
|
||||||
audioPerm: lastReq.permissions,
|
audioPerm: lastReq!.permissions,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (request.type === messages.content.from.getErrorEvents) {
|
if (request.type === messages.content.from.getErrorEvents) {
|
||||||
const logs = finalSpotObj.logs.filter(
|
const logs = finalSpotObj.logs
|
||||||
(log) => log.level === "error",
|
.filter((log) => log.level === "error")
|
||||||
).map(l => ({ title: 'JS Error', time: (l.time - finalSpotObj.startTs)/1000 }))
|
.map((l) => ({
|
||||||
const network = finalSpotObj.network.filter(
|
title: "JS Error",
|
||||||
(net) => net.statusCode >= 400 || net.error,
|
time: (l.time - finalSpotObj.startTs) / 1000,
|
||||||
).map(n => ({ title: 'Network Error', time: (n.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]
|
const errorData = [...logs, ...network].sort((a, b) => a.time - b.time);
|
||||||
.sort((a, b) => a.time - b.time)
|
|
||||||
|
|
||||||
void sendToActiveTab({
|
void sendToActiveTab({
|
||||||
type: messages.content.to.updateErrorEvents,
|
type: messages.content.to.updateErrorEvents,
|
||||||
errorData,
|
errorData,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
if (request.type === "ort:stop") {
|
if (request.type === "ort:stop") {
|
||||||
browser.runtime
|
browser.runtime
|
||||||
|
|
@ -621,8 +633,10 @@ export default defineBackground(() => {
|
||||||
.then((r) => {
|
.then((r) => {
|
||||||
if (r.status === "full") {
|
if (r.status === "full") {
|
||||||
finalSpotObj.duration = r.duration;
|
finalSpotObj.duration = r.duration;
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond(r);
|
respond(r);
|
||||||
} else {
|
} else {
|
||||||
|
// @ts-ignore this is false positive
|
||||||
respond({ status: r.status });
|
respond({ status: r.status });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -633,7 +647,7 @@ export default defineBackground(() => {
|
||||||
}
|
}
|
||||||
if (request.type === "offscr:video-data-chunk") {
|
if (request.type === "offscr:video-data-chunk") {
|
||||||
finalSpotObj.duration = request.duration;
|
finalSpotObj.duration = request.duration;
|
||||||
sendToActiveTab({
|
void sendToActiveTab({
|
||||||
type: "content:video-chunk",
|
type: "content:video-chunk",
|
||||||
data: request.data,
|
data: request.data,
|
||||||
index: request.index,
|
index: request.index,
|
||||||
|
|
@ -666,7 +680,7 @@ export default defineBackground(() => {
|
||||||
type: "content:mic-status",
|
type: "content:mic-status",
|
||||||
micStatus: micStatus === "on",
|
micStatus: micStatus === "on",
|
||||||
});
|
});
|
||||||
chrome.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
type: messages.popup.to.micStatus,
|
type: messages.popup.to.micStatus,
|
||||||
status: false,
|
status: false,
|
||||||
});
|
});
|
||||||
|
|
@ -681,7 +695,7 @@ export default defineBackground(() => {
|
||||||
type: "content:mic-status",
|
type: "content:mic-status",
|
||||||
micStatus: micStatus === "on",
|
micStatus: micStatus === "on",
|
||||||
});
|
});
|
||||||
chrome.runtime.sendMessage({
|
void browser.runtime.sendMessage({
|
||||||
type: messages.popup.to.micStatus,
|
type: messages.popup.to.micStatus,
|
||||||
status: true,
|
status: true,
|
||||||
});
|
});
|
||||||
|
|
@ -712,7 +726,7 @@ export default defineBackground(() => {
|
||||||
finalVideoBase64 += request.part;
|
finalVideoBase64 += request.part;
|
||||||
finalReady = request.index === request.total - 1;
|
finalReady = request.index === request.total - 1;
|
||||||
const getPlatformData = async () => {
|
const getPlatformData = async () => {
|
||||||
const vendor = await chrome.runtime.getPlatformInfo();
|
const vendor = await browser.runtime.getPlatformInfo();
|
||||||
const platform = `${vendor.os} ${vendor.arch}`;
|
const platform = `${vendor.os} ${vendor.arch}`;
|
||||||
return { platform };
|
return { platform };
|
||||||
};
|
};
|
||||||
|
|
@ -782,7 +796,8 @@ export default defineBackground(() => {
|
||||||
const ingestUrl = safeApiUrl(settings.ingestPoint);
|
const ingestUrl = safeApiUrl(settings.ingestPoint);
|
||||||
|
|
||||||
const dataUrl = `${ingestUrl}/spot/v1/spots`;
|
const dataUrl = `${ingestUrl}/spot/v1/spots`;
|
||||||
refreshToken().then((r) => {
|
refreshToken()
|
||||||
|
.then((r) => {
|
||||||
if (!r) {
|
if (!r) {
|
||||||
void sendToActiveTab({
|
void sendToActiveTab({
|
||||||
type: messages.content.to.notification,
|
type: messages.content.to.notification,
|
||||||
|
|
@ -822,10 +837,12 @@ export default defineBackground(() => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { id, mobURL, videoURL } = resp;
|
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"
|
? "https://app.openreplay.com"
|
||||||
: settings.ingestPoint;
|
: settings.ingestPoint;
|
||||||
chrome.tabs.create({
|
void browser.tabs.create({
|
||||||
url: `${link}/view-spot/${id}`,
|
url: `${link}/view-spot/${id}`,
|
||||||
active: settings.openInNewTab,
|
active: settings.openInNewTab,
|
||||||
});
|
});
|
||||||
|
|
@ -850,7 +867,7 @@ export default defineBackground(() => {
|
||||||
body: blob,
|
body: blob,
|
||||||
});
|
});
|
||||||
Promise.all([mPromise, vPromise])
|
Promise.all([mPromise, vPromise])
|
||||||
.then(async (r) => {
|
.then(async () => {
|
||||||
const uploadedUrl = `${safeApiUrl(settings.ingestPoint)}/spot/v1/spots/${id}/uploaded`;
|
const uploadedUrl = `${safeApiUrl(settings.ingestPoint)}/spot/v1/spots/${id}/uploaded`;
|
||||||
void fetch(uploadedUrl, {
|
void fetch(uploadedUrl, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
|
@ -872,12 +889,12 @@ export default defineBackground(() => {
|
||||||
finalSpotObj = defaultSpotObj;
|
finalSpotObj = defaultSpotObj;
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch((e) => {
|
||||||
void sendToActiveTab({
|
void sendToActiveTab({
|
||||||
type: messages.content.to.notification,
|
type: messages.content.to.notification,
|
||||||
message: `Error saving Spot: ${e.message}`,
|
message: `Error saving Spot: ${e.message}`,
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -897,11 +914,17 @@ export default defineBackground(() => {
|
||||||
});
|
});
|
||||||
void initializeOffscreenDocument();
|
void initializeOffscreenDocument();
|
||||||
|
|
||||||
type TrackedRequest =
|
type TrackedRequest = {
|
||||||
|
statusCode: number;
|
||||||
|
requestHeaders: Record<string, string>;
|
||||||
|
responseHeaders: Record<string, string>;
|
||||||
|
} & (
|
||||||
| WebRequest.OnBeforeRequestDetailsType
|
| WebRequest.OnBeforeRequestDetailsType
|
||||||
| WebRequest.OnBeforeSendHeadersDetailsType
|
| WebRequest.OnBeforeSendHeadersDetailsType
|
||||||
| WebRequest.OnCompletedDetailsType
|
| WebRequest.OnCompletedDetailsType
|
||||||
| WebRequest.OnErrorOccurredDetailsType;
|
| WebRequest.OnErrorOccurredDetailsType
|
||||||
|
| WebRequest.OnResponseStartedDetailsType
|
||||||
|
);
|
||||||
|
|
||||||
interface SpotNetworkRequest {
|
interface SpotNetworkRequest {
|
||||||
encodedBodySize: number;
|
encodedBodySize: number;
|
||||||
|
|
@ -922,20 +945,6 @@ export default defineBackground(() => {
|
||||||
startTs: number;
|
startTs: number;
|
||||||
duration: 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>) {
|
function filterHeaders(headers: Record<string, string>) {
|
||||||
const filteredHeaders: Record<string, string> = {};
|
const filteredHeaders: Record<string, string> = {};
|
||||||
const privateHs = [
|
const privateHs = [
|
||||||
|
|
@ -1065,7 +1074,6 @@ export default defineBackground(() => {
|
||||||
};
|
};
|
||||||
function startTrackingNetwork() {
|
function startTrackingNetwork() {
|
||||||
rawRequests.length = 0;
|
rawRequests.length = 0;
|
||||||
processedRequests.length = 0;
|
|
||||||
browser.webRequest.onBeforeRequest.addListener(
|
browser.webRequest.onBeforeRequest.addListener(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
trackOnBefore,
|
trackOnBefore,
|
||||||
|
|
@ -1159,8 +1167,7 @@ export default defineBackground(() => {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const resp = await browser.runtime.sendMessage(message);
|
return await browser.runtime.sendMessage(message);
|
||||||
return resp;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Sending to offscreen", e);
|
console.error("Sending to offscreen", e);
|
||||||
}
|
}
|
||||||
|
|
@ -1366,7 +1373,7 @@ export default defineBackground(() => {
|
||||||
const decodeJwt = (jwt: string): any => {
|
const decodeJwt = (jwt: string): any => {
|
||||||
const base64Url = jwt.split(".")[1];
|
const base64Url = jwt.split(".")[1];
|
||||||
if (!base64Url) {
|
if (!base64Url) {
|
||||||
return { exp: 0 }
|
return { exp: 0 };
|
||||||
}
|
}
|
||||||
const base64 = base64Url.replace("-", "+").replace("_", "/");
|
const base64 = base64Url.replace("-", "+").replace("_", "/");
|
||||||
return JSON.parse(atob(base64));
|
return JSON.parse(atob(base64));
|
||||||
|
|
@ -1383,7 +1390,7 @@ export default defineBackground(() => {
|
||||||
return request.statusCode;
|
return request.statusCode;
|
||||||
}
|
}
|
||||||
if (request.error) {
|
if (request.error) {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ interface IControlsBox {
|
||||||
getInitState: () => string;
|
getInitState: () => string;
|
||||||
onRestart: () => void;
|
onRestart: () => void;
|
||||||
getErrorEvents: () => Promise<any>;
|
getErrorEvents: () => Promise<any>;
|
||||||
getAudioPerm: () => number,
|
getAudioPerm: () => 0 | 1 | 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
function ControlsBox({
|
function ControlsBox({
|
||||||
|
|
@ -59,24 +59,37 @@ function ControlsBox({
|
||||||
const onTimerEnd = async (proceed?: boolean) => {
|
const onTimerEnd = async (proceed?: boolean) => {
|
||||||
if (!proceed) {
|
if (!proceed) {
|
||||||
onClose(false);
|
onClose(false);
|
||||||
return changeState(STATES.idle)
|
return changeState(STATES.idle);
|
||||||
}
|
}
|
||||||
|
let tries = 0;
|
||||||
|
// changeState(STATES.idle);
|
||||||
await callRecording();
|
await callRecording();
|
||||||
let int = setInterval(() => {
|
let int = setInterval(() => {
|
||||||
const state = getInitState();
|
const state = getInitState();
|
||||||
|
tries++;
|
||||||
|
if (tries > 200) {
|
||||||
|
clearInterval(int);
|
||||||
|
changeState(STATES.idle);
|
||||||
|
}
|
||||||
if (state !== "count") {
|
if (state !== "count") {
|
||||||
clearInterval(int);
|
clearInterval(int);
|
||||||
changeState(STATES.recording);
|
changeState(STATES.recording);
|
||||||
}
|
}
|
||||||
}, 100);
|
}, 50);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={"controls"}>
|
<div class={"controls"}>
|
||||||
{boxState() === STATES.saving ? (
|
{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}
|
) : null}
|
||||||
{boxState() === STATES.count ? <Countdown getAudioPerm={getAudioPerm} onEnd={onTimerEnd} /> : null}
|
|
||||||
{boxState() === STATES.recording ? (
|
{boxState() === STATES.recording ? (
|
||||||
<RecordingControls
|
<RecordingControls
|
||||||
getAudioPerm={getAudioPerm}
|
getAudioPerm={getAudioPerm}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { createSignal, onCleanup, onMount } from "solid-js";
|
||||||
|
|
||||||
function Countdown(props: {
|
function Countdown(props: {
|
||||||
onEnd: (proceed?: boolean) => void;
|
onEnd: (proceed?: boolean) => void;
|
||||||
getAudioPerm: () => number;
|
getAudioPerm: () => 0 | 1 | 2;
|
||||||
}) {
|
}) {
|
||||||
const [count, setCount] = createSignal(3);
|
const [count, setCount] = createSignal(3);
|
||||||
|
|
||||||
|
|
@ -39,8 +39,8 @@ function Countdown(props: {
|
||||||
const audioPrompt = {
|
const audioPrompt = {
|
||||||
0: "Microphone permission isn't granted yet.",
|
0: "Microphone permission isn't granted yet.",
|
||||||
1: "Microphone access is enabled. Unmute anytime to add voice over.",
|
1: "Microphone access is enabled. Unmute anytime to add voice over.",
|
||||||
2: "Microphone is enabled."
|
2: "Microphone is enabled.",
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="modal-overlay">
|
<div class="modal-overlay">
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ interface ISavingControls {
|
||||||
comment?: string;
|
comment?: string;
|
||||||
useHook?: boolean;
|
useHook?: boolean;
|
||||||
thumbnail?: string;
|
thumbnail?: string;
|
||||||
crop?: [number, number];
|
crop: [number, number] | null;
|
||||||
},
|
},
|
||||||
) => void;
|
) => void;
|
||||||
getVideoData: () => Promise<any>;
|
getVideoData: () => Promise<any>;
|
||||||
|
|
@ -51,7 +51,9 @@ function SavingControls({
|
||||||
const [endPos, setEndPos] = createSignal(100);
|
const [endPos, setEndPos] = createSignal(100);
|
||||||
const [dragging, setDragging] = createSignal<string | null>(null);
|
const [dragging, setDragging] = createSignal<string | null>(null);
|
||||||
const [isTyping, setIsTyping] = createSignal(false);
|
const [isTyping, setIsTyping] = createSignal(false);
|
||||||
const [errorEvents, setErrorEvents] = createSignal([]);
|
const [errorEvents, setErrorEvents] = createSignal<
|
||||||
|
{ title: string; time: number }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
createEffect(() => {
|
createEffect(() => {
|
||||||
setTrimBounds([0, 0]);
|
setTrimBounds([0, 0]);
|
||||||
|
|
@ -226,7 +228,7 @@ function SavingControls({
|
||||||
}
|
}
|
||||||
setDuration(videoDuration);
|
setDuration(videoDuration);
|
||||||
setErrorEvents(
|
setErrorEvents(
|
||||||
errorEvents.filter((ev: { time: number }) => ev.time < videoDuration),
|
errorEvents().filter((ev: { time: number }) => ev.time < videoDuration),
|
||||||
);
|
);
|
||||||
void generateThumbnail();
|
void generateThumbnail();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ export default defineContentScript({
|
||||||
position: "inline",
|
position: "inline",
|
||||||
anchor: "body",
|
anchor: "body",
|
||||||
append: "first",
|
append: "first",
|
||||||
onMount: (container,s,host) => {
|
onMount: (container, s, host) => {
|
||||||
Object.assign(host.style, { visibility: 'visible', display: 'block' });
|
Object.assign(host.style, { visibility: "visible", display: "block" });
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
() => (
|
() => (
|
||||||
|
|
@ -66,8 +66,9 @@ export default defineContentScript({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// no perm - muted - unmuted
|
// no perm - muted - unmuted
|
||||||
let audioPerm = 0;
|
type AudioPermState = 0 | 1 | 2;
|
||||||
const getAudioPerm = () => audioPerm
|
let audioPerm: AudioPermState = 0;
|
||||||
|
const getAudioPerm = (): AudioPermState => audioPerm;
|
||||||
let clockStart = 0;
|
let clockStart = 0;
|
||||||
let recState = "stopped";
|
let recState = "stopped";
|
||||||
const getClockStart = () => {
|
const getClockStart = () => {
|
||||||
|
|
@ -186,7 +187,7 @@ export default defineContentScript({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { name, comment, useHook, thumbnail, crop, blob } = spotObj;
|
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 resolution = `${window.screen.width}x${window.screen.height}`;
|
||||||
const browserVersion = getChromeFullVersion();
|
const browserVersion = getChromeFullVersion();
|
||||||
const spot = {
|
const spot = {
|
||||||
|
|
@ -302,6 +303,7 @@ export default defineContentScript({
|
||||||
}
|
}
|
||||||
|
|
||||||
void browser.runtime.sendMessage({ type: "ort:content-ready" });
|
void browser.runtime.sendMessage({ type: "ort:content-ready" });
|
||||||
|
// @ts-ignore false positive
|
||||||
browser.runtime.onMessage.addListener((message: any, resp) => {
|
browser.runtime.onMessage.addListener((message: any, resp) => {
|
||||||
if (message.type === "content:mount") {
|
if (message.type === "content:mount") {
|
||||||
if (recState === "count") return;
|
if (recState === "count") return;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,6 @@
|
||||||
"@wxt-dev/module-solid": "^1.1.2",
|
"@wxt-dev/module-solid": "^1.1.2",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"wxt": "0.19.8"
|
"wxt": "0.19.9"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -941,11 +941,36 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.20.7"
|
"@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":
|
"@types/estree@1.0.5", "@types/estree@^1.0.0":
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"
|
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"
|
||||||
integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
|
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":
|
"@types/http-cache-semantics@^4.0.2":
|
||||||
version "4.0.4"
|
version "4.0.4"
|
||||||
resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz"
|
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"
|
signal-exit "^4.1.0"
|
||||||
strip-final-newline "^3.0.0"
|
strip-final-newline "^3.0.0"
|
||||||
|
|
||||||
execa@^9.3.0:
|
execa@^9.3.1:
|
||||||
version "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==
|
integrity sha512-gdhefCCNy/8tpH/2+ajP9IQc14vXchNdd0weyzSJEFURhRMGncQ+zKFxwjAufIewPEJm9BPOaJnvg2UtlH2gPQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sindresorhus/merge-streams" "^4.0.0"
|
"@sindresorhus/merge-streams" "^4.0.0"
|
||||||
|
|
@ -3855,9 +3880,9 @@ ora@^6.3.1:
|
||||||
strip-ansi "^7.0.1"
|
strip-ansi "^7.0.1"
|
||||||
wcwidth "^1.0.1"
|
wcwidth "^1.0.1"
|
||||||
|
|
||||||
ora@^8.0.1:
|
ora@^8.1.0:
|
||||||
version "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==
|
integrity sha512-GQEkNkH/GHOhPFXcqZs3IDahXEQcQxsSjEkK4KvEEST4t7eNzoMjxTzef+EZ+JluDEV+Raoi3WQ2CflnRdSVnQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk "^5.3.0"
|
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"
|
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz"
|
||||||
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==
|
||||||
|
|
||||||
unimport@^3.9.1:
|
unimport@^3.11.1:
|
||||||
version "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==
|
integrity sha512-DuB1Uoq01LrrXTScxnwOoMSlTXxyKcULguFxbLrMDFcE/CO0ZWHpEiyhovN0mycPt7K6luAHe8laqvwvuoeUPg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@rollup/pluginutils" "^5.1.0"
|
"@rollup/pluginutils" "^5.1.0"
|
||||||
|
|
@ -5306,12 +5331,13 @@ ws@8.18.0:
|
||||||
resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz"
|
resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz"
|
||||||
integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
|
integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
|
||||||
|
|
||||||
wxt@0.19.8:
|
wxt@0.19.9:
|
||||||
version "0.19.8"
|
version "0.19.9"
|
||||||
resolved "https://registry.yarnpkg.com/wxt/-/wxt-0.19.8.tgz#b07b98d95a34e5e2d916c3a6a53520e0d0b1b66d"
|
resolved "https://registry.yarnpkg.com/wxt/-/wxt-0.19.9.tgz#b8f7f838cab00d66f4ee22f483c49ad8f6527af8"
|
||||||
integrity sha512-Z3LxRuM8rTZ9VOZnQ2DjtRz3uLpZpFzTfBjRVgEOHv1kf/7sRVdeKCY4pUmtimgfR2/NGclYAbCfAVTYQJg0GA==
|
integrity sha512-XUbF4JNyx2jTDpXwx2c/esaJcUD2Dr482C2GGenkGRMH2UnerzOIchGCtaa1hb2U8eAed7Akda0yRoMJU0uxUw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@aklinker1/rollup-plugin-visualizer" "5.12.0"
|
"@aklinker1/rollup-plugin-visualizer" "5.12.0"
|
||||||
|
"@types/chrome" "^0.0.269"
|
||||||
"@types/webextension-polyfill" "^0.10.7"
|
"@types/webextension-polyfill" "^0.10.7"
|
||||||
"@webext-core/fake-browser" "^1.3.1"
|
"@webext-core/fake-browser" "^1.3.1"
|
||||||
"@webext-core/isolated-element" "^1.1.2"
|
"@webext-core/isolated-element" "^1.1.2"
|
||||||
|
|
@ -5325,7 +5351,7 @@ wxt@0.19.8:
|
||||||
defu "^6.1.4"
|
defu "^6.1.4"
|
||||||
dequal "^2.0.3"
|
dequal "^2.0.3"
|
||||||
esbuild "^0.23.0"
|
esbuild "^0.23.0"
|
||||||
execa "^9.3.0"
|
execa "^9.3.1"
|
||||||
fast-glob "^3.3.2"
|
fast-glob "^3.3.2"
|
||||||
filesize "^10.1.4"
|
filesize "^10.1.4"
|
||||||
fs-extra "^11.2.0"
|
fs-extra "^11.2.0"
|
||||||
|
|
@ -5344,11 +5370,12 @@ wxt@0.19.8:
|
||||||
nypm "^0.3.9"
|
nypm "^0.3.9"
|
||||||
ohash "^1.1.3"
|
ohash "^1.1.3"
|
||||||
open "^10.1.0"
|
open "^10.1.0"
|
||||||
ora "^8.0.1"
|
ora "^8.1.0"
|
||||||
picocolors "^1.0.1"
|
picocolors "^1.0.1"
|
||||||
prompts "^2.4.2"
|
prompts "^2.4.2"
|
||||||
publish-browser-extension "^2.1.3"
|
publish-browser-extension "^2.1.3"
|
||||||
unimport "^3.9.1"
|
scule "^1.3.0"
|
||||||
|
unimport "^3.11.1"
|
||||||
vite "^5.3.5"
|
vite "^5.3.5"
|
||||||
vite-node "^2.0.4"
|
vite-node "^2.0.4"
|
||||||
web-ext-run "^0.2.1"
|
web-ext-run "^0.2.1"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue