chore: directory migration - gateway→server, web→client/electron
This commit is contained in:
68
client/electron/src/api/config.ts
Normal file
68
client/electron/src/api/config.ts
Normal file
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* API 接入配置。
|
||||
*
|
||||
* WebUI 与第三方客户端调用的是**同一套 WebAPI**,差别只在两点:
|
||||
* 1. 基地址:内嵌在 Gateway 里时是同源的 /api/v1;独立部署的客户端需要指向具体主机
|
||||
* 2. 凭证:浏览器用登录 Cookie;第三方客户端用用户密钥(Authorization: Bearer)
|
||||
*
|
||||
* 这两点都在此处集中配置,业务代码不感知差异 —— 这样把 src/api/ 整个抽成 SDK 时
|
||||
* 不需要改任何调用点。
|
||||
*/
|
||||
|
||||
/** 运行时注入点:宿主页面可在加载 bundle 前设置这两个全局量 */
|
||||
declare global {
|
||||
interface Window {
|
||||
__AGENTMAIL_API_BASE__?: string;
|
||||
__AGENTMAIL_TOKEN__?: string;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基地址优先级:运行时全局 > 构建期环境变量 > 同源默认值。
|
||||
*
|
||||
* 运行时优先是为了让同一份构建产物能部署到不同后端(容器镜像不必按环境重打)。
|
||||
*/
|
||||
function resolveBase(): string {
|
||||
const runtime = typeof window !== 'undefined' ? window.__AGENTMAIL_API_BASE__ : undefined;
|
||||
const build = import.meta.env?.VITE_API_BASE as string | undefined;
|
||||
const base = (runtime || build || '/api/v1').trim();
|
||||
// 统一去掉尾部斜杠,拼接时只在 path 侧带前导斜杠
|
||||
return base.replace(/\/+$/, '');
|
||||
}
|
||||
|
||||
export const API_BASE = resolveBase();
|
||||
|
||||
/** 当前用于 Authorization 头的令牌;空表示走 Cookie。 */
|
||||
let bearerToken: string | null =
|
||||
(typeof window !== 'undefined' ? window.__AGENTMAIL_TOKEN__ : undefined) ?? null;
|
||||
|
||||
/**
|
||||
* 设置用户密钥。第三方客户端在启动时调用一次即可,
|
||||
* 之后所有请求(含 SSE 与附件下载)自动带上。
|
||||
*/
|
||||
export function setToken(token: string | null) {
|
||||
bearerToken = token && token.trim() !== '' ? token.trim() : null;
|
||||
}
|
||||
|
||||
export function getToken(): string | null {
|
||||
return bearerToken;
|
||||
}
|
||||
|
||||
/** 认证请求头。用 Cookie 时返回空对象。 */
|
||||
export function authHeaders(): Record<string, string> {
|
||||
return bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 给 URL 附加认证信息,供无法设置请求头的场景使用:
|
||||
* - EventSource(SSE)不支持自定义头
|
||||
* - <a download> / <img src> 由浏览器直接发起
|
||||
*
|
||||
* 服务端仅在 SSE 与附件下载这两处接受 ?access_token=,
|
||||
* 其余接口一律要求请求头 —— URL 里的令牌会进访问日志。
|
||||
*/
|
||||
export function withToken(url: string): string {
|
||||
if (!bearerToken) return url;
|
||||
const sep = url.includes('?') ? '&' : '?';
|
||||
return `${url}${sep}access_token=${encodeURIComponent(bearerToken)}`;
|
||||
}
|
||||
Reference in New Issue
Block a user