e3a81f6bf5
桌面端部分构建路径将 OPC JWT 存于 pineagents_user_profile.token, 而 localStorage qwenpaw_auth_token 缺失导致 getApiToken() 返回空、 所有 API 请求无 Authorization -> 401。增加 fallback:仅当 profile.token 为三段式 JWT 时兜底,避免演示/占位 token 混入请求头。
105 lines
2.9 KiB
TypeScript
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;
|
|
}
|