feat(tenancy): implement workspace isolation

This commit is contained in:
Junyan Qin
2026-07-19 09:58:59 +08:00
parent 37099ddf7e
commit 8b7ce77cec
271 changed files with 31166 additions and 6513 deletions
+31
View File
@@ -4,6 +4,12 @@ import axios, {
AxiosResponse,
AxiosError,
} from 'axios';
import {
clearActiveWorkspaceUuid,
getActiveWorkspaceUuid,
} from './workspaceContext';
import { setCurrentWorkspaceSnapshot } from './currentWorkspaceStore';
import { clearWorkspaceBootstrapSnapshot } from './workspaceBootstrapStore';
type JSONValue = string | number | boolean | JSONObject | JSONArray | null;
interface JSONObject {
@@ -21,6 +27,8 @@ export interface ResponseData<T = unknown> {
export interface RequestConfig extends AxiosRequestConfig {
isSSR?: boolean; // 服务端渲染标识
retry?: number; // 重试次数
/** Account-scoped endpoints must not receive a stale Workspace selector. */
skipWorkspace?: boolean;
}
/**
@@ -77,6 +85,17 @@ export abstract class BaseHttpClient {
if (session) {
config.headers.Authorization = `Bearer ${session}`;
}
const requestConfig = config as RequestConfig;
const workspaceUuid = getActiveWorkspaceUuid();
if (requestConfig.skipWorkspace) {
delete config.headers['X-Workspace-Id'];
delete config.headers['x-workspace-id'];
} else if (workspaceUuid) {
config.headers['X-Workspace-Id'] = workspaceUuid;
}
delete requestConfig.skipWorkspace;
}
return config;
@@ -99,6 +118,10 @@ export abstract class BaseHttpClient {
case 401:
if (typeof window !== 'undefined') {
localStorage.removeItem('token');
localStorage.removeItem('userEmail');
clearActiveWorkspaceUuid();
setCurrentWorkspaceSnapshot(null);
clearWorkspaceBootstrapSnapshot();
if (!error.request.responseURL.includes('/check-token')) {
window.location.href = '/login';
}
@@ -187,6 +210,14 @@ export abstract class BaseHttpClient {
return this.request<T>({ method: 'put', url, data, ...config });
}
public patch<T = unknown>(
url: string,
data?: object,
config?: RequestConfig,
): Promise<T> {
return this.request<T>({ method: 'patch', url, data, ...config });
}
public delete<T = unknown>(url: string, config?: RequestConfig): Promise<T> {
return this.request<T>({ method: 'delete', url, ...config });
}