@clawvard/sdk
v0.12.0
Published
Clawvard unified service SDK — call every Clawvard service with one typed client.
Readme
@clawvard/sdk
Typed TypeScript client for Clawvard's non-LLM service layer —
composed workflows, video / image / data jobs, third-party API
integrations. Same sk-xxx key works for the OpenAI SDK against
token.clawvard.school and for this
SDK against clawvard.school.
pnpm add @clawvard/sdk
# or: npm i @clawvard/sdk / yarn add @clawvard/sdkQuick start
import { Clawvard } from "@clawvard/sdk";
const cv = new Clawvard({ apiKey: "sk-xxx" });
// Local services (instant, charged per call)
const { hex } = await cv.text.hash({ text: "hello", algorithm: "sha256" });
const { dataUri } = await cv.url.qrCode({ text: "https://clawvard.school" });
// Long-running jobs (auto-poll, refundable on failure)
const result = await cv.video.removeSilence({ inputUrl: "https://…" })
.onProgress((pct, note) => console.log(`${(pct * 100).toFixed(0)}% — ${note}`))
.wait();
// Untyped escape hatch — call any registered service by id
const out = await cv.workflow.run<MyOutput>("my.service", input).wait();For LLM calls (chat / embeddings / Whisper / DALL·E), point the
OpenAI SDK at Token Relay with the same sk-xxx:
import { OpenAI } from "openai";
const ai = new OpenAI({
apiKey: "sk-xxx",
baseURL: "https://token.clawvard.school/v1",
});
await ai.chat.completions.create({ model: "claude-opus-4-7", messages });What's in the box
| Class | Purpose |
|---|---|
| Clawvard | Main client — composes generated namespaces with platform helpers |
| Job<T> | Handle for long-running jobs — .wait(), .onProgress(cb), .cancel(), .id() |
| HttpClient | Lower-level: .invoke(), .invokeJob(), raw .raw() — exposed via cv.client |
| Generated namespaces | One per service group (cv.util.*, cv.text.*, cv.url.*, cv.video.*, …) |
| cv.workflow.run(id, input) | Untyped invoker — works for any registered service without bumping the SDK |
| cv.catalog() | Public catalog with pricing per service |
| cv.usage() / cv.usageFor(g, m) | Caller's usage stats per service |
Per-call options
// Idempotency: same key → server returns the original outcome (no double-charge)
await cv.client.invoke("video", "render", input, {
idempotencyKey: crypto.randomUUID(),
});
// Webhooks (job services only): platform POSTs the terminal state
// to your URL with HMAC signature header `X-Clawvard-Signature`
await cv.client.invokeJob("video", "removeSilence", input, {
idempotencyKey: "...",
webhookUrl: "https://you.com/webhook",
});Configuration
const cv = new Clawvard({
apiKey: "sk-xxx", // Required for remote calls
baseUrl: "https://clawvard.school", // Default; override for staging
pollIntervalMs: 2000, // Job polling cadence
retry: { maxRetries: 3, baseDelayMs: 250 },
fetch: customFetch, // For testing / edge runtimes
plugins: [], // School / capability plugins
});Auto-retry policy
- GET: always retry on 5xx + network errors
- POST/PUT/DELETE: only retry on 5xx if
Idempotency-Keyis set; always retry on network errors (request never reached the server) - 4xx: never retry (caller's bug)
Errors
import { ClawvardError, MissingApiKeyError } from "@clawvard/sdk";
try {
await cv.video.render(input);
} catch (err) {
if (err instanceof MissingApiKeyError) { /* config issue */ }
// Server errors carry .status + .hint:
// (err as Error & { status?: number; hint?: string }).status
}Plugins
Capability packages can attach namespaces:
import { Clawvard } from "@clawvard/sdk";
import { mediaPlugin } from "@clawvard/sdk-media";
const cv = new Clawvard({
apiKey: "sk-xxx",
plugins: [mediaPlugin()],
});
await cv.video.extractFrames({ url, every: "1s" });Resources
- Docs: clawvard.school/docs
- Service catalog: clawvard.school/services
- Get an API key: clawvard.school/token-relay
- Issues: github.com/THEZIONLABS/clawvard
License
MIT
