Files
agent-desktop/console/src/api/config.ts
T
Pine e3a81f6bf5 fix(api): getApiToken fallback reads JWT from user profile when qwenpaw_auth_token missing
桌面端部分构建路径将 OPC JWT 存于 pineagents_user_profile.token,
而 localStorage qwenpaw_auth_token 缺失导致 getApiToken() 返回空、
所有 API 请求无 Authorization -> 401。增加 fallback:仅当 profile.token
为三段式 JWT 时兜底,避免演示/占位 token 混入请求头。
2026-09-01 21:42:52 +08:00

105 lines
2.9 KiB
TypeScript

declare const VITE_API_BASE_URL: string;
declare const TOKEN: string;
const AUTH_TOKEN_KEY = "qwenpaw_auth_token";
const USER_PROFILE_KEY = "pineagents_user_profile";
/**
* Get the full API URL with /api prefix
* @param path - API path (e.g., "/models", "/skills")
* @returns Full API URL (e.g., "http://localhost:8088/api/models" or "/api/models")
*/
export function getApiUrl(path: string): string {
const base = VITE_API_BASE_URL || "";
const apiPrefix = "/api";
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
return `${base}${apiPrefix}${normalizedPath}`;
}
/**
* Get the API token - checks localStorage first (auth login),
* then falls back to the build-time TOKEN constant.
* @returns API token string or empty string
*/
export function getApiToken(): string {
const stored = localStorage.getItem(AUTH_TOKEN_KEY);
if (stored) return stored;
// Fallback: some desktop build paths persist the OPC JWT inside the user
// profile (pineagents_user_profile.token). Only honour it when it is a
// well-formed JWT (three dot-separated segments), so demo/placeholder
// tokens never leak into Authorization.
try {
const profile = getStoredUser<{ token?: unknown }>();
if (profile && typeof profile.token === "string" && profile.token.includes(".")) {
return profile.token;
}
} catch {
/* ignore malformed profile */
}
return typeof TOKEN !== "undefined" ? TOKEN : "";
}
/**
* Store the auth token in localStorage after login.
*/
export function setAuthToken(token: string): void {
localStorage.setItem(AUTH_TOKEN_KEY, token);
}
/**
* Remove the auth token from localStorage (logout / 401).
*/
export function clearAuthToken(): void {
localStorage.removeItem(AUTH_TOKEN_KEY);
}
/**
* 演示用户资料:登录/更新后存 localStorage,供账户管理等展示。
*/
export function setStoredUser(user: unknown): void {
if (!user || typeof user !== "object") return;
localStorage.setItem(USER_PROFILE_KEY, JSON.stringify(user));
}
/**
* 读取已存的演示用户资料。
*/
export function getStoredUser<T = Record<string, unknown>>(): T | null {
const raw = localStorage.getItem(USER_PROFILE_KEY);
if (!raw) return null;
try {
return JSON.parse(raw) as T;
} catch {
return null;
}
}
/**
* 清除已存的演示用户资料(退出登录时调用)。
*/
export function clearStoredUser(): void {
localStorage.removeItem(USER_PROFILE_KEY);
}
/**
* Get the backend API port number.
* Extracted from VITE_API_BASE_URL, then falls back to the current window
* port and finally the default desktop backend port.
*/
export function getApiPort(): number {
const base = VITE_API_BASE_URL || "";
if (base) {
try {
const url = new URL(base);
if (url.port) return parseInt(url.port, 10);
} catch {
// Fall through to runtime-derived defaults.
}
}
if (window.location.port) {
return parseInt(window.location.port, 10);
}
return 8088;
}