Merge remote-tracking branch 'origin/main'

# Conflicts:
#	AGENTS.md
#	backend/docs/docs.go
#	backend/docs/swagger.json
#	backend/docs/swagger.yaml
#	frontend/components/providers/title-updater.tsx
#	frontend/messages/fragments/admin.en.json
#	frontend/messages/fragments/admin.zh-CN.json
#	frontend/proxy.ts
This commit is contained in:
ryan
2026-09-03 09:16:22 +08:00
1065 changed files with 271858 additions and 9600 deletions
+1 -1
View File
@@ -90,7 +90,7 @@ function getRequestKey(config: {
*/
apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Browser must use same-origin relative URLs so Session Cookie hits Next rewrite.
// Browser must use same-origin relative URLs so Session Cookie hits Next rewrite (3010→3000).
if (typeof window !== 'undefined') {
config.baseURL = getApiBaseUrl();
}
+7 -7
View File
@@ -1,24 +1,19 @@
/**
* API 配置
*
* 浏览器默认走同源相对路径(`/api/...`),由 `next.config` rewrites 反代到后端,
* 避免 dev 下跨域。仅当设置了 `NEXT_PUBLIC_WAVELET_BACKEND_URL` 时浏览器才直连后端
*(静态导出 embed / WebSocket 等场景)。
*/
/**
* 获取 API 基础 URL
* @returns API 基础 URL;浏览器侧空字符串表示同源相对路径
* @returns API 基础 URL
*/
export function getApiBaseUrl(): string {
if (typeof window === 'undefined') {
return (
process.env.WAVELET_BACKEND_URL ||
process.env.NEXT_PUBLIC_WAVELET_BACKEND_URL ||
'http://localhost:8000'
'http://localhost:3000'
);
}
// 空字符串 → axios 请求 `/api/...`,经 Next rewrites 到后端,无 CORS 问题
return process.env.NEXT_PUBLIC_WAVELET_BACKEND_URL || '';
}
@@ -30,6 +25,11 @@ export const apiConfig = {
baseURL: getApiBaseUrl(),
/** 超时时间(毫秒) */
timeout: 15000,
/**
* 文件上传超时(毫秒)。
* Pages 部署包上限 100 MiB,需覆盖上传 + 服务端解压校验与入库时间。
*/
uploadTimeout: 10 * 60 * 1000,
/** 携带凭证 */
withCredentials: true,
} as const;
@@ -0,0 +1,22 @@
/**
* Serialize query params for Gin-compatible repeated array keys.
* Axios default uses hosts[]= which Gin QueryArray("hosts") ignores.
*/
export function serializeSearchParams(
params?: Record<string, unknown>,
): string {
if (!params) return '';
const search = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value === undefined || value === null || value === '') continue;
if (Array.isArray(value)) {
for (const item of value) {
if (item === undefined || item === null || item === '') continue;
search.append(key, String(item));
}
continue;
}
search.append(key, String(value));
}
return search.toString();
}