132 lines
3.5 KiB
TypeScript
132 lines
3.5 KiB
TypeScript
/**
|
|
* Centralized API client for all backend communication.
|
|
*
|
|
* Every fetch call in the app should go through here so that
|
|
* endpoint URLs live in one place and are easy to update
|
|
* (e.g. when adding multi-node support with /api/nodes/{id}/...).
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Pages
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface PageMeta {
|
|
name: string;
|
|
title: string | null;
|
|
published: boolean;
|
|
has_source: boolean;
|
|
last_modified: number | null;
|
|
size: number | null;
|
|
}
|
|
|
|
export interface PageDetail {
|
|
name: string;
|
|
source: string | null;
|
|
}
|
|
|
|
export async function fetchPages(): Promise<PageMeta[]> {
|
|
const res = await fetch("/api/pages");
|
|
return res.json();
|
|
}
|
|
|
|
export async function fetchPage(name: string): Promise<PageDetail> {
|
|
const res = await fetch(`/api/pages/${name}`);
|
|
return res.json();
|
|
}
|
|
|
|
export async function savePage(
|
|
name: string,
|
|
source: string,
|
|
publish: boolean,
|
|
): Promise<PageMeta> {
|
|
const res = await fetch(`/api/pages/${name}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ source, publish }),
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|
|
|
|
export async function deletePage(name: string): Promise<void> {
|
|
await fetch(`/api/pages/${name}`, { method: "DELETE" });
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Compile
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface CompileResult {
|
|
ascii: string;
|
|
micron: string;
|
|
script: string;
|
|
is_dynamic: boolean;
|
|
warnings: string[];
|
|
}
|
|
|
|
export async function compile(
|
|
source: string,
|
|
signal?: AbortSignal,
|
|
): Promise<CompileResult> {
|
|
const res = await fetch("/api/compile", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ source }),
|
|
signal,
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json().catch(() => ({ detail: "Compile failed" }));
|
|
throw new Error(err.detail || "Compile failed");
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// DSL Metadata
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface DslCommand {
|
|
label: string;
|
|
detail: string;
|
|
section: string;
|
|
snippet: string;
|
|
}
|
|
|
|
export interface DslMeta {
|
|
keywords: string[];
|
|
values: string[];
|
|
commands: DslCommand[];
|
|
themes: string[];
|
|
}
|
|
|
|
export async function fetchDslMeta(): Promise<DslMeta> {
|
|
const res = await fetch("/api/dsl-meta");
|
|
return res.json();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Node Management
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export async function restartNode(): Promise<void> {
|
|
const res = await fetch("/api/restart", { method: "POST" });
|
|
if (!res.ok) throw new Error(await res.text());
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Images
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export interface UploadResult {
|
|
filename: string;
|
|
path: string;
|
|
}
|
|
|
|
export async function uploadImage(file: File): Promise<UploadResult> {
|
|
const form = new FormData();
|
|
form.append("file", file);
|
|
const res = await fetch("/api/upload-image", { method: "POST", body: form });
|
|
if (!res.ok) throw new Error(await res.text());
|
|
return res.json();
|
|
}
|