Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts
T

106 lines
3.7 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Api_Fetch.ts
* 마스터 템플릿 서버 호출 — 계약 `6_계약.md` 서버 길 · 시스템 층은 시스템 관리자만
* ========================================================================== */
import { API_BASE_URL } from "@config/config_frontend";
/** 층 이름 — 서버와 같은 글 */
export type Layer = "system" | "company" | "personal" | "project";
/** 서버 종류 — 화면의 「표 양식」 = table · 「도면 양식」 = drawing */
export type Kind = "table" | "drawing";
export interface TemplateInfo {
종류: Kind;
이름: string;
판: string;
수정일: string;
}
export interface TemplateDoc {
종류: Kind;
이름: string;
판: string;
문서: unknown;
}
/** 서버가 판 불일치로 막았을 때 */
export class StaleError extends Error {}
async function call<T>(path: string, init: RequestInit = {}): Promise<T> {
const response = await fetch(`${API_BASE_URL}/m02${path}`, {
credentials: "include",
headers: { "Content-Type": "application/json" },
...init,
});
const body = (await response.json().catch(() => ({}))) as { detail?: unknown } & T;
if (response.status === 409) throw new StaleError(String(body.detail ?? "409"));
if (!response.ok) {
const detail = body.detail;
throw new Error(typeof detail === "string" ? detail : `HTTP ${response.status}`);
}
return body;
}
const enc = encodeURIComponent;
const q = (projectId: string | null): string => (projectId ? `?project_id=${enc(projectId)}` : "");
const head = (layer: Layer): string =>
layer === "system" ? "/templates" : `/layers/${layer}/templates`;
const item = (layer: Layer, kind: Kind, name: string, projectId: string | null): string =>
`${head(layer)}/${kind}/${enc(name)}${layer === "system" ? "" : q(projectId)}`;
export const listTemplates = (layer: Layer, projectId: string | null): Promise<TemplateInfo[]> =>
call(layer === "system" ? head(layer) : `${head(layer)}${q(projectId)}`);
export const readTemplate = (
layer: Layer,
kind: Kind,
name: string,
projectId: string | null,
): Promise<TemplateDoc> => call(item(layer, kind, name, projectId));
export const saveTemplate = (
layer: Layer,
kind: Kind,
name: string,
projectId: string | null,
판: string,
문서: unknown,
): Promise<TemplateInfo> =>
call(item(layer, kind, name, projectId), { method: "PUT", body: JSON.stringify({ 판, 문서 }) });
/** 시스템 층만 지움 */
export const deleteTemplate = (kind: Kind, name: string, 판: string): Promise<{ ok: boolean }> =>
call(`/templates/${kind}/${enc(name)}?판=${enc(판)}`, { method: "DELETE" });
/* --- 프로젝트 층 단추 다섯 --- */
const project = (id: string, tail: string): string => `/projects/${enc(id)}/templates/${tail}`;
const post = (path: string, body: object = {}): Promise<unknown> =>
call(path, { method: "POST", body: JSON.stringify(body) });
export const resetProject = (id: string): Promise<unknown> => post(project(id, "reset"));
export const applyToProject = (
id: string,
from: { from: Layer; user_id?: string; project_id?: string; 종류?: Kind; 이름?: string },
): Promise<unknown> => post(project(id, "apply"), from);
export const saveProjectAs = (
id: string,
to: "personal" | "company",
종류: Kind,
이름: string,
): Promise<unknown> => post(project(id, "save-as"), { to, 종류, 이름 });
export interface SourceItem {
from: Layer;
label?: string;
user_id?: string;
project_id?: string;
종류?: Kind;
이름?: string;
[key: string]: unknown;
}
export const fetchSources = (id: string): Promise<unknown> => call(`/projects/${enc(id)}/sources`);