TypeScript client SDK for Snapbase.
npm install @snapbase/client-sdkimport { SnapbaseClient } from "@snapbase/client-sdk";
const client = new SnapbaseClient({
baseUrl: "http://localhost:7070",
onAuthExpired: () => {
// Token expired — redirect to login, show a modal, etc.
window.location.href = "/login";
},
});Create a single SnapbaseClient instance and import it across your app — just like PocketBase. The authStore (token, userId, isValid) lives on this instance and stays in sync everywhere.
// lib/snapbase.ts
import { SnapbaseClient } from "@snapbase/client-sdk";
export const sb = new SnapbaseClient({
baseUrl: "http://localhost:7070",
onAuthExpired: () => window.location.href = "/login",
});// any component / file
import { sb } from "@/lib/snapbase";
sb.authStore.isValid; // true | false
sb.authStore.token; // "eyJ..."
sb.authStore.userId; // user id | nullReact: sb.authStore.isValid is not reactive on its own — React only re-renders on state changes. Sync it manually after login() / logout():
const [loggedIn, setLoggedIn] = useState(sb.authStore.isValid);
await sb.login(email, password);
setLoggedIn(sb.authStore.isValid);Solid.js: works out of the box. Fine-grained reactivity tracks property reads automatically — no syncing or context needed.
// User signup
await client.signup("Alice", "alice@test.com", "password");
// User login — token and userId are stored automatically
await client.login("alice@test.com", "password");
console.log(client.authStore.isValid); // true
console.log(client.authStore.token); // "eyJ..."
console.log(client.authStore.userId); // "yad87ap3j52peu4" | null
// Logout
client.logout();All subsequent requests automatically include Authorization: Bearer <token>.
When a request returns 401 (expired/invalid token), the SDK automatically clears the token and fires onAuthExpired. A 403 response (valid token but insufficient role) does not trigger the callback — the error bubbles to your app code so you can handle it gracefully.
// 401 — calls onAuthExpired, clears token
const users = await client.collection("users").getList();
// 403 — returns normally, token stays, caller decides what to do
const response = await client.collection("admin-only").getList();
if (response.status === "error") {
showToast("You don't have access to this resource");
}// Get a collection handle
const posts = client.collection("posts");
// Insert a record
await posts.create({ title: "Hello", body: "World" });
// Query records
await posts.getList({
filter: { title: "~Hello" },
sort: { created_at: "DESC" },
limit: 10,
});
// Update records by filter
await posts.update(
{ title: "Updated" },
{ filter: { title: "=Hello" } }
);
// Response: { status: "success", data: { updated: 1 } }
// Delete records by filter
await posts.delete({ filter: { title: "~spam" } });Wrap a collection in a Model to get compile-time type safety on records, field names, and filter keys.
import { SnapbaseClient, Model } from "@snapbase/client-sdk";
type User = {
id: string;
email: string;
name: string;
age: number;
};
const client = new SnapbaseClient();
const Users = new Model<User>(client.collection("users"));
// getList returns typed records
const allUsers = await Users.getList();
// allUsers: User[]
// Filter/sort keys are autocompleted
const adults = await Users.getList({
filter: { age: ">=18" },
sort: { name: "ASC" },
});
// create is type-checked
await Users.create({ email: "bob@test.com", name: "Bob", age: 25 });
// update with typed filter keys
await Users.update(
{ age: 31 },
{ filter: { email: "=bob@test.com" } }
);
// delete with typed filter keys
await Users.delete({ filter: { age: "<18" } });Define your type once and get autocomplete for field names everywhere — no more guessing or typos.
| Option | Type | Default | Description |
|---|---|---|---|
baseUrl |
string |
"http://localhost:7070" |
Snapbase backend URL |
onAuthExpired |
() => void |
— | Called when a 401 response is received |
| Method | Returns | Description |
|---|---|---|
login(email, password) |
Promise<ApiResponse> |
Authenticate user, stores token in authStore |
signup(name, email, password) |
Promise<ApiResponse> |
Register a new user |
logout() |
void |
Clears the stored auth token |
collection(name) |
CollectionService |
Get a collection handle |
| Method | Returns | Description |
|---|---|---|
getList(params?) |
Promise<ApiResponse> |
Query records with filters, sorting, and pagination |
create(data) |
Promise<ApiResponse> |
Insert a record |
update(data, filter) |
Promise<ApiResponse> |
Update records by filter |
delete(params?) |
Promise<ApiResponse> |
Delete records by filter |
| Method | Returns | Description |
|---|---|---|
getList(params?) |
Promise<T[]> |
Query records with typed filter/sort keys |
create(data) |
Promise<ApiResponse> |
Insert a record (type-checked Partial<T>) |
update(data, params) |
Promise<ApiResponse> |
Update records with typed filter keys |
delete(params?) |
Promise<ApiResponse> |
Delete records with typed filter keys |
| Operator | Example | Description |
|---|---|---|
= |
"=alice@test.com" |
Equal |
!= |
"!=spam" |
Not equal |
> |
">18" |
Greater than |
< |
"<100" |
Less than |
>= |
">=18" |
Greater than or equal |
<= |
"<=100" |
Less than or equal |
~ |
"~john" |
Contains / like |
!~ |
"!~test" |
Does not contain |
# 1. Build the SDK
npm run build
# 2. Register it globally
npm link
# 3. Link into your test project
cd ../your-test-project
npm link @snapbase/client-sdk
# 4. (Optional) Start watch mode for live edits
cd ../snapbase-client-sdk
npm run devThe test project's node_modules/@snapbase/client-sdk will be a symlink to this directory. Changes to src/ rebuild automatically with npm run dev.
To unlink:
cd ../your-test-project
npm unlink @snapbase/client-sdk
cd ../snapbase-client-sdk
npm unlink -g