async function parseOrThrow(res, label) {
if (!res.ok) {
const text = await res.text().catch(() => '');
throw new Error(`${label}: HTTP ${res.status} — ${text.slice(0, 500)}`);
}
return res.json();
}
export async function chat(messages, currentCard) {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages,
current_card: currentCard,
use_tools: true,
}),
});
return parseOrThrow(res, 'chat');
}
export async function validate(card, host) {
const res = await fetch('/api/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ card, host }),
});
return parseOrThrow(res, 'validate');
}
export async function listExamples(category, limit) {
const params = new URLSearchParams();
if (category) params.set('category', category);
if (limit) params.set('limit', String(limit));
const qs = params.toString();
const res = await fetch('/api/examples' + (qs ? '?' + qs : ''));
return parseOrThrow(res, 'listExamples');
}
export async function suggestExamples(query, limit) {
const params = new URLSearchParams({ q: query });
if (limit) params.set('limit', String(limit));
const res = await fetch('/api/examples/suggest?' + params.toString());
return parseOrThrow(res, 'suggestExamples');
}
export async function getExample(id) {
const res = await fetch('/api/examples/' + encodeURIComponent(id));
if (res.status === 404) return null;
return parseOrThrow(res, 'getExample');
}
export async function startPack(name, cards, opts) {
const res = await fetch('/api/pack', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name,
cards,
i18n: opts?.i18n || false,
langs: opts?.langs || null,
strict: opts?.strict || false,
verbose: opts?.verbose || false,
bundle: opts?.bundle || false,
providers: opts?.providers || null,
}),
});
return parseOrThrow(res, 'pack');
}
export async function pollPackJob(jobId) {
const res = await fetch('/api/pack/' + encodeURIComponent(jobId));
return parseOrThrow(res, 'pollPack');
}
export async function simulateHttp(spec) {
const res = await fetch('/api/simulate-http', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(spec || {}),
});
if (!res.ok) {
const detail = await res.json().catch(() => ({}));
const message = detail?.message || `HTTP ${res.status}`;
const err = new Error(`simulate-http: ${message}`);
err.detail = detail;
throw err;
}
return res.json();
}
export async function wizardBuild(name, cards, opts) {
const res = await fetch('/api/wizard/build', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
mode: opts?.mode || 'develop',
name,
cards,
channels: opts?.channels || [],
cloud: opts?.cloud || null,
translate: opts?.translate || false,
languages: opts?.languages || [],
}),
});
return parseOrThrow(res, 'wizardBuild');
}
export async function pollWizardJob(jobId) {
const res = await fetch('/api/wizard/build/' + encodeURIComponent(jobId));
return parseOrThrow(res, 'pollWizard');
}
export async function checkCredentials(cloud) {
const res = await fetch('/api/wizard/credentials/' + encodeURIComponent(cloud));
return parseOrThrow(res, 'checkCredentials');
}