greentic-flow-builder 0.4.0

Greentic Flow Builder — orchestrator that powers Adaptive Card design via the adaptive-card-mcp toolkit
Documentation
// API fetch helpers for the orchestrator backend.
//
// Pure functions, no DOM access, no Alpine state. Each helper returns a
// Promise resolving to parsed JSON, or throws on HTTP / network errors.

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');
}

// Forward an HTTP request through the backend simulator.
//
// `spec` is `{ url, method?, headers?, body?, timeout_ms? }`. The server
// executes the request with reqwest (shielding the browser from CORS and
// keeping any bearer tokens off the wire). Returns
// `{ status, headers, body, body_is_json, elapsed_ms }` on success, or
// throws with a `{ error, message }`-shaped payload on failure.
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');
}