@qubittron/bastion-sdk
v0.1.3
Published
Official TypeScript SDK for the Bastion sovereign Canadian LLM API.
Downloads
118
Readme
@qubittron/bastion-sdk
Official TypeScript SDK for the Bastion sovereign Canadian LLM API.
Alpha —
v0.1.3. API surface may change before 1.0.
Install
npm install @qubittron/bastion-sdk
# or
bun add @qubittron/bastion-sdkQuickstart
import { Bastion } from "@qubittron/bastion-sdk";
// reads BASTION_API_KEY from env if `apiKey` is omitted
const client = new Bastion({ apiKey: process.env.BASTION_API_KEY });
const res = await client.chat.completions.create({
model: "gpt-oss-120b",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(res.choices[0]?.message.content);Streaming
const stream = await client.chat.completions.create({
model: "gpt-oss-120b",
messages: [{ role: "user", content: "Tell me a poem" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
}List models
const { data } = await client.models.list();
for (const m of data) console.log(m.id);Images
const res = await client.images.generate({
model: "sd-xl",
prompt: "a sovereign Canadian moose, oil painting",
size: "1024x1024",
n: 1,
});
console.log(res.data[0]?.url);Speech (TTS)
Synthesize speech via the NVIDIA Riva proxy. Returns the raw audio bytes plus the upstream Content-Type so you know which extension to write.
import { writeFile } from "node:fs/promises";
import { SpeechEncoding } from "@qubittron/bastion-sdk";
const { audio, contentType } = await client.audio.speech({
text: "Bonjour le monde",
language_code: "fr-CA",
voice_name: "French-Canadian.Female-1",
encoding: SpeechEncoding.LINEAR_PCM, // 1
sample_rate_hz: 44100,
});
console.log(contentType); // e.g. "audio/wav"
await writeFile("hello.wav", audio);Transcription (STT)
Transcribe audio. Accepts a Blob or File and posts as multipart/form-data.
import { readFile } from "node:fs/promises";
const buf = await readFile("speech.wav");
const file = new File([buf], "speech.wav", { type: "audio/wav" });
const res = await client.audio.transcriptions.create({
file,
model: "whisper-large-v3",
response_format: "verbose_json",
});
console.log(res.text);Configuration
new Bastion({
apiKey: "sk-...", // required
baseURL: "https://bastion.qubittron.ai", // optional (default)
fetch: customFetch, // optional (defaults to global fetch)
defaultHeaders: { "x-trace-id": "..." }, // optional
});If apiKey is omitted, the SDK reads BASTION_API_KEY from process.env.
Error handling
All API errors extend BastionError and expose status, code, type, and the raw body.
import {
AuthenticationError,
BadRequestError,
PermissionDeniedError,
RateLimitError,
UpstreamError,
APIConnectionError,
} from "@qubittron/bastion-sdk";
try {
await client.chat.completions.create({ model: "x", messages: [] });
} catch (err) {
if (err instanceof RateLimitError) {
// back off
} else if (err instanceof AuthenticationError) {
// refresh key
} else if (err instanceof APIConnectionError) {
// network problem
} else {
throw err;
}
}| HTTP | Class |
|---|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 402, 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 429 | RateLimitError |
| 502, 503, 504 | UpstreamError |
| other | APIError |
| network | APIConnectionError |
Compatibility
- Node 20+ (uses global
fetchandReadableStream) - Bun
- Edge runtimes (Cloudflare Workers, Vercel Edge)
- Modern browsers with global
fetch
Module formats: ESM + CJS. Types included.
Scope (v0.1)
- ✅
chat.completions.create(sync + stream) - ✅
models.list - ✅
images.generate - ✅
audio.speech,audio.transcriptions.create - ⬜ embeddings, responses (coming)
- ⬜ automatic retries / backoff (coming)
- ⬜ tool / function calling helpers (passthrough works today)
License
MIT
