import { z } from "zod/v4"; import type { ResourceDefinitionSpec } from "../common"; import { CatalogResponseSchema, SaveDefinitionResponseSchema } from "../common"; export const catalogKeys = { scope: (scope: string) => ["resource-catalog", scope] }; export class CatalogApiError extends Error { constructor(public readonly code: string) { super(code); } } async function request(path: string, body?: unknown, csrfToken?: string) { const response = await fetch(`/api/resource-catalog/${path}`, { method: body === undefined ? "GET" : "POST", credentials: "same-origin", headers: body === undefined ? {} : { "content-type": "application/json", "x-csrf-token": csrfToken ?? "" }, ...(body === undefined ? {} : { body: JSON.stringify(body) }), }); const json: unknown = await response.json(); if (!response.ok) { const error = z.object({ code: z.string() }).safeParse(json); throw new CatalogApiError(error.success ? error.data.code : "INTERNAL_ERROR"); } return json; } export const catalogApi = { async get(scope: string) { return CatalogResponseSchema.parse(await request(scope)); }, async save(scope: string, values: ResourceDefinitionSpec, csrfToken: string, id?: string) { return SaveDefinitionResponseSchema.parse( await request(`${scope}${id ? `/${id}/update` : ""}`, { values }, csrfToken) ); }, async status(scope: string, id: string, active: boolean | null, csrfToken: string) { return CatalogResponseSchema.parse( await request(`${scope}/${id}/status`, { active }, csrfToken) ); }, };