Files
pikasTech-unidesk/scripts/src/hwlab-node-web-observe-runner-utility-source.ts
T

566 lines
24 KiB
TypeScript

// SPEC: PJ2026-01040111 long-running Workbench observation.
// Responsibility: Runner low-level IO, URL, YAML-derived policy parsing, redaction, and timeout utility source fragment.
export function nodeWebObserveRunnerUtilitySource(): string {
return String.raw`function appendJsonl(file, value) {
let line;
try {
line = JSON.stringify(sanitize(value)) + "\n";
} catch {
recordJsonlDrop(file, 0);
return Promise.resolve({ ok: false, dropped: true, reason: "json-encode-failed", valuesRedacted: true });
}
const bytes = Buffer.byteLength(line);
if (bytes > maxJsonlLineBytes) {
recordJsonlDrop(file, bytes);
return Promise.resolve({ ok: false, dropped: true, reason: "entry-too-large", bytes, maxJsonlLineBytes, valuesRedacted: true });
}
if (jsonlWriterState.queue.length >= maxJsonlQueueEntries || jsonlWriterState.queuedBytes + bytes > maxJsonlQueueBytes) {
recordJsonlDrop(file, bytes);
return Promise.resolve({ ok: false, dropped: true, reason: "queue-saturated", bytes, valuesRedacted: true });
}
jsonlWriterState.acceptedEntries += 1;
jsonlWriterState.acceptedBytes += bytes;
jsonlWriterState.queuedBytes += bytes;
const completion = new Promise((resolve) => jsonlWriterState.queue.push({ file, line, bytes, resolve }));
startJsonlPump();
return completion;
}
function recordJsonlDrop(file, bytes) {
jsonlWriterState.droppedEntries += 1;
jsonlWriterState.droppedBytes += Math.max(0, Number(bytes) || 0);
const key = path.basename(String(file || "unknown")).slice(0, 80);
jsonlWriterState.dropsByFile[key] = (jsonlWriterState.dropsByFile[key] || 0) + 1;
}
function startJsonlPump() {
if (jsonlWriterState.pump) return jsonlWriterState.pump;
jsonlWriterState.pump = (async () => {
while (jsonlWriterState.queue.length > 0) {
const entry = jsonlWriterState.queue.shift();
jsonlWriterState.queuedBytes = Math.max(0, jsonlWriterState.queuedBytes - entry.bytes);
jsonlWriterState.inFlight = 1;
try {
await appendFile(entry.file, entry.line, { mode: 0o600 });
jsonlWriterState.writtenEntries += 1;
jsonlWriterState.writtenBytes += entry.bytes;
entry.resolve({ ok: true, dropped: false, valuesRedacted: true });
} catch (error) {
jsonlWriterState.failedEntries += 1;
entry.resolve({ ok: false, dropped: false, error: errorSummary(error), valuesRedacted: true });
} finally {
jsonlWriterState.inFlight = 0;
}
}
})().finally(() => {
jsonlWriterState.pump = null;
if (jsonlWriterState.queue.length > 0) startJsonlPump();
});
return jsonlWriterState.pump;
}
function jsonlWriterStats() {
return {
queueEntries: jsonlWriterState.queue.length,
queueBytes: jsonlWriterState.queuedBytes,
inFlight: jsonlWriterState.inFlight,
maxQueueEntries: maxJsonlQueueEntries,
maxQueueBytes: maxJsonlQueueBytes,
maxLineBytes: maxJsonlLineBytes,
acceptedEntries: jsonlWriterState.acceptedEntries,
acceptedBytes: jsonlWriterState.acceptedBytes,
writtenEntries: jsonlWriterState.writtenEntries,
writtenBytes: jsonlWriterState.writtenBytes,
droppedEntries: jsonlWriterState.droppedEntries,
droppedBytes: jsonlWriterState.droppedBytes,
failedEntries: jsonlWriterState.failedEntries,
dropsByFile: { ...jsonlWriterState.dropsByFile },
valuesRedacted: true,
};
}
async function flushJsonlQueue() {
try {
await withHardTimeout((async () => {
while (jsonlWriterState.queue.length > 0 || jsonlWriterState.inFlight > 0 || jsonlWriterState.pump) {
if (jsonlWriterState.pump) await jsonlWriterState.pump;
else if (jsonlWriterState.queue.length > 0) await startJsonlPump();
else break;
}
})(), jsonlFlushTimeoutMs, "jsonl terminal flush exceeded " + jsonlFlushTimeoutMs + "ms");
return { ok: true, timedOut: false, stats: jsonlWriterStats(), valuesRedacted: true };
} catch (error) {
return { ok: false, timedOut: true, error: errorSummary(error), stats: jsonlWriterStats(), valuesRedacted: true };
}
}
async function fileMeta(file) {
const digestPromise = new Promise((resolve, reject) => {
const digest = createHash("sha256");
const stream = createReadStream(file);
stream.on("data", (chunk) => digest.update(chunk));
stream.once("error", reject);
stream.once("end", () => resolve("sha256:" + digest.digest("hex")));
});
const [sha256, stats] = await Promise.all([digestPromise, stat(file)]);
return { byteCount: stats.size, sha256 };
}
function responseBodyReadContract(response, maxBytes = responseBodyMaxBytes) {
let headers = {};
try { headers = response?.headers?.() || {}; } catch {}
const contentEncoding = String(headers["content-encoding"] || headers["Content-Encoding"] || "").trim().toLowerCase();
if (contentEncoding && contentEncoding !== "identity") {
return { ok: false, reason: "encoded-body-size-unbounded", contentEncoding: truncate(contentEncoding, 80), contentLength: null, maxBytes, valuesRedacted: true };
}
const rawContentLength = headers["content-length"] || headers["Content-Length"];
const contentLength = Number(rawContentLength);
if (!Number.isFinite(contentLength) || contentLength < 0) {
return { ok: false, reason: "content-length-unavailable", contentLength: null, maxBytes, valuesRedacted: true };
}
if (contentLength > maxBytes) {
return { ok: false, reason: "content-length-too-large", contentLength, maxBytes, valuesRedacted: true };
}
return { ok: true, reason: null, contentLength, maxBytes, valuesRedacted: true };
}
async function boundedResponseJson(response, maxBytes = responseBodyMaxBytes) {
const bodyContract = responseBodyReadContract(response, maxBytes);
if (bodyContract.ok !== true) return { ok: false, value: null, error: bodyContract, bodyContract, valuesRedacted: true };
const permit = tryAcquireResponseBodyPermit();
if (!permit) return { ok: false, value: null, error: { reason: "response-body-inflight-saturated", valuesRedacted: true }, bodyContract, valuesRedacted: true };
try {
const value = await response.json();
responseBodyState.completed += 1;
return { ok: true, value, error: null, bodyContract, valuesRedacted: true };
} catch (error) {
responseBodyState.failed += 1;
return { ok: false, value: null, error: errorSummary(error), bodyContract, valuesRedacted: true };
} finally {
permit.release();
}
}
async function boundedResponseText(response, maxBytes = responseBodyMaxBytes) {
const bodyContract = responseBodyReadContract(response, maxBytes);
if (bodyContract.ok !== true) return { ok: false, value: null, error: bodyContract, bodyContract, valuesRedacted: true };
const permit = tryAcquireResponseBodyPermit();
if (!permit) return { ok: false, value: null, error: { reason: "response-body-inflight-saturated", valuesRedacted: true }, bodyContract, valuesRedacted: true };
try {
const value = await response.text();
responseBodyState.completed += 1;
return { ok: true, value, error: null, bodyContract, valuesRedacted: true };
} catch (error) {
responseBodyState.failed += 1;
return { ok: false, value: null, error: errorSummary(error), bodyContract, valuesRedacted: true };
} finally {
permit.release();
}
}
function tryAcquireResponseBodyPermit() {
if (responseBodyState.inFlight >= maxResponseBodyInFlight) {
responseBodyState.skippedSaturated += 1;
return null;
}
responseBodyState.inFlight += 1;
responseBodyState.accepted += 1;
let released = false;
return { release() { if (released) return; released = true; responseBodyState.inFlight = Math.max(0, responseBodyState.inFlight - 1); } };
}
function responseBodyStats() {
return { ...responseBodyState, maxInFlight: maxResponseBodyInFlight, valuesRedacted: true };
}
function trackPassiveTask(factory, label) {
if (stopping || passiveTaskState.tasks.size >= maxPassiveListenerTasks) {
passiveTaskState.dropped += 1;
return false;
}
passiveTaskState.accepted += 1;
let task;
task = Promise.resolve()
.then(factory)
.then(() => { passiveTaskState.completed += 1; })
.catch(async (error) => {
passiveTaskState.failed += 1;
await appendJsonl(files.errors, eventRecord("passive-task-error", { label, error: errorSummary(error), valuesRedacted: true })).catch(() => {});
})
.finally(() => passiveTaskState.tasks.delete(task));
passiveTaskState.tasks.add(task);
task.catch(() => {});
return true;
}
function passiveTaskStats() {
return {
inFlight: passiveTaskState.tasks.size,
maxInFlight: maxPassiveListenerTasks,
accepted: passiveTaskState.accepted,
dropped: passiveTaskState.dropped,
completed: passiveTaskState.completed,
failed: passiveTaskState.failed,
drainTimedOut: passiveTaskState.drainTimedOut,
valuesRedacted: true,
};
}
async function drainPassiveTasks() {
try {
await withHardTimeout((async () => {
while (passiveTaskState.tasks.size > 0) await Promise.allSettled([...passiveTaskState.tasks]);
})(), passiveTaskFlushTimeoutMs, "passive task drain exceeded " + passiveTaskFlushTimeoutMs + "ms");
return { ok: true, timedOut: false, stats: passiveTaskStats(), valuesRedacted: true };
} catch (error) {
passiveTaskState.drainTimedOut = true;
return { ok: false, timedOut: true, error: errorSummary(error), stats: passiveTaskStats(), valuesRedacted: true };
}
}
function currentPageUrl() {
return pageUrl(page);
}
function pageUrl(targetPage) {
try { return targetPage && !targetPage.isClosed() ? targetPage.url() : null; } catch { return null; }
}
function routeSessionIdFromUrl(value) {
try {
const pathname = new URL(String(value || ""), baseUrl).pathname;
const match = pathname.match(/\/workbench\/sessions\/([^/?#]+)/u);
return match ? decodeURIComponent(match[1] || "") : null;
} catch {
return null;
}
}
function safeFrameUrl(frame) {
try { return frame ? safeUrl(frame.url()) : null; } catch { return null; }
}
function safeUrl(value) {
try {
const url = new URL(String(value), baseUrl);
for (const key of Array.from(url.searchParams.keys())) {
if (/token|key|secret|password|auth|cookie/iu.test(key)) url.searchParams.set(key, "[redacted]");
}
return url.toString();
} catch {
return truncate(String(value || ""), 300);
}
}
function safeUrlPath(value) {
try {
return new URL(String(value || ""), baseUrl).pathname;
} catch {
return null;
}
}
function normalizeBaseUrl(value) {
const raw = value || "http://127.0.0.1:3000";
const url = new URL(raw);
return url.origin;
}
function parseViewport(value) {
const match = String(value).match(/^(\d{3,5})x(\d{3,5})$/u);
return match ? { width: Number(match[1]), height: Number(match[2]) } : { width: 1440, height: 900 };
}
function positiveInteger(value, fallback) {
const parsed = Number(value);
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : fallback;
}
function boundedInteger(value, fallback, min, max) {
const parsed = Number(value);
if (!Number.isFinite(parsed)) return fallback;
const integer = Math.floor(parsed);
if (integer < min || integer > max) return fallback;
return integer;
}
function requiredBoundedInteger(value, name, min, max) {
const parsed = Number(value);
if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
throw new Error(name + " must come from the owning YAML and be an integer between " + min + " and " + max);
}
return parsed;
}
function positiveNumber(value, fallback) {
const parsed = Number(value);
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
}
function numberOrNull(value) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
function requiredPositiveThreshold(raw, key) {
const parsed = Number(raw?.[key]);
if (!Number.isFinite(parsed) || parsed <= 0) {
throw new Error("UNIDESK_WEB_OBSERVE_ALERT_THRESHOLDS_JSON requires positive " + key + "; configure config/hwlab-node-lanes.yaml webProbe.alertThresholds");
}
return parsed;
}
function parseAlertThresholds(value) {
if (!value) {
throw new Error("UNIDESK_WEB_OBSERVE_ALERT_THRESHOLDS_JSON is required; configure config/hwlab-node-lanes.yaml webProbe.alertThresholds for the selected node/lane");
}
const raw = (() => {
try { return JSON.parse(value); } catch (error) { throw new Error("UNIDESK_WEB_OBSERVE_ALERT_THRESHOLDS_JSON is invalid JSON: " + (error instanceof Error ? error.message : String(error))); }
})();
const sessionRailFallbackRatio = requiredPositiveThreshold(raw, "sessionRailFallbackRatio");
if (sessionRailFallbackRatio > 1) {
throw new Error("UNIDESK_WEB_OBSERVE_ALERT_THRESHOLDS_JSON sessionRailFallbackRatio must be <= 1");
}
return {
sameOriginApiSlowMs: requiredPositiveThreshold(raw, "sameOriginApiSlowMs"),
partialApiSlowMs: requiredPositiveThreshold(raw, "partialApiSlowMs"),
longLivedStreamOpenSlowMs: requiredPositiveThreshold(raw, "longLivedStreamOpenSlowMs"),
visibleLoadingSlowMs: requiredPositiveThreshold(raw, "visibleLoadingSlowMs"),
turnTimingSampleSlackSeconds: requiredPositiveThreshold(raw, "turnTimingSampleSlackSeconds"),
turnElapsedSevereTimeoutSeconds: requiredPositiveThreshold(raw, "turnElapsedSevereTimeoutSeconds"),
domEvaluateTimeoutRedCount: requiredPositiveThreshold(raw, "domEvaluateTimeoutRedCount"),
domEvaluateTimeoutRedWindowMs: requiredPositiveThreshold(raw, "domEvaluateTimeoutRedWindowMs"),
screenshotTimeoutRedCount: requiredPositiveThreshold(raw, "screenshotTimeoutRedCount"),
pageErrorRedCount: requiredPositiveThreshold(raw, "pageErrorRedCount"),
longTaskRedMs: requiredPositiveThreshold(raw, "longTaskRedMs"),
longAnimationFrameRedMs: requiredPositiveThreshold(raw, "longAnimationFrameRedMs"),
eventLoopGapRedMs: requiredPositiveThreshold(raw, "eventLoopGapRedMs"),
browserProcessSampleIntervalMs: requiredPositiveThreshold(raw, "browserProcessSampleIntervalMs"),
requestRateBucketMs: requiredPositiveThreshold(raw, "requestRateBucketMs"),
requestRateTotalRedPerMinute: requiredPositiveThreshold(raw, "requestRateTotalRedPerMinute"),
requestRatePageRedPerMinute: requiredPositiveThreshold(raw, "requestRatePageRedPerMinute"),
requestRateApiPathRedPerMinute: requiredPositiveThreshold(raw, "requestRateApiPathRedPerMinute"),
browserTotalRssRedMb: requiredPositiveThreshold(raw, "browserTotalRssRedMb"),
browserProcessRssRedMb: requiredPositiveThreshold(raw, "browserProcessRssRedMb"),
browserRssGrowthRedMb: requiredPositiveThreshold(raw, "browserRssGrowthRedMb"),
browserRssGrowthWindowMs: requiredPositiveThreshold(raw, "browserRssGrowthWindowMs"),
playwrightResponsivenessRedMs: requiredPositiveThreshold(raw, "playwrightResponsivenessRedMs"),
playwrightResponsivenessTimeoutRedCount: requiredPositiveThreshold(raw, "playwrightResponsivenessTimeoutRedCount"),
cdpMetricsTimeoutRedCount: requiredPositiveThreshold(raw, "cdpMetricsTimeoutRedCount"),
uncommandedStateChangeCommandWindowMs: requiredPositiveThreshold(raw, "uncommandedStateChangeCommandWindowMs"),
scrollJumpCommandWindowMs: requiredPositiveThreshold(raw, "scrollJumpCommandWindowMs"),
scrollJumpFromY: requiredPositiveThreshold(raw, "scrollJumpFromY"),
scrollJumpToY: requiredPositiveThreshold(raw, "scrollJumpToY"),
sessionRailFallbackRatio,
crossPageProjectionDivergenceRedMs: positiveNumber(raw.crossPageProjectionDivergenceRedMs, requiredPositiveThreshold(raw, "visibleLoadingSlowMs")),
source: "yaml-env",
};
}
function parseBrowserFreezePolicy(value) {
if (!value) {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON is required; configure config/hwlab-node-lanes.yaml webProbe.browserFreezePolicy for the selected node/lane");
}
const raw = (() => {
try { return JSON.parse(value); } catch (error) { throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON is invalid JSON: " + (error instanceof Error ? error.message : String(error))); }
})();
const memory = requiredPolicyRecord(raw, "memory", "webProbe.browserFreezePolicy");
const responsiveness = requiredPolicyRecord(raw, "responsiveness", "webProbe.browserFreezePolicy");
const cdp = requiredPolicyRecord(raw, "cdp", "webProbe.browserFreezePolicy");
const kill = requiredPolicyRecord(raw, "kill", "webProbe.browserFreezePolicy");
return {
enabled: requiredPolicyBoolean(raw, "enabled", "webProbe.browserFreezePolicy"),
blockerWindowMs: requiredPolicyPositiveNumber(raw, "blockerWindowMs", "webProbe.browserFreezePolicy"),
memory: {
totalRssBlockerMb: requiredPolicyPositiveNumber(memory, "totalRssBlockerMb", "webProbe.browserFreezePolicy.memory"),
processRssBlockerMb: requiredPolicyPositiveNumber(memory, "processRssBlockerMb", "webProbe.browserFreezePolicy.memory"),
growthBlockerMb: requiredPolicyPositiveNumber(memory, "growthBlockerMb", "webProbe.browserFreezePolicy.memory"),
},
responsiveness: {
latencyBlockerMs: requiredPolicyPositiveNumber(responsiveness, "latencyBlockerMs", "webProbe.browserFreezePolicy.responsiveness"),
eventBlockerCount: requiredPolicyPositiveNumber(responsiveness, "eventBlockerCount", "webProbe.browserFreezePolicy.responsiveness"),
},
cdp: {
metricsTimeoutBlockerCount: requiredPolicyPositiveNumber(cdp, "metricsTimeoutBlockerCount", "webProbe.browserFreezePolicy.cdp"),
},
kill: {
enabled: requiredPolicyBoolean(kill, "enabled", "webProbe.browserFreezePolicy.kill"),
gracefulSignal: requiredPolicySignal(kill, "gracefulSignal", "webProbe.browserFreezePolicy.kill", "SIGTERM"),
forceSignal: requiredPolicySignal(kill, "forceSignal", "webProbe.browserFreezePolicy.kill", "SIGKILL"),
graceMs: requiredPolicyIntegerInRange(kill, "graceMs", "webProbe.browserFreezePolicy.kill", 1, 120000),
pollIntervalMs: requiredPolicyIntegerInRange(kill, "pollIntervalMs", "webProbe.browserFreezePolicy.kill", 1, 10000),
exitCode: requiredPolicyIntegerInRange(kill, "exitCode", "webProbe.browserFreezePolicy.kill", 1, 125),
},
source: "yaml-env",
valuesRedacted: true,
};
}
function requiredPolicyRecord(raw, key, pathLabel) {
const value = raw?.[key];
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON requires object " + pathLabel + "." + key);
}
return value;
}
function requiredPolicyBoolean(raw, key, pathLabel) {
const value = raw?.[key];
if (typeof value !== "boolean") {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON requires boolean " + pathLabel + "." + key);
}
return value;
}
function requiredPolicyPositiveNumber(raw, key, pathLabel) {
const value = Number(raw?.[key]);
if (!Number.isFinite(value) || value <= 0) {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON requires positive number " + pathLabel + "." + key);
}
return value;
}
function requiredPolicyIntegerInRange(raw, key, pathLabel, min, max) {
const value = Number(raw?.[key]);
if (!Number.isInteger(value) || value < min || value > max) {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON requires integer " + pathLabel + "." + key + " between " + min + " and " + max);
}
return value;
}
function requiredPolicySignal(raw, key, pathLabel, expected) {
const value = String(raw?.[key] || "");
if (value !== expected) {
throw new Error("UNIDESK_WEB_OBSERVE_BROWSER_FREEZE_POLICY_JSON requires " + pathLabel + "." + key + "=" + expected);
}
return value;
}
function parseProjectManagementConfig(value) {
if (!value || value === "null") {
return {
enabled: false,
targetPaths: [],
readinessSelectors: [],
naturalApiPathPrefixes: [],
commandAllowlist: [],
launchRoute: "",
slowApiBudgetMs: 0,
source: "yaml-env",
valuesRedacted: true
};
}
const raw = (() => {
try { return JSON.parse(value); } catch (error) { throw new Error("UNIDESK_WEB_OBSERVE_PROJECT_MANAGEMENT_JSON is invalid JSON: " + (error instanceof Error ? error.message : String(error))); }
})();
const stringList = (key) => {
const list = raw?.[key];
if (!Array.isArray(list) || list.some((item) => typeof item !== "string" || item.length === 0)) throw new Error("UNIDESK_WEB_OBSERVE_PROJECT_MANAGEMENT_JSON requires string[] " + key + "; configure config/hwlab-node-lanes.yaml webProbe.projectManagement");
return list;
};
const positive = (key) => {
const numeric = Number(raw?.[key]);
if (!Number.isFinite(numeric) || numeric <= 0) throw new Error("UNIDESK_WEB_OBSERVE_PROJECT_MANAGEMENT_JSON requires positive " + key + "; configure config/hwlab-node-lanes.yaml webProbe.projectManagement");
return numeric;
};
if (raw?.enabled !== true && raw?.enabled !== false) throw new Error("UNIDESK_WEB_OBSERVE_PROJECT_MANAGEMENT_JSON requires boolean enabled");
if (raw.enabled !== true) return { enabled: false, targetPaths: [], readinessSelectors: [], naturalApiPathPrefixes: [], commandAllowlist: [], launchRoute: "", slowApiBudgetMs: 0, source: "yaml-env", valuesRedacted: true };
const targetPaths = stringList("targetPaths");
const readinessSelectors = stringList("readinessSelectors");
const naturalApiPathPrefixes = stringList("naturalApiPathPrefixes");
const commandAllowlist = stringList("commandAllowlist");
const launchRoute = String(raw.launchRoute || "");
if (!launchRoute.startsWith("/")) throw new Error("UNIDESK_WEB_OBSERVE_PROJECT_MANAGEMENT_JSON launchRoute must be an absolute path");
return {
enabled: true,
targetPaths,
readinessSelectors,
naturalApiPathPrefixes,
commandAllowlist,
launchRoute,
slowApiBudgetMs: positive("slowApiBudgetMs"),
source: "yaml-env",
valuesRedacted: true
};
}
function sha256Text(value) {
return "sha256:" + createHash("sha256").update(String(value)).digest("hex");
}
function safeId(value) {
return String(value || "").replace(/[^A-Za-z0-9_.-]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 120) || "item";
}
function cssEscape(value) {
return String(value).replace(/\\/gu, "\\\\").replace(/"/gu, "\\\"");
}
function truncate(value, limit) {
const text = String(value || "");
return text.length > limit ? text.slice(0, limit) + "..." : text;
}
function sanitize(value) {
if (value === null || value === undefined) return value;
if (typeof value === "string") return value === password ? "[redacted]" : value.replaceAll(password, "[redacted]");
if (typeof value === "number" || typeof value === "boolean") return value;
if (Array.isArray(value)) return value.map(sanitize);
if (typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => /password|cookie|authorization|token|secret/iu.test(key) ? [key, "[redacted]"] : [key, sanitize(item)]));
return String(value);
}
function errorSummary(error) {
const summary = { name: error && error.name ? error.name : "Error", message: error && error.message ? truncate(error.message, 1000) : truncate(String(error), 1000), stackTail: error && error.stack ? truncate(error.stack, 2000) : null };
if (error && error.webProbeAuth) summary.auth = sanitize(error.webProbeAuth);
if (error && Array.isArray(error.attempts)) summary.attempts = sanitize(error.attempts.slice(-5));
if (error && error.navigationReadiness) summary.navigationReadiness = sanitize(error.navigationReadiness);
if (error && error.details) summary.details = sanitize(error.details);
if (error && error.target) summary.target = sanitize(error.target);
return summary;
}
function sleep(ms) {
return interruptibleRunnerSleep(ms);
}
function boundedCleanupSleep(ms) {
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
}
function interruptibleRunnerSleep(ms) {
if (stopping) return Promise.resolve();
return new Promise((resolve) => {
const timer = setTimeout(() => {
runnerSleepWakes.delete(wake);
resolve();
}, Math.max(0, ms));
const wake = () => {
clearTimeout(timer);
runnerSleepWakes.delete(wake);
resolve();
};
runnerSleepWakes.add(wake);
});
}
function interruptRunnerSleep() {
for (const wake of [...runnerSleepWakes]) wake();
}
function withHardTimeout(promise, timeoutMs, message) {
const guarded = Promise.resolve(promise);
let timer = null;
const timeout = new Promise((_, reject) => {
timer = setTimeout(() => reject(new Error(message)), Math.max(1, Number(timeoutMs) || 1));
if (timer && typeof timer.unref === "function") timer.unref();
});
return Promise.race([guarded, timeout]).finally(() => {
if (timer) clearTimeout(timer);
guarded.catch(() => {});
});
}
`;
}