Skip to content
Command Palette
Search for a command to run...
QuizBase · Docs

TypeScript SDK#

Install#

npm install @quizbase/client
# or pnpm add @quizbase/client
# or bun add @quizbase/client

Requires Node ≥20 (or any modern browser with fetch + AbortController). Zero runtime dependencies.

What’s inside#

  • Typed client — every endpoint typed from /openapi.json, regenerated on each release
  • Built-in retryRetry-After-aware, exponential backoff with jitter, retries 429 / 5xx / network errors
  • onRequest telemetry hook — wire up to PostHog / Sentry / Datadog with one callback
  • Performance-aware timeouts — defaults tuned against /docs/performance, per-endpoint overridable
  • RFC 9457 typed errorsinstanceof QuizbaseError with .requestId, .retryAfter, .problem
  • Works everywhere — Node ≥20, Deno, Bun, Cloudflare Workers, browsers (with qb_pk_* only — qb_sk_* is blocked by CORS)

Quick start#

import { createClient } from '@quizbase/client';

const client = createClient({ apiKey: process.env.QUIZBASE_API_KEY! });

const random = await client.questions.random({
  amount: 5,
  lang: 'pl',
  difficulty: 'medium'
});

console.log(random.data); // Question[]

Pagination#

let cursor: string | undefined;
do {
  const page = await client.questions.list({ lang: 'pl', limit: 100, cursor });
  for (const q of page.data) await db.upsert(q);
  cursor = page.meta.pagination?.nextCursor ?? undefined;
} while (cursor);

Errors#

import { QuizbaseError } from '@quizbase/client';

try {
  await client.questions.random({ category: 'unknown' });
} catch (err) {
  if (err instanceof QuizbaseError) {
    console.error(err.status);          // 400
    console.error(err.problem.code);    // "invalid_query_param"
    console.error(err.problem.detail);  // human-readable message
    console.error(err.requestId);       // for support requests
    if (err.isRateLimited) console.error(err.retryAfter); // seconds
  }
}

Telemetry hook#

const client = createClient({
  apiKey: process.env.QUIZBASE_API_KEY!,
  onRequest: ({ method, endpoint, duration, status, requestId, retryCount, final }) => {
    posthog.capture('quizbase_api_call', {
      method, endpoint, duration, status, requestId, retryCount, final
    });
  }
});

Async-safe, no-op default. Fires on every attempt (including retries). final: false means another retry will follow. Errors thrown inside the hook are swallowed so telemetry can never break the caller.

Performance-aware timeouts#

Per-endpoint defaults match the public performance baseline:

EndpointDefault timeout
questions.list, topics.list, tags.list, subcategories.list, report.create15 s
questions.random, questions.get, categories.list, languages.list, topics.get, stats.get, me.get, usage.get10 s
Global default30 s

Override per-endpoint:

createClient({
  apiKey,
  timeout: 30_000,
  timeouts: {
    'questions.random': 5_000   // narrow filters → fail fast
  }
});

Source & releases#

See also#