export type BootstrapContext = { userId: string; workspace: { _id: string; name: string }; project: { _id: string; name: string }; }; async function readJson(response: Response): Promise { if (!response.ok) { const payload = (await response.json().catch(() => null)) as { message?: string } | null; throw new Error(payload?.message ?? `Request failed: ${response.status}`); } return (await response.json()) as T; } export class ApiClient { constructor(private readonly baseUrl: string) {} async bootstrapDev(projectName?: string): Promise { const response = await fetch(`${this.baseUrl}/api/dev/bootstrap`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ projectName }), }); return readJson(response); } async listAssets(projectId: string) { return readJson( await fetch(`${this.baseUrl}/api/assets?projectId=${encodeURIComponent(projectId)}`), ); } async registerLocalAsset(input: { workspaceId: string; projectId: string; sourcePath: string; displayName?: string; }) { return readJson( await fetch(`${this.baseUrl}/api/assets/register`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }), ); } async getAsset(assetId: string) { return readJson(await fetch(`${this.baseUrl}/api/assets/${assetId}`)); } async probeAsset(assetId: string) { return readJson( await fetch(`${this.baseUrl}/api/assets/${assetId}/probe`, { method: "POST" }), ); } async getProbeReport(assetId: string) { return readJson( await fetch(`${this.baseUrl}/api/assets/${assetId}/probe-report`), ); } async listWorkflows(projectId: string) { return readJson( await fetch(`${this.baseUrl}/api/workflows?projectId=${encodeURIComponent(projectId)}`), ); } async createWorkflow(input: { workspaceId: string; projectId: string; name: string; }) { return readJson( await fetch(`${this.baseUrl}/api/workflows`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }), ); } async listWorkflowVersions(workflowDefinitionId: string) { return readJson( await fetch(`${this.baseUrl}/api/workflows/${workflowDefinitionId}/versions`), ); } async getWorkflowDefinition(workflowDefinitionId: string) { return readJson( await fetch(`${this.baseUrl}/api/workflows/${workflowDefinitionId}`), ); } async saveWorkflowVersion(workflowDefinitionId: string, payload: Record) { return readJson( await fetch(`${this.baseUrl}/api/workflows/${workflowDefinitionId}/versions`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload), }), ); } async listNodeDefinitions() { return readJson(await fetch(`${this.baseUrl}/api/node-definitions`)); } async createRun(input: { workflowDefinitionId: string; workflowVersionId: string; assetIds: string[]; }) { return readJson( await fetch(`${this.baseUrl}/api/runs`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }), ); } async getRun(runId: string) { return readJson(await fetch(`${this.baseUrl}/api/runs/${runId}`)); } async listRuns(input: { projectId: string; workflowDefinitionId?: string; }) { const search = new URLSearchParams({ projectId: input.projectId }); if (input.workflowDefinitionId) { search.set("workflowDefinitionId", input.workflowDefinitionId); } return readJson(await fetch(`${this.baseUrl}/api/runs?${search.toString()}`)); } async listRunTasks(runId: string) { return readJson(await fetch(`${this.baseUrl}/api/runs/${runId}/tasks`)); } async createArtifact(input: { type: "json" | "directory" | "video"; title: string; producerType: string; producerId: string; payload: Record; }) { return readJson( await fetch(`${this.baseUrl}/api/artifacts`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(input), }), ); } async getArtifact(artifactId: string) { return readJson(await fetch(`${this.baseUrl}/api/artifacts/${artifactId}`)); } async listArtifactsByProducer(producerType: string, producerId: string) { const search = new URLSearchParams({ producerType, producerId }); return readJson(await fetch(`${this.baseUrl}/api/artifacts?${search.toString()}`)); } }