198 lines
6.1 KiB
JavaScript
198 lines
6.1 KiB
JavaScript
function createDebugContentLog({
|
|
previewDebugBody,
|
|
DEBUG_BODY_LIMIT,
|
|
debugState,
|
|
renderDebugPanel
|
|
}) {
|
|
function logRequestStart(details) {
|
|
const entry = {
|
|
id: debugState.requestLog.length + 1,
|
|
name: details.name,
|
|
method: details.method,
|
|
url: details.url,
|
|
headers: details.headers,
|
|
status: "pending",
|
|
startedAt: new Date(),
|
|
completedAt: null,
|
|
durationMs: null,
|
|
httpStatus: null,
|
|
statusText: "",
|
|
requestHeaders: details.headers,
|
|
requestBody: details.body || "",
|
|
metadata: details.metadata || {},
|
|
responseHeaders: {},
|
|
responseBody: "",
|
|
responseBodyTruncated: false,
|
|
error: ""
|
|
};
|
|
|
|
debugState.requestLog.push(entry);
|
|
renderDebugPanel();
|
|
return entry;
|
|
}
|
|
|
|
function logRequestSuccess(entry, response, responseBody) {
|
|
entry.status = response.ok ? "success" : "failed";
|
|
entry.completedAt = new Date();
|
|
entry.durationMs = entry.completedAt.getTime() - entry.startedAt.getTime();
|
|
entry.httpStatus = response.status;
|
|
entry.statusText = response.statusText || "";
|
|
entry.responseHeaders = headersToObject(response.headers);
|
|
entry.responseBody = responseBody.value;
|
|
entry.responseBodyTruncated = responseBody.truncated;
|
|
renderDebugPanel();
|
|
}
|
|
|
|
function logRequestFailure(entry, errorMessage) {
|
|
entry.status = "failed";
|
|
entry.completedAt = new Date();
|
|
entry.durationMs = entry.completedAt.getTime() - entry.startedAt.getTime();
|
|
entry.error = errorMessage;
|
|
renderDebugPanel();
|
|
}
|
|
|
|
function appendBackgroundRequestLog(entries) {
|
|
if (!Array.isArray(entries) || entries.length === 0) {
|
|
return;
|
|
}
|
|
|
|
entries.forEach((entry) => {
|
|
const existing = entry.debugKey && debugState.requestLog.find(item => item.debugKey === entry.debugKey);
|
|
if (existing && existing.status !== "pending" && entry.status === "pending") return;
|
|
const normalized = {
|
|
id: existing ? existing.id : debugState.requestLog.length + 1,
|
|
debugKey: entry.debugKey,
|
|
name: entry.name || "backgroundRequest",
|
|
method: entry.method || "GET",
|
|
url: entry.url || "",
|
|
headers: entry.requestHeaders || {},
|
|
status: entry.status || "failed",
|
|
startedAt: new Date(entry.startedAt),
|
|
completedAt: entry.completedAt ? new Date(entry.completedAt) : null,
|
|
durationMs: entry.durationMs,
|
|
httpStatus: entry.httpStatus,
|
|
statusText: entry.statusText || "",
|
|
requestHeaders: entry.requestHeaders || {},
|
|
requestBody: entry.requestBody || "",
|
|
metadata: entry.metadata || { executionContext: "background" },
|
|
responseHeaders: entry.responseHeaders || {},
|
|
responseBody: entry.responseBody || "",
|
|
responseBodyTruncated: Boolean(entry.responseBodyTruncated),
|
|
error: entry.error || ""
|
|
};
|
|
if (existing) Object.assign(existing, normalized);
|
|
else debugState.requestLog.push(normalized);
|
|
});
|
|
renderDebugPanel();
|
|
}
|
|
|
|
async function readResponseBodyForDebug(response) {
|
|
try {
|
|
const text = await response.clone().text();
|
|
return createDebugBody(text);
|
|
} catch (error) {
|
|
return {
|
|
value: `Unable to read response body: ${error.message || "unknown error"}`,
|
|
truncated: false
|
|
};
|
|
}
|
|
}
|
|
|
|
function createDebugBody(text) {
|
|
return previewDebugBody(text, DEBUG_BODY_LIMIT);
|
|
}
|
|
|
|
function headersToObject(headers) {
|
|
const headerMap = {};
|
|
|
|
headers.forEach((value, key) => {
|
|
headerMap[key] = value;
|
|
});
|
|
|
|
return headerMap;
|
|
}
|
|
|
|
function formatHeaderBlock(headers) {
|
|
const entries = Object.entries(headers);
|
|
|
|
if (entries.length === 0) {
|
|
return "(none)";
|
|
}
|
|
|
|
return entries
|
|
.map(([key, value]) => `${key}: ${debugState.debugSecretsVisible || !isSensitiveDebugKey(key)
|
|
? value
|
|
: formatHiddenDebugValue(value)}`)
|
|
.join("\n");
|
|
}
|
|
|
|
function formatDebugBody(body) {
|
|
const text = body || "(none)";
|
|
try {
|
|
const normalized = String(text).replace(/^\uFEFF/, "").trimStart()
|
|
.replace(/^\)\]\}',?\s*/, "")
|
|
.replace(/^while\s*\(1\);\s*/, "");
|
|
let value = JSON.parse(normalized);
|
|
// Some services serialize their JSON document inside a JSON string.
|
|
for (let depth = 0; depth < 2 && typeof value === "string" && /^[\s]*[\[{]/.test(value); depth += 1) {
|
|
try { value = JSON.parse(value); } catch { break; }
|
|
}
|
|
return JSON.stringify(debugState.debugSecretsVisible ? value : maskSensitiveDebugValue(value), null, 2);
|
|
} catch (error) {
|
|
return text;
|
|
}
|
|
}
|
|
|
|
function maskSensitiveDebugValue(value, parentKey = "") {
|
|
if (Array.isArray(value)) {
|
|
return value.map((item) => maskSensitiveDebugValue(item, parentKey));
|
|
}
|
|
|
|
if (!value || typeof value !== "object") {
|
|
return value;
|
|
}
|
|
|
|
return Object.fromEntries(Object.entries(value).map(([key, child]) => {
|
|
const isSensitive = isSensitiveDebugKey(key)
|
|
|| (key === "value" && /uiaasHeader|uiassHeader/i.test(parentKey));
|
|
return [key, isSensitive
|
|
? formatHiddenDebugValue(child)
|
|
: maskSensitiveDebugValue(child, key)];
|
|
}));
|
|
}
|
|
|
|
function isSensitiveDebugKey(key) {
|
|
return /authorization|cookie|password|secret|(^|[_-])token($|[_-])|token$/i.test(key);
|
|
}
|
|
|
|
function formatHiddenDebugValue(value) {
|
|
if (value === null || value === undefined || value === "") {
|
|
return "(missing)";
|
|
}
|
|
|
|
return `(present, ${String(value).length} characters)`;
|
|
}
|
|
|
|
function formatMetadataBlock(metadata) {
|
|
const entries = Object.entries(metadata);
|
|
|
|
if (entries.length === 0) {
|
|
return "(none)";
|
|
}
|
|
|
|
return entries
|
|
.map(([key, value]) => `${key}: ${value || "(none)"}`)
|
|
.join("\n");
|
|
}
|
|
|
|
function maskToken(token) {
|
|
if (token.length <= 10) {
|
|
return "(present)";
|
|
}
|
|
|
|
return `${token.slice(0, 4)}...${token.slice(-4)}`;
|
|
}
|
|
|
|
return { logRequestStart, logRequestSuccess, logRequestFailure, appendBackgroundRequestLog, readResponseBodyForDebug, createDebugBody, headersToObject, formatHeaderBlock, formatDebugBody, maskSensitiveDebugValue, isSensitiveDebugKey, formatHiddenDebugValue, formatMetadataBlock, maskToken };
|
|
}
|