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
@@ -1,6 +1,6 @@
import { computed, readonly, shallowRef } from "vue";
import { computed, readonly, shallowRef } from 'vue'
import { ApiClientError, createApiClient } from "@geo/http-client";
import { ApiClientError, createApiClient } from '@geo/http-client'
import type {
AuthTokens,
DesktopClientInfo,
@@ -11,93 +11,94 @@ import type {
LoginResponse,
RefreshResponse,
UserInfo,
} from "@geo/shared-types";
} from '@geo/shared-types'
type SessionMode = "authenticated" | "preview";
type SessionMode = 'authenticated' | 'preview'
interface DesktopSession {
mode: SessionMode;
accessToken: string | null;
refreshToken: string | null;
user: UserInfo | null;
clientToken: string | null;
clientTokenExpiresAt: number | null;
desktopClient: DesktopClientInfo | null;
mode: SessionMode
accessToken: string | null
refreshToken: string | null
user: UserInfo | null
clientToken: string | null
clientTokenExpiresAt: number | null
desktopClient: DesktopClientInfo | null
}
interface ResolvedDeviceInfo {
device_name: string;
os: string;
cpu_arch: string;
device_name: string
os: string
cpu_arch: string
}
const sessionStorageKey = "geo.desktop.session.v1";
const apiBaseURLStorageKey = "geo.desktop.api-base-url";
export const DEFAULT_API_BASE_URL = import.meta.env.VITE_DESKTOP_API_BASE_URL ?? "https://api.shengxintui.com";
const sessionStorageKey = 'geo.desktop.session.v1'
const apiBaseURLStorageKey = 'geo.desktop.api-base-url'
export const DEFAULT_API_BASE_URL =
import.meta.env.VITE_DESKTOP_API_BASE_URL ?? 'https://api.shengxintui.com'
const session = shallowRef<DesktopSession | null>(readStoredSession());
const apiBaseURL = shallowRef(readStoredApiBaseURL());
const pending = shallowRef(false);
const error = shallowRef<string | null>(null);
let loginPromise: Promise<void> | null = null;
let logoutPromise: Promise<void> | null = null;
const session = shallowRef<DesktopSession | null>(readStoredSession())
const apiBaseURL = shallowRef(readStoredApiBaseURL())
const pending = shallowRef(false)
const error = shallowRef<string | null>(null)
let loginPromise: Promise<void> | null = null
let logoutPromise: Promise<void> | null = null
function readStoredSession(): DesktopSession | null {
if (typeof window === "undefined") {
return null;
if (typeof window === 'undefined') {
return null
}
try {
const raw = window.localStorage.getItem(sessionStorageKey);
const raw = window.localStorage.getItem(sessionStorageKey)
if (!raw) {
return null;
return null
}
return JSON.parse(raw) as DesktopSession;
return JSON.parse(raw) as DesktopSession
} catch {
return null;
return null
}
}
function persistSession(next: DesktopSession | null): void {
session.value = next;
session.value = next
if (typeof window === "undefined") {
return;
if (typeof window === 'undefined') {
return
}
if (!next) {
window.localStorage.removeItem(sessionStorageKey);
window.localStorage.removeItem(sessionStorageKey)
} else {
window.localStorage.setItem(sessionStorageKey, JSON.stringify(next));
window.localStorage.setItem(sessionStorageKey, JSON.stringify(next))
}
void syncRuntimeSessionToMain(next);
void syncRuntimeSessionToMain(next)
}
function readStoredApiBaseURL(): string {
if (typeof window === "undefined") {
return DEFAULT_API_BASE_URL;
if (typeof window === 'undefined') {
return DEFAULT_API_BASE_URL
}
return window.localStorage.getItem(apiBaseURLStorageKey) ?? DEFAULT_API_BASE_URL;
return window.localStorage.getItem(apiBaseURLStorageKey) ?? DEFAULT_API_BASE_URL
}
function persistApiBaseURL(value: string): void {
const trimmed = value.trim() || DEFAULT_API_BASE_URL;
apiBaseURL.value = trimmed;
const trimmed = value.trim() || DEFAULT_API_BASE_URL
apiBaseURL.value = trimmed
if (typeof window !== "undefined") {
window.localStorage.setItem(apiBaseURLStorageKey, trimmed);
if (typeof window !== 'undefined') {
window.localStorage.setItem(apiBaseURLStorageKey, trimmed)
}
void syncRuntimeSessionToMain();
void syncRuntimeSessionToMain()
}
function createPublicClient() {
return createApiClient({
baseURL: apiBaseURL.value,
timeoutMs: 15000,
});
})
}
function createAuthenticatedClient() {
@@ -109,34 +110,34 @@ function createAuthenticatedClient() {
getRefreshToken: () => session.value?.refreshToken ?? null,
setTokens: (tokens: AuthTokens) => {
if (!session.value) {
return;
return
}
persistSession({
...session.value,
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken,
});
})
},
clearTokens: () => persistSession(null),
async refresh(refreshToken: string): Promise<AuthTokens> {
const next = await createPublicClient().post<RefreshResponse, { refresh_token: string }>(
"/api/auth/refresh",
'/api/auth/refresh',
{ refresh_token: refreshToken },
);
)
return {
accessToken: next.access_token,
refreshToken: next.refresh_token,
};
}
},
},
});
})
}
function createSessionBoundAuthenticatedClient(source: DesktopSession) {
let accessToken = source.accessToken;
let refreshToken = source.refreshToken;
let accessToken = source.accessToken
let refreshToken = source.refreshToken
return createApiClient({
baseURL: apiBaseURL.value,
@@ -145,79 +146,79 @@ function createSessionBoundAuthenticatedClient(source: DesktopSession) {
getAccessToken: () => accessToken,
getRefreshToken: () => refreshToken,
setTokens: (tokens: AuthTokens) => {
accessToken = tokens.accessToken;
refreshToken = tokens.refreshToken;
accessToken = tokens.accessToken
refreshToken = tokens.refreshToken
},
clearTokens: () => {
accessToken = null;
refreshToken = null;
accessToken = null
refreshToken = null
},
async refresh(refreshTokenValue: string): Promise<AuthTokens> {
const next = await createPublicClient().post<RefreshResponse, { refresh_token: string }>(
"/api/auth/refresh",
'/api/auth/refresh',
{ refresh_token: refreshTokenValue },
);
)
return {
accessToken: next.access_token,
refreshToken: next.refresh_token,
};
}
},
},
});
})
}
function resolveFallbackPlatform(): string {
const currentNavigator = globalThis.navigator as Navigator & {
userAgentData?: { platform?: string };
};
return currentNavigator.userAgentData?.platform || currentNavigator.platform || "unknown";
userAgentData?: { platform?: string }
}
return currentNavigator.userAgentData?.platform || currentNavigator.platform || 'unknown'
}
function resolveFallbackOS(platform: string): string {
const normalized = platform.toLowerCase();
if (normalized.includes("mac")) {
return "darwin";
const normalized = platform.toLowerCase()
if (normalized.includes('mac')) {
return 'darwin'
}
if (normalized.includes("win")) {
return "windows";
if (normalized.includes('win')) {
return 'windows'
}
if (normalized.includes("linux")) {
return "linux";
if (normalized.includes('linux')) {
return 'linux'
}
return normalized || "unknown";
return normalized || 'unknown'
}
function resolveFallbackDeviceName(platform: string): string {
const normalized = platform.toLowerCase();
if (normalized.includes("mac")) {
return "Current Mac";
const normalized = platform.toLowerCase()
if (normalized.includes('mac')) {
return 'Current Mac'
}
if (normalized.includes("win")) {
return "Current Windows PC";
if (normalized.includes('win')) {
return 'Current Windows PC'
}
if (normalized.includes("linux")) {
return "Current Linux Desktop";
if (normalized.includes('linux')) {
return 'Current Linux Desktop'
}
return "Current Desktop";
return 'Current Desktop'
}
async function resolveDeviceInfo(): Promise<ResolvedDeviceInfo> {
try {
const info = await window.desktopBridge?.app?.deviceInfo?.();
const info = await window.desktopBridge?.app?.deviceInfo?.()
if (info?.device_name && info.os && info.cpu_arch) {
return info;
return info
}
} catch (err) {
console.warn("[desktop-session] deviceInfo bridge failed", err);
console.warn('[desktop-session] deviceInfo bridge failed', err)
}
const platform = resolveFallbackPlatform();
const platform = resolveFallbackPlatform()
return {
device_name: resolveFallbackDeviceName(platform),
os: resolveFallbackOS(platform),
cpu_arch: "unknown",
};
cpu_arch: 'unknown',
}
}
async function resolveDesktopClientID(user: UserInfo): Promise<string> {
@@ -225,53 +226,58 @@ async function resolveDesktopClientID(user: UserInfo): Promise<string> {
tenant_id: user.tenant_id,
workspace_id: user.primary_workspace_id,
user_id: user.id,
});
})
if (!clientID) {
throw new Error("无法生成本机账号 client_id,请重启桌面客户端后重试");
throw new Error('无法生成本机账号 client_id,请重启桌面客户端后重试')
}
return clientID;
return clientID
}
async function syncStoredDesktopClientDeviceInfo(): Promise<void> {
const current = session.value;
if (typeof window === "undefined" || current?.mode !== "authenticated" || !current.desktopClient || !current.user) {
return;
const current = session.value
if (
typeof window === 'undefined' ||
current?.mode !== 'authenticated' ||
!current.desktopClient ||
!current.user
) {
return
}
const [device, clientID] = await Promise.all([
resolveDeviceInfo(),
resolveDesktopClientID(current.user),
]);
])
if (session.value !== current) {
return;
return
}
const desktopClient = current.desktopClient;
const desktopClient = current.desktopClient
if (desktopClient.id !== clientID) {
try {
const registered = await registerDesktopClient(current.user, device);
const latest = session.value;
if (latest?.mode !== "authenticated" || latest.user?.id !== current.user?.id) {
return;
const registered = await registerDesktopClient(current.user, device)
const latest = session.value
if (latest?.mode !== 'authenticated' || latest.user?.id !== current.user?.id) {
return
}
persistSession({
...latest,
clientToken: registered.client_token,
clientTokenExpiresAt: registered.expires_at,
desktopClient: registered.client,
});
})
} catch (err) {
console.warn("[desktop-session] stable client migration failed", err);
console.warn('[desktop-session] stable client migration failed', err)
}
return;
return
}
if (
desktopClient.device_name === device.device_name
&& desktopClient.os === device.os
&& desktopClient.cpu_arch === device.cpu_arch
desktopClient.device_name === device.device_name &&
desktopClient.os === device.os &&
desktopClient.cpu_arch === device.cpu_arch
) {
return;
return
}
persistSession({
@@ -282,74 +288,76 @@ async function syncStoredDesktopClientDeviceInfo(): Promise<void> {
os: device.os,
cpu_arch: device.cpu_arch,
},
});
})
}
async function registerPayload(
user: UserInfo,
device?: ResolvedDeviceInfo,
): Promise<DesktopClientRegisterRequest> {
const resolvedDevice = device ?? await resolveDeviceInfo();
const resolvedDevice = device ?? (await resolveDeviceInfo())
return {
client_id: await resolveDesktopClientID(user),
device_name: resolvedDevice.device_name,
os: resolvedDevice.os,
cpu_arch: resolvedDevice.cpu_arch,
client_version: "0.1.0-dev",
channel: "dev",
};
client_version: '0.1.0-dev',
channel: 'dev',
}
}
async function registerDesktopClient(
user: UserInfo,
device?: ResolvedDeviceInfo,
): Promise<DesktopClientRegisterResponse> {
const resolvedDevice = device ?? await resolveDeviceInfo();
const resolvedDevice = device ?? (await resolveDeviceInfo())
return createAuthenticatedClient().post<
DesktopClientRegisterResponse,
DesktopClientRegisterRequest
>("/api/desktop/clients/register", await registerPayload(user, resolvedDevice));
>('/api/desktop/clients/register', await registerPayload(user, resolvedDevice))
}
function createPreviewUser(): UserInfo {
return {
id: 0,
email: "preview@geo-rankly.local",
phone: "",
name: "开发预览账号",
email: 'preview@geo-rankly.local',
phone: '',
name: '开发预览账号',
avatar_url: null,
tenant_id: 0,
primary_workspace_id: 0,
tenant_role: "owner",
permissions: ["desktop.preview"],
tenant_role: 'owner',
permissions: ['desktop.preview'],
membership: null,
kol_profile: null,
};
}
}
async function createPreviewClient(): Promise<DesktopClientInfo> {
const now = new Date().toISOString();
const device = await resolveDeviceInfo();
const now = new Date().toISOString()
const device = await resolveDeviceInfo()
return {
id: "preview-client",
id: 'preview-client',
tenant_id: 0,
workspace_id: 0,
user_id: 0,
device_name: `Preview ${device.device_name}`,
os: device.os,
cpu_arch: device.cpu_arch,
client_version: "0.1.0-preview",
channel: "dev",
client_version: '0.1.0-preview',
channel: 'dev',
created_at: now,
last_seen_at: now,
last_rotated_at: now,
revoked_at: null,
};
}
}
function buildRuntimeSessionPayload(next: DesktopSession | null): DesktopRuntimeSessionSyncRequest | null {
function buildRuntimeSessionPayload(
next: DesktopSession | null,
): DesktopRuntimeSessionSyncRequest | null {
if (!next) {
return null;
return null
}
return {
@@ -357,156 +365,161 @@ function buildRuntimeSessionPayload(next: DesktopSession | null): DesktopRuntime
mode: next.mode,
client_token: next.clientToken,
desktop_client: next.desktopClient,
};
}
}
async function syncRuntimeSessionToMain(next: DesktopSession | null = session.value): Promise<void> {
if (typeof window === "undefined") {
return;
async function syncRuntimeSessionToMain(
next: DesktopSession | null = session.value,
): Promise<void> {
if (typeof window === 'undefined') {
return
}
if (!window.desktopBridge?.app?.syncRuntimeSession) {
return;
return
}
await window.desktopBridge.app.syncRuntimeSession(buildRuntimeSessionPayload(next));
await window.desktopBridge.app.syncRuntimeSession(buildRuntimeSessionPayload(next))
}
function formatLoginError(err: unknown): string {
if (err instanceof ApiClientError) {
const messages: Record<string, string> = {
invalid_credentials: "账号或密码错误",
login_rate_limited: "登录请求过于频繁",
login_locked: "登录已被临时保护",
login_in_progress: "登录请求正在处理中",
login_guard_unavailable: "登录保护暂时不可用",
};
const message = messages[err.message] ?? err.message.replaceAll("_", " ");
return err.detail ? `${message}${err.detail}` : message;
invalid_credentials: '账号或密码错误',
login_rate_limited: '登录请求过于频繁',
login_locked: '登录已被临时保护',
login_in_progress: '登录请求正在处理中',
login_guard_unavailable: '登录保护暂时不可用',
}
const message = messages[err.message] ?? err.message.replaceAll('_', ' ')
return err.detail ? `${message}${err.detail}` : message
}
return err instanceof Error ? err.message : "登录失败,请稍后重试";
return err instanceof Error ? err.message : '登录失败,请稍后重试'
}
async function performLogin(payload: LoginRequest): Promise<void> {
pending.value = true;
error.value = null;
pending.value = true
error.value = null
try {
const authData = await createPublicClient().post<LoginResponse, LoginRequest>(
"/api/auth/login",
'/api/auth/login',
payload,
);
)
persistSession({
mode: "authenticated",
mode: 'authenticated',
accessToken: authData.access_token,
refreshToken: authData.refresh_token,
user: authData.user,
clientToken: null,
clientTokenExpiresAt: null,
desktopClient: null,
});
})
const registered = await registerDesktopClient(authData.user);
const registered = await registerDesktopClient(authData.user)
persistSession({
mode: "authenticated",
mode: 'authenticated',
accessToken: authData.access_token,
refreshToken: authData.refresh_token,
user: authData.user,
clientToken: registered.client_token,
clientTokenExpiresAt: registered.expires_at,
desktopClient: registered.client,
});
})
} catch (err) {
error.value = formatLoginError(err);
persistSession(null);
throw err;
error.value = formatLoginError(err)
persistSession(null)
throw err
} finally {
pending.value = false;
pending.value = false
}
}
async function login(payload: LoginRequest): Promise<void> {
if (loginPromise) {
return loginPromise;
return loginPromise
}
loginPromise = performLogin({ ...payload }).finally(() => {
loginPromise = null;
});
return loginPromise;
loginPromise = null
})
return loginPromise
}
async function enterPreview(): Promise<void> {
error.value = null;
error.value = null
persistSession({
mode: "preview",
mode: 'preview',
accessToken: null,
refreshToken: null,
user: createPreviewUser(),
clientToken: "preview-client-token",
clientToken: 'preview-client-token',
clientTokenExpiresAt: Date.now() + 7 * 24 * 60 * 60 * 1000,
desktopClient: await createPreviewClient(),
});
})
}
async function releaseSessionForLogout(current: DesktopSession | null): Promise<void> {
if (current?.mode === "authenticated") {
if (current?.mode === 'authenticated') {
try {
await window.desktopBridge?.app?.releaseRuntimeSession?.(true);
await window.desktopBridge?.app?.releaseRuntimeSession?.(true)
} catch (err) {
console.warn("[desktop-session] releaseRuntimeSession failed", err);
console.warn('[desktop-session] releaseRuntimeSession failed', err)
}
try {
await createSessionBoundAuthenticatedClient(current).post<null, Record<string, never>>("/api/auth/logout", {});
await createSessionBoundAuthenticatedClient(current).post<null, Record<string, never>>(
'/api/auth/logout',
{},
)
} catch (err) {
console.warn("[desktop-session] auth logout failed", err);
console.warn('[desktop-session] auth logout failed', err)
}
}
}
async function transitionWindowForLogout(): Promise<void> {
try {
await window.desktopBridge?.app?.setWindowMode?.("login", { source: "logout", animate: true });
await window.desktopBridge?.app?.setWindowMode?.('login', { source: 'logout', animate: true })
} catch (err) {
console.warn("[desktop-session] logout window transition failed", err);
console.warn('[desktop-session] logout window transition failed', err)
}
}
async function performLogout(): Promise<void> {
error.value = null;
const current = session.value;
const releasePromise = releaseSessionForLogout(current);
error.value = null
const current = session.value
const releasePromise = releaseSessionForLogout(current)
persistSession(null);
await transitionWindowForLogout();
persistSession(null)
await transitionWindowForLogout()
void releasePromise.catch((err) => {
console.warn("[desktop-session] background logout release failed", err);
});
console.warn('[desktop-session] background logout release failed', err)
})
}
async function logout(): Promise<void> {
if (logoutPromise) {
return logoutPromise;
return logoutPromise
}
logoutPromise = performLogout().finally(() => {
logoutPromise = null;
});
return logoutPromise;
logoutPromise = null
})
return logoutPromise
}
if (typeof window !== "undefined") {
window.addEventListener("storage", (event) => {
if (typeof window !== 'undefined') {
window.addEventListener('storage', (event) => {
if (event.key === apiBaseURLStorageKey) {
apiBaseURL.value = event.newValue?.trim() || DEFAULT_API_BASE_URL;
void syncRuntimeSessionToMain();
apiBaseURL.value = event.newValue?.trim() || DEFAULT_API_BASE_URL
void syncRuntimeSessionToMain()
}
});
void syncStoredDesktopClientDeviceInfo();
})
void syncStoredDesktopClientDeviceInfo()
}
export function useDesktopSession() {
@@ -516,11 +529,11 @@ export function useDesktopSession() {
pending: readonly(pending),
error: readonly(error),
isAuthenticated: computed(() => Boolean(session.value?.clientToken)),
isPreviewMode: computed(() => session.value?.mode === "preview"),
isPreviewMode: computed(() => session.value?.mode === 'preview'),
setApiBaseURL: persistApiBaseURL,
syncRuntimeSession: syncRuntimeSessionToMain,
login,
logout,
enterPreview,
};
}
}