API Client & Endpoints
Production-ready API client layer for the MetaForge Digital Twin Dashboard. Each module exports typed functions that wrap Axios calls to the Gateway REST API.
src/api/client.ts
Shared Axios instance with interceptors for auth tokens and structured error handling.
import axios, {
type AxiosError,
type AxiosInstance,
type AxiosResponse,
type InternalAxiosRequestConfig,
} from "axios";
// ---------------------------------------------------------------------------
// Error types
// ---------------------------------------------------------------------------
export interface ApiErrorPayload {
code: string;
message: string;
details?: Record<string, unknown>;
}
export class ApiError extends Error {
readonly code: string;
readonly status: number;
readonly details?: Record<string, unknown>;
constructor(status: number, payload: ApiErrorPayload) {
super(payload.message);
this.name = "ApiError";
this.code = payload.code;
this.status = status;
this.details = payload.details;
}
}
// ---------------------------------------------------------------------------
// Client factory
// ---------------------------------------------------------------------------
function createClient(): AxiosInstance {
const instance = axios.create({
baseURL: import.meta.env.VITE_API_URL ?? "/api/v1",
headers: { "Content-Type": "application/json" },
timeout: 30_000,
});
// ---- request interceptor: attach bearer token when present -------------
instance.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
const token =
typeof window !== "undefined"
? localStorage.getItem("metaforge_token")
: null;
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error: AxiosError) => Promise.reject(error),
);
// ---- response interceptor: normalise errors into ApiError --------------
instance.interceptors.response.use(
(response: AxiosResponse) => response,
(error: AxiosError<{ error?: ApiErrorPayload }>) => {
if (error.response) {
const payload: ApiErrorPayload = error.response.data?.error ?? {
code: "UNKNOWN_ERROR",
message: error.message,
};
return Promise.reject(new ApiError(error.response.status, payload));
}
// Network / timeout errors
return Promise.reject(
new ApiError(0, {
code: "NETWORK_ERROR",
message: error.message ?? "Network request failed",
}),
);
},
);
return instance;
}
export const client = createClient();
src/api/endpoints/sessions.ts
CRUD operations for orchestration sessions.
import { client } from "@/api/client";
import type {
PaginatedResponse,
Session,
SessionStatus,
} from "@/types/session";
export interface GetSessionsParams {
limit?: number;
offset?: number;
status?: SessionStatus;
}
export interface CreateSessionPayload {
skill: string;
files?: string[];
args?: Record<string, unknown>;
}
/**
* List sessions with optional filtering and pagination.
*/
export async function getSessions(
params?: GetSessionsParams,
): Promise<PaginatedResponse<Session>> {
const { data } = await client.get<PaginatedResponse<Session>>("/sessions", {
params,
});
return data;
}
/**
* Retrieve a single session by ID.
*/
export async function getSession(id: string): Promise<Session> {
const { data } = await client.get<Session>(`/session/${id}`);
return data;
}
/**
* Create a new execution session.
*/
export async function createSession(
payload: CreateSessionPayload,
): Promise<Session> {
const { data } = await client.post<Session>("/session/create", {
skill: payload.skill,
input: {
files: payload.files,
args: payload.args,
},
});
return data;
}
/**
* Delete a session and its artifacts.
*/
export async function deleteSession(id: string): Promise<void> {
await client.delete(`/session/${id}`);
}
src/api/endpoints/agents.ts
Agent execution and status polling.
import { client } from "@/api/client";
import type { Agent } from "@/types/agent";
export interface RunAgentPayload {
agentId: string;
sessionId: string;
}
export interface RunAgentResponse {
runId: string;
}
/**
* Retrieve all registered agents and their current state.
* Derives from the `/status` endpoint's agent list.
*/
export async function getAgents(): Promise<Agent[]> {
const { data } = await client.get<{ agents: Agent[] }>("/status");
return data.agents;
}
/**
* Get the current execution status for a specific agent.
*/
export async function getAgentStatus(id: string): Promise<Agent> {
const { data } = await client.get<Agent>(`/agent/${id}/status`);
return data;
}
/**
* Trigger an agent run within an existing session.
*/
export async function runAgent(
payload: RunAgentPayload,
): Promise<RunAgentResponse> {
const { data } = await client.post<RunAgentResponse>("/agent/run", {
agentId: payload.agentId,
sessionId: payload.sessionId,
});
return data;
}
src/api/endpoints/approvals.ts
Human-in-the-loop approval workflow.
import { client } from "@/api/client";
import type { Approval } from "@/types/approval";
/**
* Get all sessions waiting for human approval.
*/
export async function getPendingApprovals(): Promise<Approval[]> {
const { data } = await client.get<{ pending: Approval[] }>("/pending");
return data.pending;
}
/**
* Approve a pending session. Optionally include a comment.
*/
export async function approveSession(
sessionId: string,
comment?: string,
): Promise<void> {
await client.post(`/approve/${sessionId}`, comment ? { comment } : undefined);
}
/**
* Reject a pending session. A reason is required.
*/
export async function rejectSession(
sessionId: string,
reason: string,
): Promise<void> {
await client.post(`/reject/${sessionId}`, { reason });
}
src/api/endpoints/health.ts
System health and status probes.
import { client } from "@/api/client";
import type { HealthResponse, StatusResponse } from "@/types/system";
/**
* Lightweight liveness probe.
*/
export async function getHealth(): Promise<HealthResponse> {
const { data } = await client.get<HealthResponse>("/health");
return data;
}
/**
* Detailed system status including tool availability and session counts.
*/
export async function getStatus(): Promise<StatusResponse> {
const { data } = await client.get<StatusResponse>("/status");
return data;
}
src/api/endpoints/bom.ts
Bill of Materials retrieval and risk analysis.
import { client } from "@/api/client";
import type { BOMEntry, BOMRiskSummary } from "@/types/bom";
/**
* Fetch the current Bill of Materials.
*/
export async function getBOM(): Promise<BOMEntry[]> {
const { data } = await client.get<{ items: BOMEntry[] }>("/bom");
return data.items;
}
/**
* Fetch BOM risk analysis (single-source, EOL, lead-time flags).
*/
export async function getBOMRisk(): Promise<BOMRiskSummary> {
const { data } = await client.get<BOMRiskSummary>("/bom/risk");
return data;
}
src/api/endpoints/compliance.ts
Regulatory compliance summaries per target market.
import { client } from "@/api/client";
import type { ComplianceMarket, ComplianceSummary } from "@/types/compliance";
/**
* Get compliance status for a specific market (UKCA, CE, or FCC).
*/
export async function getCompliance(
market: ComplianceMarket,
): Promise<ComplianceSummary> {
const { data } = await client.get<ComplianceSummary>(
`/compliance/${market}`,
);
return data;
}
src/api/endpoints/digital-thread.ts
Digital-thread graph traversal and requirement traceability.
import { client } from "@/api/client";
import type { DigitalThreadGraph } from "@/types/digital-thread";
/**
* Fetch the full digital-thread graph
* (requirements <-> BOM <-> tests <-> artifacts).
*/
export async function getDigitalThread(): Promise<DigitalThreadGraph> {
const { data } = await client.get<DigitalThreadGraph>("/digital-thread");
return data;
}
/**
* Trace a single requirement through the thread to see every linked
* artefact, test, and BOM line.
*/
export async function getTraceability(
reqId: string,
): Promise<DigitalThreadGraph> {
const { data } = await client.get<DigitalThreadGraph>(
`/digital-thread/trace/${reqId}`,
);
return data;
}
src/api/endpoints/supply-chain.ts
Supply-chain risk intelligence.
import { client } from "@/api/client";
import type { SupplyChainRisk } from "@/types/supply-chain";
/**
* Retrieve current supply-chain risk entries
* (lead-time alerts, geopolitical flags, single-source warnings).
*/
export async function getSupplyChainRisks(): Promise<SupplyChainRisk[]> {
const { data } = await client.get<{ risks: SupplyChainRisk[] }>(
"/supply-chain/risks",
);
return data.risks;
}
src/api/endpoints/testing.ts
Test-coverage metrics.
import { client } from "@/api/client";
import type { TestCoverage } from "@/types/testing";
/**
* Fetch aggregate test-coverage data across all requirements.
*/
export async function getTestCoverage(): Promise<TestCoverage> {
const { data } = await client.get<TestCoverage>("/testing/coverage");
return data;
}
src/api/endpoints/artifacts.ts
Artifact retrieval and 3-D model download.
import { client } from "@/api/client";
import type { Artifact } from "@/types/artifact";
/**
* Fetch metadata for a single artifact.
*/
export async function getArtifact(id: string): Promise<Artifact> {
const { data } = await client.get<Artifact>(`/artifacts/${id}`);
return data;
}
/**
* Download the glTF binary for a 3-D artifact (digital-twin viewer).
*/
export async function getArtifactGltf(id: string): Promise<Blob> {
const { data } = await client.get<Blob>(`/artifacts/${id}/gltf`, {
responseType: "blob",
});
return data;
}
src/api/endpoints/gates.ts
Gate-readiness checks for hardware milestones.
import { client } from "@/api/client";
import type { GateReadiness, GateName } from "@/types/gate";
/**
* Retrieve readiness status for a specific gate (EVT, DVT, or PVT).
*/
export async function getGateReadiness(
gate: GateName,
): Promise<GateReadiness> {
const { data } = await client.get<GateReadiness>(
`/gate-readiness/${gate}`,
);
return data;
}
src/api/endpoints/index.ts
Barrel re-export for convenient imports.
export * from "./sessions";
export * from "./agents";
export * from "./approvals";
export * from "./health";
export * from "./bom";
export * from "./compliance";
export * from "./digital-thread";
export * from "./supply-chain";
export * from "./testing";
export * from "./artifacts";
export * from "./gates";
export * from "./chat";
src/api/endpoints/chat.ts(threads, messages, channels) is specified in Agent Chat Channel.