chore(frontend): introduce prettier + eslint and prune unused code
Backend CI / Backend (push) Has been cancelled
Frontend CI / Frontend (push) Failing after 1m39s

- 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:
2026-05-01 20:39:09 +08:00
parent 21c7892ee4
commit 162abdc97c
258 changed files with 42261 additions and 37556 deletions
+187 -179
View File
@@ -1,93 +1,93 @@
import { BrowserWindow, nativeTheme } from "electron/main";
import type { BrowserWindow as ElectronBrowserWindow, Session } from "electron/main";
import type { Browser as PlaywrightBrowser, Page as PlaywrightPage } from "playwright-core";
import type { BrowserWindow as ElectronBrowserWindow, Session } from 'electron/main'
import { BrowserWindow, nativeTheme } from 'electron/main'
import type { Browser as PlaywrightBrowser, Page as PlaywrightPage } from 'playwright-core'
import {
isReclaimableHiddenPlaywrightTarget,
type CDPTargetDescriptor,
} from "./playwright-cdp-targets";
import { STANDARD_USER_AGENT } from "./user-agent";
} from './playwright-cdp-targets'
import { STANDARD_USER_AGENT } from './user-agent'
const hiddenPlaywrightIdleTTLms = 5 * 60_000;
const hiddenPlaywrightReaperIntervalMs = 60_000;
const defaultConnectTimeoutMs = 10_000;
const defaultPageTimeoutMs = 45_000;
const hiddenBootstrapMetaName = "geo-hidden-playwright-token";
const cdpPort = Number.parseInt(process.env.GEO_ELECTRON_CDP_PORT ?? "9339", 10);
const cdpEndpointURL = `http://127.0.0.1:${cdpPort}`;
const cdpTargetsListURL = `${cdpEndpointURL}/json/list`;
const hiddenPlaywrightIdleTTLms = 5 * 60_000
const hiddenPlaywrightReaperIntervalMs = 60_000
const defaultConnectTimeoutMs = 10_000
const defaultPageTimeoutMs = 45_000
const hiddenBootstrapMetaName = 'geo-hidden-playwright-token'
const cdpPort = Number.parseInt(process.env.GEO_ELECTRON_CDP_PORT ?? '9339', 10)
const cdpEndpointURL = `http://127.0.0.1:${cdpPort}`
const cdpTargetsListURL = `${cdpEndpointURL}/json/list`
interface HiddenPlaywrightRecord {
key: string;
accountId: string;
title: string;
targetURL: string;
window: ElectronBrowserWindow;
browser: PlaywrightBrowser;
page: PlaywrightPage;
retainCount: number;
activatedAt: number;
lastReleasedAt: number | null;
key: string
accountId: string
title: string
targetURL: string
window: ElectronBrowserWindow
browser: PlaywrightBrowser
page: PlaywrightPage
retainCount: number
activatedAt: number
lastReleasedAt: number | null
}
export interface HiddenPlaywrightLease {
accountId: string;
browser: PlaywrightBrowser;
page: PlaywrightPage;
release(): Promise<void>;
accountId: string
browser: PlaywrightBrowser
page: PlaywrightPage
release(): Promise<void>
}
const records = new Map<string, HiddenPlaywrightRecord>();
let reaperHandle: ReturnType<typeof setInterval> | null = null;
let connectPromise: Promise<PlaywrightBrowser> | null = null;
let connectedBrowser: PlaywrightBrowser | null = null;
const records = new Map<string, HiddenPlaywrightRecord>()
let reaperHandle: ReturnType<typeof setInterval> | null = null
let connectPromise: Promise<PlaywrightBrowser> | null = null
let connectedBrowser: PlaywrightBrowser | null = null
export function getPlaywrightCDPPort(): number {
return cdpPort;
return cdpPort
}
export function startHiddenPlaywrightReaper(): void {
if (reaperHandle) {
return;
return
}
reaperHandle = setInterval(() => {
reapIdleHiddenPlaywrightPages();
}, hiddenPlaywrightReaperIntervalMs);
reaperHandle.unref?.();
reapIdleHiddenPlaywrightPages()
}, hiddenPlaywrightReaperIntervalMs)
reaperHandle.unref?.()
}
export async function retainHiddenPlaywrightPage(options: {
accountId: string;
session: Session;
targetURL: string;
title: string;
accountId: string
session: Session
targetURL: string
title: string
}): Promise<HiddenPlaywrightLease> {
startHiddenPlaywrightReaper();
startHiddenPlaywrightReaper()
const key = hiddenPlaywrightKey(options.accountId, options.targetURL);
const existing = records.get(key);
const key = hiddenPlaywrightKey(options.accountId, options.targetURL)
const existing = records.get(key)
if (existing && !existing.window.isDestroyed() && !existing.page.isClosed()) {
await ensureRecordTarget(existing, options.targetURL);
existing.retainCount += 1;
existing.activatedAt = Date.now();
existing.lastReleasedAt = null;
return createLease(existing);
await ensureRecordTarget(existing, options.targetURL)
existing.retainCount += 1
existing.activatedAt = Date.now()
existing.lastReleasedAt = null
return createLease(existing)
}
const browser = await connectBrowserOverCDP();
const knownPages = new Set(defaultContext(browser).pages());
const bootstrapToken = createHiddenBootstrapToken();
const bootstrapURL = buildHiddenWindowBootstrapURL(options.title, bootstrapToken);
const window = createHiddenWindow(options.title, options.session, bootstrapURL);
const page = await waitForNewPage(browser, knownPages, bootstrapToken);
const browser = await connectBrowserOverCDP()
const knownPages = new Set(defaultContext(browser).pages())
const bootstrapToken = createHiddenBootstrapToken()
const bootstrapURL = buildHiddenWindowBootstrapURL(options.title, bootstrapToken)
const window = createHiddenWindow(options.title, options.session, bootstrapURL)
const page = await waitForNewPage(browser, knownPages, bootstrapToken)
page.setDefaultTimeout(defaultPageTimeoutMs);
page.setDefaultNavigationTimeout(defaultPageTimeoutMs);
page.setDefaultTimeout(defaultPageTimeoutMs)
page.setDefaultNavigationTimeout(defaultPageTimeoutMs)
await page.goto(options.targetURL, {
timeout: defaultPageTimeoutMs,
waitUntil: "domcontentloaded",
});
waitUntil: 'domcontentloaded',
})
const record: HiddenPlaywrightRecord = {
key,
@@ -100,31 +100,34 @@ export async function retainHiddenPlaywrightPage(options: {
retainCount: 1,
activatedAt: Date.now(),
lastReleasedAt: null,
};
}
window.once("closed", () => {
records.delete(key);
});
page.once("close", () => {
records.delete(key);
});
window.once('closed', () => {
records.delete(key)
})
page.once('close', () => {
records.delete(key)
})
records.set(key, record);
return createLease(record);
records.set(key, record)
return createLease(record)
}
export async function releaseHiddenPlaywrightPage(accountId: string, targetURL: string): Promise<void> {
const key = hiddenPlaywrightKey(accountId, targetURL);
const record = records.get(key);
export async function releaseHiddenPlaywrightPage(
accountId: string,
targetURL: string,
): Promise<void> {
const key = hiddenPlaywrightKey(accountId, targetURL)
const record = records.get(key)
if (!record) {
return;
return
}
if (record.retainCount > 0) {
record.retainCount -= 1;
record.retainCount -= 1
}
if (record.retainCount === 0) {
record.lastReleasedAt = Date.now();
record.lastReleasedAt = Date.now()
}
}
@@ -132,24 +135,24 @@ export function reapIdleHiddenPlaywrightPages(
now = Date.now(),
idleTTLms = hiddenPlaywrightIdleTTLms,
): string[] {
const reclaimed: string[] = [];
const reclaimed: string[] = []
for (const [key, record] of records.entries()) {
if (record.retainCount > 0) {
continue;
continue
}
const idleSince = record.lastReleasedAt ?? record.activatedAt;
const idleSince = record.lastReleasedAt ?? record.activatedAt
if (now - idleSince < idleTTLms) {
continue;
continue
}
closeRecord(record);
records.delete(key);
reclaimed.push(key);
closeRecord(record)
records.delete(key)
reclaimed.push(key)
}
return reclaimed;
return reclaimed
}
export function getHiddenPlaywrightSnapshot() {
@@ -169,7 +172,7 @@ export function getHiddenPlaywrightSnapshot() {
windowDestroyed: record.window.isDestroyed(),
pageClosed: record.page.isClosed(),
})),
};
}
}
function createLease(record: HiddenPlaywrightRecord): HiddenPlaywrightLease {
@@ -178,7 +181,7 @@ function createLease(record: HiddenPlaywrightRecord): HiddenPlaywrightLease {
browser: record.browser,
page: record.page,
release: () => releaseHiddenPlaywrightPage(record.accountId, record.targetURL),
};
}
}
function createHiddenWindow(
@@ -194,7 +197,7 @@ function createHiddenWindow(
focusable: false,
hiddenInMissionControl: true,
autoHideMenuBar: true,
backgroundColor: nativeTheme.shouldUseDarkColors ? "#15191a" : "#f4f1ea",
backgroundColor: nativeTheme.shouldUseDarkColors ? '#15191a' : '#f4f1ea',
title,
webPreferences: {
session,
@@ -203,156 +206,159 @@ function createHiddenWindow(
nodeIntegration: false,
backgroundThrottling: false,
},
});
})
window.webContents.setUserAgent(STANDARD_USER_AGENT);
void window.loadURL(bootstrapURL);
return window;
window.webContents.setUserAgent(STANDARD_USER_AGENT)
void window.loadURL(bootstrapURL)
return window
}
function createHiddenBootstrapToken(): string {
if (typeof globalThis.crypto?.randomUUID === "function") {
return globalThis.crypto.randomUUID();
if (typeof globalThis.crypto?.randomUUID === 'function') {
return globalThis.crypto.randomUUID()
}
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
return `${Date.now()}-${Math.random().toString(16).slice(2)}`
}
function escapeHtml(value: string): string {
return value
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;")
.replaceAll("'", "&#39;");
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;')
}
function buildHiddenWindowBootstrapURL(title: string, token: string): string {
const html = [
"<!doctype html>",
"<html lang=\"en\">",
"<head>",
" <meta charset=\"utf-8\">",
'<!doctype html>',
'<html lang="en">',
'<head>',
' <meta charset="utf-8">',
` <meta name=\"${hiddenBootstrapMetaName}\" content=\"${escapeHtml(token)}\">`,
` <title>${escapeHtml(title)} · hidden-playwright</title>`,
"</head>",
'</head>',
` <body data-${hiddenBootstrapMetaName}=\"${escapeHtml(token)}\"></body>`,
"</html>",
].join("");
return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`;
'</html>',
].join('')
return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`
}
async function ensureRecordTarget(record: HiddenPlaywrightRecord, targetURL: string): Promise<void> {
record.targetURL = targetURL;
async function ensureRecordTarget(
record: HiddenPlaywrightRecord,
targetURL: string,
): Promise<void> {
record.targetURL = targetURL
const currentURL = safePageURL(record.page);
const currentURL = safePageURL(record.page)
if (currentURL === targetURL) {
return;
return
}
await record.page.goto(targetURL, {
timeout: defaultPageTimeoutMs,
waitUntil: "domcontentloaded",
});
waitUntil: 'domcontentloaded',
})
}
async function connectBrowserOverCDP(): Promise<PlaywrightBrowser> {
if (connectedBrowser?.isConnected()) {
return connectedBrowser;
return connectedBrowser
}
if (connectPromise) {
return connectPromise;
return connectPromise
}
connectPromise = (async () => {
await waitForCDPEndpoint();
const { chromium } = await import("playwright-core");
await pruneStaleCDPTargets();
await waitForCDPEndpoint()
const { chromium } = await import('playwright-core')
await pruneStaleCDPTargets()
try {
return await openBrowserOverCDP(chromium);
return await openBrowserOverCDP(chromium)
} catch (error) {
if (!isConnectOverCDPTimeout(error)) {
throw error;
throw error
}
const prunedTargetCount = await pruneStaleCDPTargets();
const prunedTargetCount = await pruneStaleCDPTargets()
if (prunedTargetCount <= 0) {
throw error;
throw error
}
return openBrowserOverCDP(chromium);
return openBrowserOverCDP(chromium)
}
})();
})()
try {
return await connectPromise;
return await connectPromise
} finally {
if (!connectedBrowser?.isConnected()) {
connectPromise = null;
connectPromise = null
}
}
}
async function waitForCDPEndpoint(timeoutMs = defaultConnectTimeoutMs): Promise<void> {
const startedAt = Date.now();
const startedAt = Date.now()
while (Date.now() - startedAt < timeoutMs) {
try {
const response = await fetch(`${cdpEndpointURL}/json/version`);
const response = await fetch(`${cdpEndpointURL}/json/version`)
if (response.ok) {
return;
return
}
} catch {
// Ignore and continue polling.
}
await wait(200);
await wait(200)
}
throw new Error("playwright_cdp_endpoint_unavailable");
throw new Error('playwright_cdp_endpoint_unavailable')
}
async function openBrowserOverCDP(
chromium: typeof import("playwright-core").chromium,
chromium: typeof import('playwright-core').chromium,
): Promise<PlaywrightBrowser> {
const browser = await chromium.connectOverCDP(cdpEndpointURL, {
timeout: defaultConnectTimeoutMs,
});
})
browser.on("disconnected", () => {
connectedBrowser = null;
connectPromise = null;
});
browser.on('disconnected', () => {
connectedBrowser = null
connectPromise = null
})
connectedBrowser = browser;
return browser;
connectedBrowser = browser
return browser
}
async function pruneStaleCDPTargets(): Promise<number> {
let targets: CDPTargetDescriptor[] = [];
let targets: CDPTargetDescriptor[] = []
try {
const response = await fetch(cdpTargetsListURL);
const response = await fetch(cdpTargetsListURL)
if (!response.ok) {
return 0;
return 0
}
const payload = await response.json();
const payload = await response.json()
if (Array.isArray(payload)) {
targets = payload as CDPTargetDescriptor[];
targets = payload as CDPTargetDescriptor[]
}
} catch {
return 0;
return 0
}
let closedCount = 0;
let closedCount = 0
for (const target of targets) {
if (!isReclaimableHiddenPlaywrightTarget(target)) {
continue;
continue
}
try {
const closeURL = `${cdpEndpointURL}/json/close/${encodeURIComponent(target.id ?? "")}`;
const response = await fetch(closeURL);
const closeURL = `${cdpEndpointURL}/json/close/${encodeURIComponent(target.id ?? '')}`
const response = await fetch(closeURL)
if (response.ok) {
closedCount += 1;
closedCount += 1
}
} catch {
// Ignore best-effort stale target cleanup failures.
@@ -360,15 +366,17 @@ async function pruneStaleCDPTargets(): Promise<number> {
}
if (closedCount > 0) {
await wait(150);
await wait(150)
}
return closedCount;
return closedCount
}
function isConnectOverCDPTimeout(error: unknown): boolean {
return error instanceof Error
&& error.name === "TimeoutError"
&& error.message.includes("connectOverCDP");
return (
error instanceof Error &&
error.name === 'TimeoutError' &&
error.message.includes('connectOverCDP')
)
}
async function waitForNewPage(
@@ -376,87 +384,87 @@ async function waitForNewPage(
knownPages: Set<PlaywrightPage>,
bootstrapToken: string,
): Promise<PlaywrightPage> {
const context = defaultContext(browser);
const startedAt = Date.now();
const context = defaultContext(browser)
const startedAt = Date.now()
while (Date.now() - startedAt < defaultPageTimeoutMs) {
const nextPages = context.pages().filter((page) => !knownPages.has(page));
const nextPages = context.pages().filter((page) => !knownPages.has(page))
for (const nextPage of nextPages) {
if (isDevtoolsPage(nextPage)) {
knownPages.add(nextPage);
continue;
knownPages.add(nextPage)
continue
}
if (await matchesHiddenBootstrapPage(nextPage, bootstrapToken)) {
return nextPage;
return nextPage
}
}
await wait(100);
await wait(100)
}
throw new Error("playwright_hidden_page_unavailable");
throw new Error('playwright_hidden_page_unavailable')
}
async function matchesHiddenBootstrapPage(
page: PlaywrightPage,
bootstrapToken: string,
): Promise<boolean> {
const url = safePageURL(page);
const url = safePageURL(page)
if (url.includes(bootstrapToken) || url.includes(encodeURIComponent(bootstrapToken))) {
return true;
return true
}
try {
return await page.evaluate(
({ token, metaName }) => {
const metaToken =
document.querySelector(`meta[name="${metaName}"]`)?.getAttribute("content")
?? document.body?.getAttribute(`data-${metaName}`)
?? null;
return metaToken === token;
document.querySelector(`meta[name="${metaName}"]`)?.getAttribute('content') ??
document.body?.getAttribute(`data-${metaName}`) ??
null
return metaToken === token
},
{
token: bootstrapToken,
metaName: hiddenBootstrapMetaName,
},
);
)
} catch {
return false;
return false
}
}
function defaultContext(browser: PlaywrightBrowser) {
const context = browser.contexts()[0];
const context = browser.contexts()[0]
if (!context) {
throw new Error("playwright_default_context_unavailable");
throw new Error('playwright_default_context_unavailable')
}
return context;
return context
}
function hiddenPlaywrightKey(accountId: string, targetURL: string): string {
return `${accountId}::${targetURL}`;
return `${accountId}::${targetURL}`
}
function safePageURL(page: PlaywrightPage): string {
try {
return page.url();
return page.url()
} catch {
return "";
return ''
}
}
function isDevtoolsPage(page: PlaywrightPage): boolean {
const url = safePageURL(page);
return url.startsWith("devtools://");
const url = safePageURL(page)
return url.startsWith('devtools://')
}
function closeRecord(record: HiddenPlaywrightRecord): void {
if (!record.window.isDestroyed()) {
record.window.close();
record.window.close()
}
}
function wait(timeMs: number): Promise<void> {
return new Promise((resolve) => {
setTimeout(resolve, timeMs);
});
setTimeout(resolve, timeMs)
})
}