Files
Genarrative/apps/preview-deployer-web/src/api.ts
T
kdletters abb3912530
Project CI / Frontend tests (push) Successful in 2m54s
Project CI / Native shell tests (push) Successful in 14m0s
Project CI / Repository checks (push) Successful in 1m6s
Project CI / Backend tests (push) Successful in 3m54s
增加分支与提交搜索校验
增加分支和 commit 的输入搜索下拉构建前复核固定仓库中的分支与 commit 归属补充预览控制面接口合同、配置和测试
2026-08-17 12:04:31 +08:00

160 lines
3.9 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 interface BranchRef {
name: string;
commitHash?: string | null;
}
export interface CommitRef {
commitHash: string;
shortHash: string;
subject?: string | null;
}
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 async function searchBranches(query: string, signal?: AbortSignal) {
const payload = await request<BranchRef[] | { items: BranchRef[] }>(
`/refs/branches?q=${encodeURIComponent(query)}`,
{ signal },
);
return Array.isArray(payload) ? payload : payload.items;
}
export async function searchCommits(
branch: string,
query: string,
signal?: AbortSignal,
) {
const payload = await request<CommitRef[] | { items: CommitRef[] }>(
`/refs/commits?branch=${encodeURIComponent(branch)}&q=${encodeURIComponent(query)}`,
{ signal },
);
return Array.isArray(payload) ? payload : payload.items;
}
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;
}