chore(frontend): introduce prettier + eslint and prune unused code
- Add Prettier 3 with prettier-plugin-organize-imports (sorts/removes unused imports) - Add ESLint 10 flat config with typescript-eslint + eslint-plugin-vue + eslint-config-prettier - Add root scripts: format, format:check, lint, lint:fix - Reformat 257 files across admin-web, ops-web, desktop-client, packages - Remove unused locals/exports flagged by --noUnusedLocals/--noUnusedParameters - Fix duplicate localTabLabel key, surrogate-pair regex u-flag, NBSP literal in regex - Skip server/ (Go) and apps/browser-extension/ (deprecated per ADR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,100 +1,100 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { randomUUID } from 'node:crypto'
|
||||
|
||||
import { app } from "electron/main";
|
||||
import type { Session, WebContents } from "electron/main";
|
||||
import type { Session, WebContents } from 'electron/main'
|
||||
import { app } from 'electron/main'
|
||||
|
||||
import type {
|
||||
DesktopObservedRequest,
|
||||
DesktopObservedRequestKind,
|
||||
DesktopObservedRequestSnapshot,
|
||||
DesktopObservedRequestSource,
|
||||
} from "../shared/network-debug";
|
||||
} from '../shared/network-debug'
|
||||
|
||||
interface ActiveObservedRequest {
|
||||
id: string;
|
||||
startedAt: number;
|
||||
kind: DesktopObservedRequestKind;
|
||||
source: DesktopObservedRequestSource;
|
||||
label: string;
|
||||
method: string;
|
||||
url: string;
|
||||
partition: string | null;
|
||||
resourceType: string | null;
|
||||
id: string
|
||||
startedAt: number
|
||||
kind: DesktopObservedRequestKind
|
||||
source: DesktopObservedRequestSource
|
||||
label: string
|
||||
method: string
|
||||
url: string
|
||||
partition: string | null
|
||||
resourceType: string | null
|
||||
}
|
||||
|
||||
interface StartObservedRequestOptions {
|
||||
kind?: DesktopObservedRequestKind;
|
||||
source?: DesktopObservedRequestSource;
|
||||
label: string;
|
||||
method?: string;
|
||||
url: string;
|
||||
partition?: string | null;
|
||||
resourceType?: string | null;
|
||||
kind?: DesktopObservedRequestKind
|
||||
source?: DesktopObservedRequestSource
|
||||
label: string
|
||||
method?: string
|
||||
url: string
|
||||
partition?: string | null
|
||||
resourceType?: string | null
|
||||
}
|
||||
|
||||
const observedSessions = new WeakSet<Session>();
|
||||
const activeRequests = new Map<string, ActiveObservedRequest>();
|
||||
const observedRecords: DesktopObservedRequest[] = [];
|
||||
const maxObservedRecords = 240;
|
||||
const observedSessions = new WeakSet<Session>()
|
||||
const activeRequests = new Map<string, ActiveObservedRequest>()
|
||||
const observedRecords: DesktopObservedRequest[] = []
|
||||
const maxObservedRecords = 240
|
||||
const requestFilter = {
|
||||
urls: ["http://*/*", "https://*/*", "ws://*/*", "wss://*/*"],
|
||||
};
|
||||
const redactedQueryKeys = /token|signature|sig|auth|key|password|session/i;
|
||||
const networkObserverEnabled = !app.isPackaged;
|
||||
urls: ['http://*/*', 'https://*/*', 'ws://*/*', 'wss://*/*'],
|
||||
}
|
||||
const redactedQueryKeys = /token|signature|sig|auth|key|password|session/i
|
||||
const networkObserverEnabled = !app.isPackaged
|
||||
|
||||
let rendererTarget: WebContents | null = null;
|
||||
let originalFetch: typeof globalThis.fetch | null = null;
|
||||
let rendererTarget: WebContents | null = null
|
||||
let originalFetch: typeof globalThis.fetch | null = null
|
||||
|
||||
export function installObservedGlobalFetch(): void {
|
||||
if (!networkObserverEnabled) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if (originalFetch || typeof globalThis.fetch !== "function") {
|
||||
return;
|
||||
if (originalFetch || typeof globalThis.fetch !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
originalFetch = globalThis.fetch.bind(globalThis);
|
||||
originalFetch = globalThis.fetch.bind(globalThis)
|
||||
globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const url = requestURL(input);
|
||||
const url = requestURL(input)
|
||||
if (!url || !isInspectableURL(url) || !originalFetch) {
|
||||
return originalFetch!(input, init);
|
||||
return originalFetch!(input, init)
|
||||
}
|
||||
|
||||
const method = requestMethod(input, init);
|
||||
const method = requestMethod(input, init)
|
||||
const requestId = startObservedRequest({
|
||||
kind: inferKindFromHeaders(input, init),
|
||||
source: "main",
|
||||
label: "main.fetch",
|
||||
source: 'main',
|
||||
label: 'main.fetch',
|
||||
method,
|
||||
url,
|
||||
});
|
||||
})
|
||||
|
||||
try {
|
||||
const response = await originalFetch(input, init);
|
||||
const response = await originalFetch(input, init)
|
||||
resolveObservedRequest(requestId, {
|
||||
phase: "response",
|
||||
phase: 'response',
|
||||
status: response.status,
|
||||
});
|
||||
return response;
|
||||
})
|
||||
return response
|
||||
} catch (error) {
|
||||
failObservedRequest(requestId, error);
|
||||
throw error;
|
||||
failObservedRequest(requestId, error)
|
||||
throw error
|
||||
}
|
||||
}) as typeof globalThis.fetch;
|
||||
}) as typeof globalThis.fetch
|
||||
}
|
||||
|
||||
export function registerObservedRequestRendererTarget(webContents: WebContents): void {
|
||||
if (!networkObserverEnabled) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
rendererTarget = webContents;
|
||||
webContents.once("destroyed", () => {
|
||||
rendererTarget = webContents
|
||||
webContents.once('destroyed', () => {
|
||||
if (rendererTarget === webContents) {
|
||||
rendererTarget = null;
|
||||
rendererTarget = null
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
export function observeSessionRequests(
|
||||
@@ -102,158 +102,172 @@ export function observeSessionRequests(
|
||||
options: { label: string; partition?: string | null },
|
||||
): void {
|
||||
if (!networkObserverEnabled) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
if (observedSessions.has(target)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
observedSessions.add(target);
|
||||
observedSessions.add(target)
|
||||
|
||||
target.webRequest.onBeforeRequest(requestFilter, (details, callback) => {
|
||||
if (!isInspectableURL(details.url)) {
|
||||
callback({});
|
||||
return;
|
||||
callback({})
|
||||
return
|
||||
}
|
||||
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null);
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null)
|
||||
activeRequests.set(requestId, {
|
||||
id: requestId,
|
||||
startedAt: Date.now(),
|
||||
kind: details.resourceType === "webSocket" ? "ws" : "http",
|
||||
source: "session",
|
||||
kind: details.resourceType === 'webSocket' ? 'ws' : 'http',
|
||||
source: 'session',
|
||||
label: options.label,
|
||||
method: normalizeMethod(details.method),
|
||||
url: sanitizeURL(details.url),
|
||||
partition: options.partition ?? null,
|
||||
resourceType: normalizeResourceType(details.resourceType),
|
||||
});
|
||||
})
|
||||
|
||||
pushRecord(buildRecord(activeRequests.get(requestId)!, {
|
||||
at: Date.now(),
|
||||
phase: "request",
|
||||
}));
|
||||
pushRecord(
|
||||
buildRecord(activeRequests.get(requestId)!, {
|
||||
at: Date.now(),
|
||||
phase: 'request',
|
||||
}),
|
||||
)
|
||||
|
||||
callback({});
|
||||
});
|
||||
callback({})
|
||||
})
|
||||
|
||||
target.webRequest.onCompleted(requestFilter, (details) => {
|
||||
if (!isInspectableURL(details.url)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null);
|
||||
const active = activeRequests.get(requestId)
|
||||
?? createFallbackActiveRequest(requestId, {
|
||||
source: "session",
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null)
|
||||
const active =
|
||||
activeRequests.get(requestId) ??
|
||||
createFallbackActiveRequest(requestId, {
|
||||
source: 'session',
|
||||
label: options.label,
|
||||
method: normalizeMethod(details.method),
|
||||
url: details.url,
|
||||
partition: options.partition ?? null,
|
||||
resourceType: normalizeResourceType(details.resourceType),
|
||||
});
|
||||
})
|
||||
|
||||
pushRecord(buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: "response",
|
||||
status: details.statusCode,
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
}));
|
||||
activeRequests.delete(requestId);
|
||||
});
|
||||
pushRecord(
|
||||
buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: 'response',
|
||||
status: details.statusCode,
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
}),
|
||||
)
|
||||
activeRequests.delete(requestId)
|
||||
})
|
||||
|
||||
target.webRequest.onErrorOccurred(requestFilter, (details) => {
|
||||
if (!isInspectableURL(details.url)) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null);
|
||||
const active = activeRequests.get(requestId)
|
||||
?? createFallbackActiveRequest(requestId, {
|
||||
source: "session",
|
||||
const requestId = sessionRequestId(details.id, options.partition ?? null)
|
||||
const active =
|
||||
activeRequests.get(requestId) ??
|
||||
createFallbackActiveRequest(requestId, {
|
||||
source: 'session',
|
||||
label: options.label,
|
||||
method: normalizeMethod(details.method),
|
||||
url: details.url,
|
||||
partition: options.partition ?? null,
|
||||
resourceType: normalizeResourceType(details.resourceType),
|
||||
});
|
||||
})
|
||||
|
||||
pushRecord(buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: "error",
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: normalizeErrorMessage(details.error),
|
||||
}));
|
||||
activeRequests.delete(requestId);
|
||||
});
|
||||
pushRecord(
|
||||
buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: 'error',
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: normalizeErrorMessage(details.error),
|
||||
}),
|
||||
)
|
||||
activeRequests.delete(requestId)
|
||||
})
|
||||
}
|
||||
|
||||
export function startObservedRequest(options: StartObservedRequestOptions): string {
|
||||
if (!networkObserverEnabled) {
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
const id = `main:${randomUUID()}`;
|
||||
const id = `main:${randomUUID()}`
|
||||
const active: ActiveObservedRequest = {
|
||||
id,
|
||||
startedAt: Date.now(),
|
||||
kind: options.kind ?? "http",
|
||||
source: options.source ?? "main",
|
||||
kind: options.kind ?? 'http',
|
||||
source: options.source ?? 'main',
|
||||
label: options.label,
|
||||
method: normalizeMethod(options.method),
|
||||
url: sanitizeURL(options.url),
|
||||
partition: options.partition ?? null,
|
||||
resourceType: options.resourceType ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
activeRequests.set(id, active);
|
||||
pushRecord(buildRecord(active, {
|
||||
at: active.startedAt,
|
||||
phase: "request",
|
||||
}));
|
||||
return id;
|
||||
activeRequests.set(id, active)
|
||||
pushRecord(
|
||||
buildRecord(active, {
|
||||
at: active.startedAt,
|
||||
phase: 'request',
|
||||
}),
|
||||
)
|
||||
return id
|
||||
}
|
||||
|
||||
export function resolveObservedRequest(
|
||||
id: string,
|
||||
options: {
|
||||
phase?: "response" | "close";
|
||||
status?: number | null;
|
||||
error?: string | null;
|
||||
keepActive?: boolean;
|
||||
phase?: 'response' | 'close'
|
||||
status?: number | null
|
||||
error?: string | null
|
||||
keepActive?: boolean
|
||||
} = {},
|
||||
): void {
|
||||
const active = activeRequests.get(id);
|
||||
const active = activeRequests.get(id)
|
||||
if (!active) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
pushRecord(buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: options.phase ?? "response",
|
||||
status: options.status ?? null,
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: options.error ?? null,
|
||||
}));
|
||||
pushRecord(
|
||||
buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: options.phase ?? 'response',
|
||||
status: options.status ?? null,
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: options.error ?? null,
|
||||
}),
|
||||
)
|
||||
|
||||
if (!options.keepActive) {
|
||||
activeRequests.delete(id);
|
||||
activeRequests.delete(id)
|
||||
}
|
||||
}
|
||||
|
||||
export function failObservedRequest(id: string, error: unknown): void {
|
||||
const active = activeRequests.get(id);
|
||||
const active = activeRequests.get(id)
|
||||
if (!active) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
pushRecord(buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: "error",
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: normalizeErrorMessage(error),
|
||||
}));
|
||||
activeRequests.delete(id);
|
||||
pushRecord(
|
||||
buildRecord(active, {
|
||||
at: Date.now(),
|
||||
phase: 'error',
|
||||
durationMs: Date.now() - active.startedAt,
|
||||
error: normalizeErrorMessage(error),
|
||||
}),
|
||||
)
|
||||
activeRequests.delete(id)
|
||||
}
|
||||
|
||||
export function getObservedRequestSnapshot(): DesktopObservedRequestSnapshot {
|
||||
@@ -262,135 +276,140 @@ export function getObservedRequestSnapshot(): DesktopObservedRequestSnapshot {
|
||||
rendererAttached: false,
|
||||
activeCount: 0,
|
||||
recent: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
rendererAttached: Boolean(rendererTarget && !rendererTarget.isDestroyed()),
|
||||
activeCount: activeRequests.size,
|
||||
recent: observedRecords.slice(-80),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function requestURL(input: RequestInfo | URL): string | null {
|
||||
if (typeof input === "string") {
|
||||
return input;
|
||||
if (typeof input === 'string') {
|
||||
return input
|
||||
}
|
||||
if (input instanceof URL) {
|
||||
return input.toString();
|
||||
return input.toString()
|
||||
}
|
||||
return typeof input.url === "string" ? input.url : null;
|
||||
return typeof input.url === 'string' ? input.url : null
|
||||
}
|
||||
|
||||
function requestMethod(input: RequestInfo | URL, init?: RequestInit): string {
|
||||
if (init?.method) {
|
||||
return normalizeMethod(init.method);
|
||||
return normalizeMethod(init.method)
|
||||
}
|
||||
if (typeof Request !== "undefined" && input instanceof Request) {
|
||||
return normalizeMethod(input.method);
|
||||
if (typeof Request !== 'undefined' && input instanceof Request) {
|
||||
return normalizeMethod(input.method)
|
||||
}
|
||||
return "GET";
|
||||
return 'GET'
|
||||
}
|
||||
|
||||
function inferKindFromHeaders(input: RequestInfo | URL, init?: RequestInit): DesktopObservedRequestKind {
|
||||
const headers = new Headers(init?.headers);
|
||||
if (!headers.has("accept") && typeof Request !== "undefined" && input instanceof Request) {
|
||||
const requestAccept = input.headers.get("accept");
|
||||
function inferKindFromHeaders(
|
||||
input: RequestInfo | URL,
|
||||
init?: RequestInit,
|
||||
): DesktopObservedRequestKind {
|
||||
const headers = new Headers(init?.headers)
|
||||
if (!headers.has('accept') && typeof Request !== 'undefined' && input instanceof Request) {
|
||||
const requestAccept = input.headers.get('accept')
|
||||
if (requestAccept) {
|
||||
headers.set("accept", requestAccept);
|
||||
headers.set('accept', requestAccept)
|
||||
}
|
||||
}
|
||||
|
||||
const accept = headers.get("accept")?.toLowerCase() ?? "";
|
||||
if (accept.includes("text/event-stream")) {
|
||||
return "sse";
|
||||
const accept = headers.get('accept')?.toLowerCase() ?? ''
|
||||
if (accept.includes('text/event-stream')) {
|
||||
return 'sse'
|
||||
}
|
||||
return "http";
|
||||
return 'http'
|
||||
}
|
||||
|
||||
function isInspectableURL(url: string): boolean {
|
||||
try {
|
||||
const protocol = new URL(url).protocol;
|
||||
return protocol === "http:" || protocol === "https:" || protocol === "ws:" || protocol === "wss:";
|
||||
const protocol = new URL(url).protocol
|
||||
return (
|
||||
protocol === 'http:' || protocol === 'https:' || protocol === 'ws:' || protocol === 'wss:'
|
||||
)
|
||||
} catch {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function sanitizeURL(url: string): string {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const parsed = new URL(url)
|
||||
for (const key of parsed.searchParams.keys()) {
|
||||
if (redactedQueryKeys.test(key)) {
|
||||
parsed.searchParams.set(key, "[REDACTED]");
|
||||
parsed.searchParams.set(key, '[REDACTED]')
|
||||
}
|
||||
}
|
||||
return parsed.toString();
|
||||
return parsed.toString()
|
||||
} catch {
|
||||
return url;
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeMethod(value: string | undefined | null): string {
|
||||
return typeof value === "string" && value.trim() ? value.trim().toUpperCase() : "GET";
|
||||
return typeof value === 'string' && value.trim() ? value.trim().toUpperCase() : 'GET'
|
||||
}
|
||||
|
||||
function normalizeResourceType(value: unknown): string | null {
|
||||
return typeof value === "string" && value.trim() ? value : null;
|
||||
return typeof value === 'string' && value.trim() ? value : null
|
||||
}
|
||||
|
||||
function normalizeErrorMessage(error: unknown): string {
|
||||
if (typeof error === "string" && error.trim()) {
|
||||
return error;
|
||||
if (typeof error === 'string' && error.trim()) {
|
||||
return error
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return error.message || error.name || "request_failed";
|
||||
return error.message || error.name || 'request_failed'
|
||||
}
|
||||
if (error && typeof error === "object" && "message" in error) {
|
||||
const message = (error as { message?: unknown }).message;
|
||||
if (typeof message === "string" && message.trim()) {
|
||||
return message;
|
||||
if (error && typeof error === 'object' && 'message' in error) {
|
||||
const message = (error as { message?: unknown }).message
|
||||
if (typeof message === 'string' && message.trim()) {
|
||||
return message
|
||||
}
|
||||
}
|
||||
return "request_failed";
|
||||
return 'request_failed'
|
||||
}
|
||||
|
||||
function sessionRequestId(id: number, partition: string | null): string {
|
||||
return `session:${partition ?? "default"}:${id}`;
|
||||
return `session:${partition ?? 'default'}:${id}`
|
||||
}
|
||||
|
||||
function createFallbackActiveRequest(
|
||||
id: string,
|
||||
options: {
|
||||
source: DesktopObservedRequestSource;
|
||||
label: string;
|
||||
method?: string;
|
||||
url: string;
|
||||
partition?: string | null;
|
||||
resourceType?: string | null;
|
||||
source: DesktopObservedRequestSource
|
||||
label: string
|
||||
method?: string
|
||||
url: string
|
||||
partition?: string | null
|
||||
resourceType?: string | null
|
||||
},
|
||||
): ActiveObservedRequest {
|
||||
return {
|
||||
id,
|
||||
startedAt: Date.now(),
|
||||
kind: options.resourceType === "webSocket" ? "ws" : "http",
|
||||
kind: options.resourceType === 'webSocket' ? 'ws' : 'http',
|
||||
source: options.source,
|
||||
label: options.label,
|
||||
method: normalizeMethod(options.method),
|
||||
url: sanitizeURL(options.url),
|
||||
partition: options.partition ?? null,
|
||||
resourceType: options.resourceType ?? null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function buildRecord(
|
||||
active: ActiveObservedRequest,
|
||||
input: {
|
||||
at: number;
|
||||
phase: DesktopObservedRequest["phase"];
|
||||
status?: number | null;
|
||||
durationMs?: number | null;
|
||||
error?: string | null;
|
||||
at: number
|
||||
phase: DesktopObservedRequest['phase']
|
||||
status?: number | null
|
||||
durationMs?: number | null
|
||||
error?: string | null
|
||||
},
|
||||
): DesktopObservedRequest {
|
||||
return {
|
||||
@@ -407,21 +426,21 @@ function buildRecord(
|
||||
status: input.status ?? null,
|
||||
durationMs: input.durationMs ?? null,
|
||||
error: input.error ?? null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function pushRecord(record: DesktopObservedRequest): void {
|
||||
observedRecords.push(record);
|
||||
observedRecords.push(record)
|
||||
if (observedRecords.length > maxObservedRecords) {
|
||||
observedRecords.splice(0, observedRecords.length - maxObservedRecords);
|
||||
observedRecords.splice(0, observedRecords.length - maxObservedRecords)
|
||||
}
|
||||
|
||||
if (!rendererTarget || rendererTarget.isDestroyed()) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
rendererTarget.send("desktop:network-observed", record);
|
||||
rendererTarget.send('desktop:network-observed', record)
|
||||
} catch {
|
||||
// Best-effort diagnostics only.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user