@nublestation/blaze is two things in one package:
- A schema DSL (
defineSchema,t) you use to declare your tables in TypeScript. - A typed table client (
createBlazeClient) that gives every tablelist/get/create/update/deletemethods, fully typed from your schema.
You can also reach the same table client through the unified
@nublestation/client as nuble.blaze.
Installation
npm install @nublestation/blaze
# or
pnpm add @nublestation/blaze
1. Declare your schema
// schema.ts
import { defineSchema, t } from "@nublestation/blaze";
export const schema = defineSchema({
file_comments: t.model({
file_id: t.string().required(),
body: t.string().required(),
author_id: t.string().required(),
author_name: t.string().required(),
}),
});
Field builders: t.string(), t.number(), t.boolean(), t.uuid(), t.timestamp(),
t.json(), t.enum([...]), t.ref("table"). Modifiers: .required(), .unique(),
.default(value), .index(). Every table automatically gets an id (uuid, primary key)
and an app_id (uuid) column — you never declare those.
Push the schema with the CLI — see nuble db push.
2. Create a client
import { createBlazeClient } from "@nublestation/blaze";
import { schema } from "./schema";
const blaze = createBlazeClient({
baseUrl: "http://api.clinic.local",
apiKey: "nbl_<key_id>.<secret>",
schema,
}).db;
schema is optional, but passing it makes table names and row shapes type-safe.
3. CRUD
Every table exposes five methods. They map 1:1 to the auto-generated REST endpoints (Blaze service).
list
const comments = await blaze.file_comments.list();
const page2 = await blaze.file_comments.list({ limit: 20, offset: 20 });
list(opts?) returns every row for your app (subject to RLS), with optional limit and
offset for pagination.
get
const comment = await blaze.file_comments.get(commentId);
// returns the row, or throws if not found
create
const comment = await blaze.file_comments.create({
file_id: fileId,
body: "Looks good to me",
author_id: user.id,
author_name: user.name,
});
// returns the created row, with server-generated id
update
const updated = await blaze.file_comments.update(commentId, {
body: "Edited comment",
});
update accepts a partial — unknown fields are dropped silently by the server.
delete
await blaze.file_comments.delete(commentId);
Current limitations
Isolation
Every query runs inside a tenant-scoped transaction. Postgres Row-Level Security adds
app_id = current_setting('app.current_tenant') to every statement, so one app can never
read or write another app’s rows — even though they share one physical table. See
Row-Level Security.
Exports
import { defineSchema, t, serializeSchema, createBlazeClient } from "@nublestation/blaze";
import type { Schema, SerializedSchema, BlazeClient } from "@nublestation/blaze";