TypeScript SDK
@jaina/sdk — typed client for Node and the browser.
Install
Heads up:
@jaina/sdkis publishing soon and is not yet on npm. Until it ships, use the REST API directly. The examples below are correct for when the package is live.
npm install @jaina/sdk
Quickstart
import { JainaClient } from '@jaina/sdk';
const jaina = new JainaClient({
apiKey: process.env.JAINA_API_KEY!,
});
const projects = await jaina.projects.list();
console.log(projects); // Project[]
Resources
The client mirrors the REST API surface:
jaina.projects— list, get, create, update, deletejaina.schemas—(projectSlug)→ list/get/create/update/deletejaina.packages—(projectSlug)→ list/get/create/update/deletejaina.records:(projectSlug, schemaSlug)→ list/listTyped/get/getTyped/create/update/deletejaina.files: uploadjaina.actions— define and execute actionsjaina.webhooks— register, list, test
Typed records
Use listTyped<T>() for full type safety. The fields of T are flattened onto each record alongside its metadata:
interface Enemy {
name: string;
hp: number;
attack: number;
sprite: string;
rarity: 'common' | 'uncommon' | 'rare' | 'mythic';
}
const enemies = await jaina.records.listTyped<Enemy>('my-game', 'enemy', {
page: 1,
limit: 50,
});
enemies.data.forEach((e) => {
// e.name and e.hp are typed; e.id, e.created_at, etc. are also present
});
List options are page, limit, package_slug, and paginate. There is no server-side filter option, so filter the returned data array in your own code.
Generate the interface from your schema with jaina codegen --lang typescript.
Error handling
import { JainaError } from '@jaina/sdk';
try {
await jaina.records.create('my-game', 'enemy', { /* ... */ });
} catch (err) {
if (err instanceof JainaError) {
console.error(err.status, err.code, err.message);
if (err.code === 'validation_failed') {
console.error(err.issues);
}
} else {
throw err;
}
}
Pagination
list and listTyped return a paginated envelope ({ data, total, page, limit, pages }). Walk pages by incrementing page:
let page = 1;
while (true) {
const result = await jaina.records.list('my-game', 'enemy', { page, limit: 50 });
for (const record of result.data) {
/* ... */
}
if (page * result.limit >= result.total) break;
page++;
}
Browser usage
The SDK works in browsers if you wrap it with an authenticated proxy on your backend. Never put jn_live_... tokens in client-side bundles.
