Skip to main content
CID222 Docs

JavaScript SDK

A JavaScript client library is planned but not released — what it will cover, and the working REST client to use until it ships.

  • Version: 0.4
  • Role: admin_user, normal_user

Note

There is no JavaScript or TypeScript client library for CID222 yet — no package is published, and no installation command on this page would resolve. Call the REST API directly, as shown below.

CID222's API is small enough to call without a library: one route to send a chat request, one to scan text, one to list the models you can reach. What a client library will eventually save you is the part that surprises people — the response is a server-sent event stream with its own shape, not an OpenAI- or Anthropic-compatible payload.

What a client library would have to hide

  • There is no non-streaming mode. POST /chat/completions always answers text/event-stream. The stream field in the request body is accepted and then ignored, so response.json() fails on every call.
  • The answer arrives as one event, not as deltas. The gateway consumes the provider's tokens, buffers the full reply, runs the output filter over it, and emits {"id":"filtered-response","content":…,"finish_reason":"stop"} once. There is no choices[].delta, no content_block_delta, and nothing to render progressively.
  • A policy block is not an error status. A rejected prompt is an event on a 200 response.
  • The two chat surfaces disagree about rejection. /chat/completions uses an error field; /sessions/:id/messages uses {"type":"content_rejected","reason":…} with no error field.
  • Not every route takes the same credential. A cid_key_ bearer works on /chat/completions, /models and /api/v1/guardrails/detect. Sessions, image analysis and document analysis need a user JWT.

Use the REST API today

This client works against the contract above on Node 18 or later, and in a browser only behind your own server route — a gateway key must never reach front-end code.

const GATEWAY = 'https://<gateway-host>';
 
export async function chat({ model, provider, messages, maxTokens }) {
  const res = await fetch(`${GATEWAY}/chat/completions`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CID222_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ model, provider, messages, max_tokens: maxTokens }),
  });
 
  if (!res.ok) {
    // 400/401/402/403/423 arrive here. The body may or may not carry a `code`.
    const body = await res.json().catch(() => ({}));
    const error = new Error(body.message ?? `Gateway returned ${res.status}`);
    error.status = res.status;
    error.code = body.code;
    throw error;
  }
 
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let answer = '';
  let usage = null;
 
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
 
    // Frames are separated by a blank line. Keep the trailing partial frame.
    const frames = buffer.split('\n\n');
    buffer = frames.pop() ?? '';
 
    for (const frame of frames) {
      const line = frame.split('\n').find((l) => l.startsWith('data: '));
      if (!line) continue;
      const data = line.slice(6).trim();
      if (data === '[DONE]') return { answer, usage };
 
      const event = JSON.parse(data);
 
      // Prompt blocked before the provider was called, or a server-side failure.
      if (event.error) throw new Error(event.error);
      // Answer discarded by the output filter.
      if (event.type === 'output_content_rejected') throw new Error(event.reason);
      if (event.type === 'token_usage') { usage = event.usage; continue; }
      if (event.type) continue; // routing, compression and warning telemetry
 
      // The whole filtered answer, as one event.
      if (typeof event.content === 'string') answer = event.content;
    }
  }
 
  return { answer, usage };
}

Scanning text needs no stream handling at all — the detection endpoint answers with plain JSON:

export async function detect(text, checkType = 'prompt') {
  const res = await fetch(`${GATEWAY}/api/v1/guardrails/detect`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.CID222_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ text, check_type: checkType }),
  });
  if (!res.ok) throw new Error(`Detection returned ${res.status}`);
  // { action, detectedEntities, detectionCount, maskedText, processingTimeMs, … }
  return res.json();
}

What the library is planned to cover

These are intentions, not shipped behaviour. Nothing here is callable today.

  • Typed requests and responses, generated from the gateway's own DTOs, so a renamed field is a compile error rather than a silently stripped body field.
  • Stream handling, including frame reassembly and the terminal events, behind a single await.
  • Distinct error types for a transport failure, a policy rejection and a licence or role refusal, so a caller can branch without inspecting status codes and optional code fields.
  • Connection pooling with keep-alive, configured once.
  • Session support, including the JWT-only constraint and token refresh.

Limits and known gaps

  • No package exists. Any @cid222/… name you find on a public registry is not published by this project. Do not install it.
  • No release date. Treat the planned list above as a direction, not a commitment.
  • No official types. Until the library ships, mirror the DTOs by hand from Chat completions and re-check them when you upgrade the gateway.
  • Unknown request fields are dropped silently. With no typed client, a misspelt field name produces a successful call that ignores your setting.
  • A browser cannot call the gateway directly with a key. Anything that holds a cid_key_ value can spend the tenant's provider budget, so the credential stays on your server.
  • Integration examples — the same client as a step-by-step procedure, plus Python, cURL and React.
  • Error handling — status codes, the three error body shapes, and the rejection events.
  • Python SDK — the same situation on the Python side.

Last updated on

On this page

Download PDF