Files
Genarrative/apps/preview-deployer-web/src/api.ts
T
kdletters 41874ab391
Project CI / Repository checks (push) Successful in 1m16s
Project CI / Frontend tests (push) Successful in 3m1s
Project CI / Backend tests (push) Successful in 4m2s
Project CI / Native shell tests (push) Successful in 17m2s
新增内网容器预览部署控制面
新增分支与指定提交的预览部署 SPA 和 Jenkins 代理服务
新增多实例 Docker 预览流水线、端口租约、实时健康状态和卸载能力
新增 /build 内网路由、systemd 部署资产和运维文档
修正容器 Nginx 健康检查探针
2026-08-15 17:18:10 +08:00

129 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { CreateDeploymentInput, PreviewDeployment } from './types';
const API_BASE = '/api/preview-deployer';
export class PreviewDeployerApiError extends Error {
status: number;
constructor(message: string, status: number) {
super(message);
this.name = 'PreviewDeployerApiError';
this.status = status;
}
}
export interface PreviewDeployerSession {
authenticated: boolean;
}
export async function getSession(signal?: AbortSignal) {
const session = await request<PreviewDeployerSession | null>('/session', {
signal,
});
return session ?? { authenticated: true };
}
export function createSession(accessToken: string) {
return request<PreviewDeployerSession>('/session', {
method: 'POST',
body: { accessToken },
});
}
export function deleteSession() {
return request<void>('/session', { method: 'DELETE' });
}
export async function listDeployments(signal?: AbortSignal) {
const payload = await request<
PreviewDeployment[] | { deployments: PreviewDeployment[] }
>('/deployments', { signal });
return Array.isArray(payload) ? payload : payload.deployments;
}
export function createDeployment(input: CreateDeploymentInput) {
return request<PreviewDeployment>('/deployments', {
method: 'POST',
body: input,
});
}
export function uninstallDeployment(deploymentId: string) {
return request<PreviewDeployment>(
`/deployments/${encodeURIComponent(deploymentId)}/uninstall`,
{ method: 'POST', body: {} },
);
}
interface RequestOptions {
method?: string;
body?: unknown;
signal?: AbortSignal;
}
async function request<T>(
path: string,
options: RequestOptions = {},
): Promise<T> {
const headers: Record<string, string> = { Accept: 'application/json' };
const init: RequestInit = {
method: options.method ?? 'GET',
headers,
signal: options.signal,
credentials: 'same-origin',
};
if (options.body !== undefined) {
headers['Content-Type'] = 'application/json';
init.body = JSON.stringify(options.body);
}
const response = await fetch(`${API_BASE}${path}`, init);
const responseText = await response.text();
const payload = parseJson(responseText);
if (!response.ok) {
throw new PreviewDeployerApiError(
readErrorMessage(payload) || `请求失败(HTTP ${response.status}`,
response.status,
);
}
return unwrapPayload<T>(payload);
}
function parseJson(value: string): unknown {
if (!value.trim()) {
return null;
}
try {
return JSON.parse(value) as unknown;
} catch {
return value;
}
}
function unwrapPayload<T>(payload: unknown): T {
if (isRecord(payload) && 'data' in payload) {
return payload.data as T;
}
return payload as T;
}
function readErrorMessage(payload: unknown) {
if (typeof payload === 'string') {
return payload.trim();
}
if (!isRecord(payload)) {
return '';
}
if (typeof payload.message === 'string') {
return payload.message;
}
if (isRecord(payload.error) && typeof payload.error.message === 'string') {
return payload.error.message;
}
return '';
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}