spot: small refactoring + testing debugger for network capture
This commit is contained in:
parent
8be6f63711
commit
f59a8c24f4
9 changed files with 306 additions and 117 deletions
BIN
spot/bun.lockb
BIN
spot/bun.lockb
Binary file not shown.
|
|
@ -4,76 +4,22 @@ import {
|
|||
getFinalRequests,
|
||||
stopTrackingNetwork,
|
||||
} from "~/utils/networkTracking";
|
||||
import { mergeRequests } from "~/utils/networkTrackingUtils";
|
||||
import { mergeRequests, SpotNetworkRequest } from "~/utils/networkTrackingUtils";
|
||||
import { safeApiUrl } from '~/utils/smallUtils'
|
||||
import {
|
||||
attachDebuggerToTab,
|
||||
detachDebuggerFromTab,
|
||||
getRequests as getDebuggerRequests,
|
||||
resetMap
|
||||
} from "~/utils/networkDebuggerTracking";
|
||||
import { messages } from '~/utils/messages'
|
||||
|
||||
let checkBusy = false;
|
||||
|
||||
export default defineBackground(() => {
|
||||
const CHECK_INT = 60 * 1000;
|
||||
const PING_INT = 30 * 1000;
|
||||
const VER = "1.0.10";
|
||||
|
||||
const messages = {
|
||||
popup: {
|
||||
from: {
|
||||
updateSettings: "ort:settings",
|
||||
start: "popup:start",
|
||||
},
|
||||
to: {
|
||||
micStatus: "popup:mic-status",
|
||||
stopped: "popup:stopped",
|
||||
started: "popup:started",
|
||||
noLogin: "popup:no-login",
|
||||
},
|
||||
stop: "popup:stop",
|
||||
checkStatus: "popup:check-status",
|
||||
loginExist: "popup:login",
|
||||
getAudioPerms: "popup:get-audio-perm",
|
||||
},
|
||||
content: {
|
||||
from: {
|
||||
bumpVitals: "ort:bump-vitals",
|
||||
bumpClicks: "ort:bump-clicks",
|
||||
bumpLocation: "ort:bump-location",
|
||||
discard: "ort:discard",
|
||||
checkLogin: "ort:get-login",
|
||||
checkRecStatus: "ort:check-status",
|
||||
checkMicStatus: "ort:getMicStatus",
|
||||
setLoginToken: "ort:login-token",
|
||||
invalidateToken: "ort:invalidate-token",
|
||||
saveSpotData: "ort:save-spot",
|
||||
saveSpotVidChunk: "ort:save-spot-part",
|
||||
countEnd: "ort:countend",
|
||||
contentReady: "ort:content-ready",
|
||||
checkNewTab: "ort:check-new-tab",
|
||||
started: "ort:started",
|
||||
stopped: "ort:stopped",
|
||||
toStop: "ort:stop",
|
||||
restart: "ort:restart",
|
||||
getErrorEvents: "ort:get-error-events",
|
||||
},
|
||||
to: {
|
||||
setJWT: "content:set-jwt",
|
||||
micStatus: "content:mic-status",
|
||||
unmount: "content:unmount",
|
||||
notification: "notif:display",
|
||||
updateErrorEvents: "content:error-events",
|
||||
},
|
||||
},
|
||||
injected: {
|
||||
from: {
|
||||
bumpLogs: "ort:bump-logs",
|
||||
bumpNetwork: "ort:bump-network",
|
||||
},
|
||||
},
|
||||
offscreen: {
|
||||
to: {
|
||||
checkRecStatus: "offscr:check-status",
|
||||
startRecording: "offscr:start-recording",
|
||||
stopRecording: "offscr:stop-recording",
|
||||
},
|
||||
},
|
||||
};
|
||||
const VER = "1.0.14";
|
||||
|
||||
interface SpotObj {
|
||||
name: string;
|
||||
|
|
@ -116,6 +62,7 @@ export default defineBackground(() => {
|
|||
openInNewTab: true,
|
||||
consoleLogs: true,
|
||||
networkLogs: true,
|
||||
useDebugger: false,
|
||||
ingestPoint: "https://app.openreplay.com",
|
||||
};
|
||||
const defaultSpotObj = {
|
||||
|
|
@ -145,12 +92,18 @@ export default defineBackground(() => {
|
|||
let injectNetworkRequests = [];
|
||||
let onStop: (() => void) | null = null;
|
||||
let settings = defaultSettings;
|
||||
let recordingState = {
|
||||
type recState = {
|
||||
activeTabId: number | null;
|
||||
area: string | null;
|
||||
recording: string;
|
||||
audioPerm: number;
|
||||
}
|
||||
let recordingState: recState = {
|
||||
activeTabId: null,
|
||||
area: null,
|
||||
recording: REC_STATE.stopped,
|
||||
audioPerm: 0,
|
||||
} as Record<string, any>;
|
||||
}
|
||||
let jwtToken = "";
|
||||
let refreshInt: any;
|
||||
let pingInt: any;
|
||||
|
|
@ -187,17 +140,6 @@ export default defineBackground(() => {
|
|||
}
|
||||
}
|
||||
|
||||
function safeApiUrl(url: string) {
|
||||
let str = url;
|
||||
if (str.endsWith("/")) {
|
||||
str = str.slice(0, -1);
|
||||
}
|
||||
if (str.includes("app.openreplay.com")) {
|
||||
str = str.replace("app.openreplay.com", "api.openreplay.com");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
let slackChannels: { name: string; webhookId: number }[] = [];
|
||||
|
||||
void checkTokenValidity();
|
||||
|
|
@ -346,7 +288,6 @@ export default defineBackground(() => {
|
|||
recording: REC_STATE.stopped,
|
||||
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
|
||||
};
|
||||
startTrackingNetwork();
|
||||
if (request.area === "tab") {
|
||||
browser.tabs
|
||||
.query({
|
||||
|
|
@ -358,6 +299,12 @@ export default defineBackground(() => {
|
|||
if (active) {
|
||||
recordingState.activeTabId = active.id;
|
||||
}
|
||||
if (settings.useDebugger) {
|
||||
resetMap();
|
||||
void attachDebuggerToTab(active.id);
|
||||
} else {
|
||||
startTrackingNetwork();
|
||||
}
|
||||
void sendToActiveTab({
|
||||
type: "content:mount",
|
||||
area: request.area,
|
||||
|
|
@ -367,12 +314,22 @@ export default defineBackground(() => {
|
|||
});
|
||||
});
|
||||
} else {
|
||||
if (!settings.useDebugger) {
|
||||
startTrackingNetwork();
|
||||
}
|
||||
void sendToActiveTab({
|
||||
type: "content:mount",
|
||||
area: request.area,
|
||||
mic: request.mic,
|
||||
audioId: request.selectedAudioDevice,
|
||||
audioPerm: request.permissions ? (request.mic ? 2 : 1) : 0,
|
||||
}, (tabId) => {
|
||||
if (settings.useDebugger) {
|
||||
resetMap();
|
||||
void attachDebuggerToTab(tabId);
|
||||
} else {
|
||||
startTrackingNetwork();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -675,15 +632,21 @@ export default defineBackground(() => {
|
|||
if (recordingState.recording === REC_STATE.stopped) {
|
||||
return console.error("Calling stopped recording?");
|
||||
}
|
||||
const networkRequests = getFinalRequests(
|
||||
recordingState.activeTabId ?? false,
|
||||
);
|
||||
|
||||
stopTrackingNetwork();
|
||||
const mappedNetwork = mergeRequests(
|
||||
networkRequests,
|
||||
injectNetworkRequests,
|
||||
);
|
||||
let networkRequests;
|
||||
let mappedNetwork;
|
||||
if (settings.useDebugger && recordingState.area === "tab") {
|
||||
void detachDebuggerFromTab(recordingState.activeTabId);
|
||||
mappedNetwork = getDebuggerRequests();
|
||||
} else {
|
||||
networkRequests = getFinalRequests(
|
||||
recordingState.activeTabId ?? false,
|
||||
);
|
||||
stopTrackingNetwork();
|
||||
mappedNetwork = mergeRequests(
|
||||
networkRequests,
|
||||
injectNetworkRequests,
|
||||
);
|
||||
}
|
||||
injectNetworkRequests = [];
|
||||
finalSpotObj.network = mappedNetwork;
|
||||
browser.runtime
|
||||
|
|
@ -1012,7 +975,7 @@ export default defineBackground(() => {
|
|||
data?: any;
|
||||
activeTabId?: number;
|
||||
[key: string]: any;
|
||||
}) {
|
||||
}, onSent?: (tabId: number) => void) {
|
||||
let activeTabs = await browser.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
|
|
@ -1038,6 +1001,7 @@ export default defineBackground(() => {
|
|||
message,
|
||||
);
|
||||
await browser.tabs.sendMessage(sendTo, message);
|
||||
onSent?.(sendTo);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1135,6 +1099,7 @@ export default defineBackground(() => {
|
|||
stopTabActivationListening();
|
||||
}
|
||||
if (tabId !== previousTab) {
|
||||
detachDebuggerFromTab(previousTab)
|
||||
browser.runtime
|
||||
.sendMessage({
|
||||
type: messages.offscreen.to.checkRecStatus,
|
||||
|
|
@ -1148,6 +1113,7 @@ export default defineBackground(() => {
|
|||
state: getRecState(),
|
||||
activeTabId: null,
|
||||
};
|
||||
attachDebuggerToTab(tabId)
|
||||
void sendToActiveTab(msg);
|
||||
});
|
||||
if (previousTab) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
stopClickRecording,
|
||||
} from "./eventTrackers";
|
||||
import ControlsBox from "~/entrypoints/content/ControlsBox";
|
||||
|
||||
import { messages } from '~/utils/messages';
|
||||
import { convertBlobToBase64, getChromeFullVersion } from "./utils";
|
||||
import "./style.css";
|
||||
import "~/assets/main.css";
|
||||
|
|
@ -55,7 +55,7 @@ export default defineContentScript({
|
|||
const getMicStatus = async () => {
|
||||
return new Promise((res) => {
|
||||
browser.runtime.sendMessage({
|
||||
type: "ort:getMicStatus",
|
||||
type: messages.content.from.checkMicStatus,
|
||||
});
|
||||
let int = setInterval(() => {
|
||||
if (micResponse !== null) {
|
||||
|
|
@ -124,7 +124,7 @@ export default defineContentScript({
|
|||
recState = "stopped";
|
||||
stopClickRecording();
|
||||
stopLocationRecording();
|
||||
const result = await browser.runtime.sendMessage({ type: "ort:stop" });
|
||||
const result = await browser.runtime.sendMessage({ type: messages.content.from.toStop });
|
||||
if (result.status === "full") {
|
||||
chunksReady = true;
|
||||
data = result;
|
||||
|
|
@ -149,20 +149,20 @@ export default defineContentScript({
|
|||
|
||||
const pause = () => {
|
||||
recState = "paused";
|
||||
browser.runtime.sendMessage({ type: "ort:pause" });
|
||||
browser.runtime.sendMessage({ type: messages.content.from.pause });
|
||||
};
|
||||
|
||||
const resume = () => {
|
||||
recState = "recording";
|
||||
browser.runtime.sendMessage({ type: "ort:resume" });
|
||||
browser.runtime.sendMessage({ type: messages.content.from.resume });
|
||||
};
|
||||
|
||||
const muteMic = () => {
|
||||
browser.runtime.sendMessage({ type: "ort:mute-microphone" });
|
||||
browser.runtime.sendMessage({ type: messages.content.from.muteMic });
|
||||
};
|
||||
|
||||
const unmuteMic = () => {
|
||||
browser.runtime.sendMessage({ type: "ort:unmute-microphone" });
|
||||
browser.runtime.sendMessage({ type: messages.content.from.unmuteMic });
|
||||
};
|
||||
|
||||
const onClose = async (
|
||||
|
|
@ -202,14 +202,14 @@ export default defineContentScript({
|
|||
|
||||
try {
|
||||
await browser.runtime.sendMessage({
|
||||
type: "ort:save-spot",
|
||||
type: messages.content.from.saveSpotData,
|
||||
spot,
|
||||
});
|
||||
let index = 0;
|
||||
for (let part of videoData.result) {
|
||||
if (part) {
|
||||
await browser.runtime.sendMessage({
|
||||
type: "ort:save-spot-part",
|
||||
type: messages.content.from.saveSpotVidChunk,
|
||||
part,
|
||||
index,
|
||||
total: videoData.result.length,
|
||||
|
|
@ -238,24 +238,24 @@ export default defineContentScript({
|
|||
if (event.data.type === "orspot:token") {
|
||||
window.postMessage({ type: "orspot:logged" }, "*");
|
||||
void browser.runtime.sendMessage({
|
||||
type: "ort:login-token",
|
||||
type: messages.content.from.setLoginToken,
|
||||
token: event.data.token,
|
||||
});
|
||||
}
|
||||
if (event.data.type === "orspot:invalidate") {
|
||||
void browser.runtime.sendMessage({
|
||||
type: "ort:invalidate-token",
|
||||
type: messages.content.from.invalidateToken,
|
||||
});
|
||||
}
|
||||
if (event.data.type === "ort:bump-logs") {
|
||||
void chrome.runtime.sendMessage({
|
||||
type: "ort:bump-logs",
|
||||
type: messages.injected.from.bumpLogs,
|
||||
logs: event.data.logs,
|
||||
});
|
||||
}
|
||||
if (event.data.type === "ort:bump-network") {
|
||||
void chrome.runtime.sendMessage({
|
||||
type: "ort:bump-network",
|
||||
type: messages.injected.from.bumpNetwork,
|
||||
event: event.data.event,
|
||||
});
|
||||
}
|
||||
|
|
@ -292,7 +292,7 @@ export default defineContentScript({
|
|||
|
||||
function onRestart() {
|
||||
chrome.runtime.sendMessage({
|
||||
type: "ort:restart",
|
||||
type: messages.content.from.restart,
|
||||
});
|
||||
stopClickRecording();
|
||||
stopLocationRecording();
|
||||
|
|
@ -316,7 +316,7 @@ export default defineContentScript({
|
|||
let onEndObj = {};
|
||||
async function countEnd(): Promise<boolean> {
|
||||
return browser.runtime
|
||||
.sendMessage({ ...onEndObj, type: "ort:countend" })
|
||||
.sendMessage({ ...onEndObj, type: messages.content.from.countEnd })
|
||||
.then((r: boolean) => {
|
||||
onEndObj = {};
|
||||
return r;
|
||||
|
|
@ -324,11 +324,11 @@ export default defineContentScript({
|
|||
}
|
||||
|
||||
setInterval(() => {
|
||||
void browser.runtime.sendMessage({ type: "ort:content-ready" });
|
||||
void browser.runtime.sendMessage({ type: messages.content.from.contentReady });
|
||||
}, 250);
|
||||
// @ts-ignore false positive
|
||||
browser.runtime.onMessage.addListener((message: any, resp) => {
|
||||
if (message.type === "content:mount") {
|
||||
if (message.type === messages.content.to.mount) {
|
||||
if (recState === "count") return;
|
||||
recState = "count";
|
||||
onEndObj = {
|
||||
|
|
@ -339,7 +339,7 @@ export default defineContentScript({
|
|||
audioPerm = message.audioPerm;
|
||||
ui.mount();
|
||||
}
|
||||
if (message.type === "content:start") {
|
||||
if (message.type === messages.content.to.start) {
|
||||
if (recState === "recording") return;
|
||||
clockStart = message.time;
|
||||
recState = "recording";
|
||||
|
|
@ -352,13 +352,13 @@ export default defineContentScript({
|
|||
if (message.withNetwork) {
|
||||
startNetworkTracking();
|
||||
}
|
||||
browser.runtime.sendMessage({ type: "ort:started" });
|
||||
browser.runtime.sendMessage({ type: messages.content.from.started });
|
||||
if (message.shouldMount) {
|
||||
ui.mount();
|
||||
}
|
||||
return "pong";
|
||||
}
|
||||
if (message.type === "notif:display") {
|
||||
if (message.type === messages.content.to.notification) {
|
||||
window.postMessage(
|
||||
{
|
||||
type: "ornotif:display",
|
||||
|
|
@ -367,7 +367,7 @@ export default defineContentScript({
|
|||
"*",
|
||||
);
|
||||
}
|
||||
if (message.type === "content:unmount") {
|
||||
if (message.type === messages.content.to.unmount) {
|
||||
stopClickRecording();
|
||||
stopLocationRecording();
|
||||
stopConsoleTracking();
|
||||
|
|
@ -376,22 +376,22 @@ export default defineContentScript({
|
|||
ui.remove();
|
||||
return "unmounted";
|
||||
}
|
||||
if (message.type === "content:video-chunk") {
|
||||
if (message.type === messages.content.to.videoChunk) {
|
||||
videoChunks[message.index] = message.data;
|
||||
if (message.total === message.index + 1) {
|
||||
chunksReady = true;
|
||||
}
|
||||
}
|
||||
if (message.type === "content:spot-saved") {
|
||||
if (message.type === messages.content.to.spotSaved) {
|
||||
window.postMessage({ type: "ornotif:copy", url: message.url });
|
||||
}
|
||||
if (message.type === "content:stop") {
|
||||
if (message.type === messages.content.to.stop) {
|
||||
window.postMessage({ type: "content:trigger-stop" }, "*");
|
||||
}
|
||||
if (message.type === "content:mic-status") {
|
||||
if (message.type === messages.content.to.micStatus) {
|
||||
micResponse = message.micStatus;
|
||||
}
|
||||
if (message.type === "content:error-events") {
|
||||
if (message.type === messages.content.to.updateErrorEvents) {
|
||||
errorsReady = true;
|
||||
errorData.push(...message.errorData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,11 +11,11 @@ function Settings({ goBack }: { goBack: () => void }) {
|
|||
const [ingest, setIngest] = createSignal(defaultIngest);
|
||||
const [editIngest, setEditIngest] = createSignal(false);
|
||||
const [tempIngest, setTempIngest] = createSignal("");
|
||||
const [useDebugger, setUseDebugger] = createSignal(false);
|
||||
|
||||
onMount(() => {
|
||||
chrome.storage.local.get("settings", (data: any) => {
|
||||
if (data.settings) {
|
||||
console.log('update state', data.settings)
|
||||
const ingest =
|
||||
data.settings.ingestPoint || defaultIngest;
|
||||
const devToolsEnabled =
|
||||
|
|
@ -26,6 +26,7 @@ function Settings({ goBack }: { goBack: () => void }) {
|
|||
setTempIngest(ingest);
|
||||
setShowIngest(ingest !== defaultIngest);
|
||||
setEditIngest(!data.settings.ingestPoint);
|
||||
setUseDebugger(data.settings.useDebugger);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -94,6 +95,16 @@ function Settings({ goBack }: { goBack: () => void }) {
|
|||
});
|
||||
};
|
||||
|
||||
const toggleUseDebugger = (e: Event) => {
|
||||
e.stopPropagation();
|
||||
const value = useDebugger();
|
||||
setUseDebugger(!value);
|
||||
chrome.runtime.sendMessage({
|
||||
type: "ort:settings",
|
||||
settings: { useDebugger: !value },
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={"flex flex-col"}>
|
||||
<div class={"flex gap-2 items-center justify-between p-4"}>
|
||||
|
|
@ -153,6 +164,27 @@ function Settings({ goBack }: { goBack: () => void }) {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border-b border-slate-300 hover:bg-indigo-50 cursor-default">
|
||||
<div class="flex flex-row justify-between items-center">
|
||||
<p class="font-semibold mb-1 flex items-center">
|
||||
<span>Use Debugger</span>
|
||||
</p>
|
||||
<div>
|
||||
<label class="cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle toggle-primary toggle-sm"
|
||||
checked={useDebugger()}
|
||||
onChange={toggleUseDebugger}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-xs">
|
||||
Enable the chrome debugger to track network requests with more precision.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="p-4 hover:bg-indigo-50 cursor-default">
|
||||
<div class="flex flex-row justify-between">
|
||||
<p class="font-semibold mb-1">Ingest Point</p>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"name": "spot",
|
||||
"description": "manifest.json description",
|
||||
"private": true,
|
||||
"version": "1.0.14",
|
||||
"version": "1.0.15",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "wxt",
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
"@wxt-dev/module-solid": "^1.1.3",
|
||||
"daisyui": "^4.12.10",
|
||||
"typescript": "^5.7.2",
|
||||
"wxt": "0.19.22"
|
||||
"wxt": "0.19.24"
|
||||
},
|
||||
"packageManager": "yarn@4.5.3"
|
||||
}
|
||||
|
|
|
|||
70
spot/utils/messages.ts
Normal file
70
spot/utils/messages.ts
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
export const messages = {
|
||||
popup: {
|
||||
from: {
|
||||
updateSettings: "ort:settings",
|
||||
start: "popup:start",
|
||||
},
|
||||
to: {
|
||||
micStatus: "popup:mic-status",
|
||||
stopped: "popup:stopped",
|
||||
started: "popup:started",
|
||||
noLogin: "popup:no-login",
|
||||
},
|
||||
stop: "popup:stop",
|
||||
checkStatus: "popup:check-status",
|
||||
loginExist: "popup:login",
|
||||
getAudioPerms: "popup:get-audio-perm",
|
||||
},
|
||||
content: {
|
||||
from: {
|
||||
bumpVitals: "ort:bump-vitals",
|
||||
bumpClicks: "ort:bump-clicks",
|
||||
bumpLocation: "ort:bump-location",
|
||||
discard: "ort:discard",
|
||||
checkLogin: "ort:get-login",
|
||||
checkRecStatus: "ort:check-status",
|
||||
checkMicStatus: "ort:getMicStatus",
|
||||
setLoginToken: "ort:login-token",
|
||||
invalidateToken: "ort:invalidate-token",
|
||||
saveSpotData: "ort:save-spot",
|
||||
saveSpotVidChunk: "ort:save-spot-part",
|
||||
countEnd: "ort:countend",
|
||||
contentReady: "ort:content-ready",
|
||||
checkNewTab: "ort:check-new-tab",
|
||||
started: "ort:started",
|
||||
stopped: "ort:stopped",
|
||||
toStop: "ort:stop",
|
||||
restart: "ort:restart",
|
||||
getErrorEvents: "ort:get-error-events",
|
||||
muteMic: "ort:mute-microphone",
|
||||
unmuteMic: "ort:unmute-microphone",
|
||||
resume: "ort:resume",
|
||||
pause: "ort:pause",
|
||||
},
|
||||
to: {
|
||||
setJWT: "content:set-jwt",
|
||||
micStatus: "content:mic-status",
|
||||
unmount: "content:unmount",
|
||||
mount: "content:mount",
|
||||
start: "content:start",
|
||||
notification: "notif:display",
|
||||
updateErrorEvents: "content:error-events",
|
||||
videoChunk: "content:video-chunk",
|
||||
spotSaved: "content:spot-saved",
|
||||
stop: "content:stop",
|
||||
},
|
||||
},
|
||||
injected: {
|
||||
from: {
|
||||
bumpLogs: "ort:bump-logs",
|
||||
bumpNetwork: "ort:bump-network",
|
||||
},
|
||||
},
|
||||
offscreen: {
|
||||
to: {
|
||||
checkRecStatus: "offscr:check-status",
|
||||
startRecording: "offscr:start-recording",
|
||||
stopRecording: "offscr:stop-recording",
|
||||
},
|
||||
},
|
||||
};
|
||||
110
spot/utils/networkDebuggerTracking.ts
Normal file
110
spot/utils/networkDebuggerTracking.ts
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
let requestMap = {}
|
||||
|
||||
export function resetMap() {
|
||||
requestMap = {}
|
||||
}
|
||||
|
||||
export async function attachDebuggerToTab(tabId: string | number) {
|
||||
await new Promise((resolve, reject) => {
|
||||
chrome.debugger.attach({ tabId }, "1.3", () => {
|
||||
if (chrome.runtime.lastError)
|
||||
return reject(chrome.runtime.lastError.message);
|
||||
chrome.debugger.sendCommand({ tabId }, "Network.enable", {}, resolve);
|
||||
});
|
||||
chrome.debugger.onEvent.addListener(handleRequestIntercept);
|
||||
});
|
||||
}
|
||||
export async function detachDebuggerFromTab(tabId: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.debugger.detach({ tabId }, resolve);
|
||||
chrome.debugger.onEvent.removeListener(handleRequestIntercept);
|
||||
});
|
||||
}
|
||||
|
||||
const getType = (requestType: string) => {
|
||||
switch (requestType) {
|
||||
case "Fetch":
|
||||
case "XHR":
|
||||
case "xmlhttprequest":
|
||||
return 'xmlhttprequest'
|
||||
default:
|
||||
return requestType
|
||||
}
|
||||
}
|
||||
function handleRequestIntercept(source, method, params) {
|
||||
if (!source.tabId) return; // Not our target tab
|
||||
if (!params.request) return; // No request object
|
||||
if (params.request.method === "OPTIONS") return; // Ignore preflight requests
|
||||
|
||||
switch (method) {
|
||||
case "Network.requestWillBeSent":
|
||||
const reqType = params.type ? getType(params.type) : "resource";
|
||||
if (reqType !== "xmlhttprequest") {
|
||||
console.log(params);
|
||||
}
|
||||
|
||||
requestMap[params.requestId] = {
|
||||
encodedBodySize: 0,
|
||||
responseBodySize: 0,
|
||||
duration: 0,
|
||||
method: params.request.method,
|
||||
type: reqType,
|
||||
statusCode: 0,
|
||||
url: params.request.url,
|
||||
body: params.request.postData || "",
|
||||
responseBody: "",
|
||||
fromCache: false,
|
||||
requestHeaders: params.request.headers || {},
|
||||
responseHeaders: {},
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
break;
|
||||
|
||||
case "Network.responseReceived":
|
||||
if (!requestMap[params.requestId]) return;
|
||||
requestMap[params.requestId].statusCode = params.response.status;
|
||||
requestMap[params.requestId].responseHeaders =
|
||||
params.response.headers || {};
|
||||
// fromDiskCache or fromServiceWorker if available
|
||||
if (params.response.fromDiskCache)
|
||||
requestMap[params.requestId].fromCache = true;
|
||||
break;
|
||||
|
||||
case "Network.dataReceived":
|
||||
if (!requestMap[params.requestId]) return;
|
||||
requestMap[params.requestId].encodedBodySize += params.dataLength;
|
||||
// There's no direct content-encoding size from debugger
|
||||
break;
|
||||
|
||||
case "Network.loadingFinished":
|
||||
if (!requestMap[params.requestId]) return;
|
||||
requestMap[params.requestId].duration =
|
||||
Date.now() - requestMap[params.requestId].time;
|
||||
requestMap[params.requestId].responseBodySize =
|
||||
requestMap[params.requestId].encodedBodySize;
|
||||
chrome.debugger.sendCommand(
|
||||
{ tabId: source.tabId },
|
||||
"Network.getResponseBody",
|
||||
{ requestId: params.requestId },
|
||||
(res) => {
|
||||
if (!res || res.error) {
|
||||
requestMap[params.requestId].error = res?.error || "Unknown";
|
||||
} else {
|
||||
requestMap[params.requestId].responseBody = res.base64Encoded
|
||||
? atob(res.body)
|
||||
: res.body;
|
||||
}
|
||||
},
|
||||
);
|
||||
break;
|
||||
|
||||
case "Network.loadingFailed":
|
||||
if (!requestMap[params.requestId]) return;
|
||||
requestMap[params.requestId].error = params.errorText || "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
export const getRequests = () => {
|
||||
return Object.values(requestMap);
|
||||
};
|
||||
10
spot/utils/smallUtils.ts
Normal file
10
spot/utils/smallUtils.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export function safeApiUrl(url: string) {
|
||||
let str = url;
|
||||
if (str.endsWith("/")) {
|
||||
str = str.slice(0, -1);
|
||||
}
|
||||
if (str.includes("app.openreplay.com")) {
|
||||
str = str.replace("app.openreplay.com", "api.openreplay.com");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ export default defineConfig({
|
|||
"webNavigation",
|
||||
"webRequest",
|
||||
"<all_urls>",
|
||||
"debugger",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue