Client SDK
Overview
Section titled “Overview”The @rebasepro/client package provides a type-safe JavaScript SDK for interacting with your Rebase backend. It handles:
- Data operations — CRUD with filtering, sorting, and pagination
- Relation fetching — Include related entities with
.include() - Real-time subscriptions — WebSocket-based live updates
- Authentication — Token management, login, signup
- Storage — File upload and download
Installation
Section titled “Installation”pnpm add @rebasepro/clientimport { createRebaseClient } from "@rebasepro/client";
const client = createRebaseClient({ baseUrl: "http://localhost:3001", websocketUrl: "ws://localhost:3001"});The client automatically manages authentication tokens — once a user logs in, all subsequent requests include the JWT.
Data Operations
Section titled “Data Operations”Access any collection through client.data.<collectionName> (camelCase) or client.data.collection("slug") (kebab-case):
// Property-style access (auto-converts to kebab-case)client.data.blogPosts // → "blog-posts"client.data.users // → "users"
// Dynamic access by slugclient.data.collection("blog-posts")Find (List)
Section titled “Find (List)”// All products (default limit: 20)const { data, meta } = await client.data.products.find();
// With pagination, filtering, and sortingconst { data, meta } = await client.data.products.find({ where: { active: true, price: [">=", 100] }, orderBy: "created_at:desc", limit: 25, offset: 0});
// data is Entity<M>[] — each item has { id, values, path }// meta has { total, limit, offset, hasMore }Find by ID
Section titled “Find by ID”const product = await client.data.products.findById(42);// Entity<M> | undefinedCreate
Section titled “Create”const newProduct = await client.data.products.create({ name: "New Product", price: 29.99, active: true});
// With a specific IDconst newProduct = await client.data.products.create( { name: "Custom ID Product" }, "my-custom-id");Update
Section titled “Update”const updated = await client.data.products.update(42, { name: "Updated Name", price: 39.99});Delete
Section titled “Delete”await client.data.products.delete(42);Fluent Query Builder
Section titled “Fluent Query Builder”Chain methods for more expressive queries:
const { data } = await client.data.products .where("price", ">=", 100) .where("active", "==", true) .orderBy("created_at", "desc") .limit(10) .find();Available Methods
Section titled “Available Methods”| Method | Description | Example |
|---|---|---|
.where(field, op, value) | Add a filter condition | .where("age", ">=", 18) |
.orderBy(field, dir) | Sort results | .orderBy("name", "asc") |
.limit(n) | Limit result count | .limit(25) |
.offset(n) | Skip first N results | .offset(50) |
.search(text) | Full-text search | .search("laptop") |
.include(...relations) | Include related entities | .include("author", "tags") |
.find() | Execute the query | Returns FindResponse<M> |
.listen(onUpdate) | Subscribe to real-time updates | Returns unsubscribe() |
Filter Operators
Section titled “Filter Operators”| Operator | Alias | Description |
|---|---|---|
"==" | "eq" | Equal |
"!=" | "neq" | Not equal |
">" | "gt" | Greater than |
">=" | "gte" | Greater than or equal |
"<" | "lt" | Less than |
"<=" | "lte" | Less than or equal |
"in" | Value in array | |
"not-in" | "nin" | Value not in array |
"array-contains" | "cs" | Array field contains value |
"array-contains-any" | "csa" | Array field contains any of values |
Fetching Relations
Section titled “Fetching Relations”Relations can be included in query results so that related entities are returned alongside the primary data, instead of just their foreign key IDs.
Using include() (Fluent)
Section titled “Using include() (Fluent)”// Include specific relationsconst { data } = await client.data.posts .include("author", "categories") .find();
// Include all defined relationsconst { data } = await client.data.posts .include("*") .find();Using find({ include }) (Params)
Section titled “Using find({ include }) (Params)”const { data } = await client.data.posts.find({ include: ["author", "categories"]});Combining with Filters
Section titled “Combining with Filters”const { data } = await client.data.posts .where("status", "==", "published") .include("author") .orderBy("published_at", "desc") .limit(10) .find();Reading Relation Data
Section titled “Reading Relation Data”When relations are included, the response contains both the scalar foreign key and the hydrated relation object:
const { data } = await client.data.posts .include("author") .find();
for (const post of data) { // Scalar foreign key — always present console.log(post.values.author_id); // "uuid-1234"
// Hydrated relation — present when included console.log(post.values.author?.name); // "Jane Doe"}Note: Without
.include("author"), only the scalarauthor_idfield is returned. The hydratedauthorobject will beundefined.
Relation Names
Section titled “Relation Names”The relation names you pass to include() must match the relationName defined in the collection’s relations array. For example:
// Collection definitionrelations: [ { relationName: "author", target: () => usersCollection, ... }, { relationName: "categories", target: () => categoriesCollection, ... }]
// SDK usage — names must matchclient.data.articles.include("author", "categories").find()Real-time Subscriptions
Section titled “Real-time Subscriptions”Subscribe to collection changes via WebSocket:
// Subscribe to all active productsconst unsubscribe = client.data.products.listen( { where: { active: true }, limit: 50 }, (response) => { console.log("Products updated:", response.data); });
// Unsubscribe when doneunsubscribe();Subscribe to a single entity:
const unsubscribe = client.data.products.listenById( 42, (entity) => { console.log("Product changed:", entity); });You can also subscribe through the fluent query builder:
const unsubscribe = client.data.products .where("active", "==", true) .orderBy("created_at", "desc") .limit(20) .listen( (response) => console.log("Updated:", response.data), (error) => console.error("Error:", error) );The WebSocket client handles reconnection automatically.
Authentication
Section titled “Authentication”// Loginconst session = await client.auth.signIn("user@example.com", "password");
// Registerconst session = await client.auth.signUp("user@example.com", "password");
// Google OAuthconst session = await client.auth.signInWithGoogle(googleIdToken);
// Refresh tokenawait client.auth.refreshToken();
// Logoutawait client.auth.signOut();
// Get current userconst user = client.auth.getUser();Storage
Section titled “Storage”// Uploadconst result = await client.storage.uploadFile(file, "products/image.jpg");
// Get URLconst url = await client.storage.getDownloadURL("products/image.jpg");
// Deleteawait client.storage.deleteFile("products/image.jpg");Custom Endpoints
Section titled “Custom Endpoints”Call custom server endpoints (Cloud Functions, custom routes, etc.):
const result = await client.call<{ summary: string }>("generate-summary", { articleId: 42});Using with React
Section titled “Using with React”In a Rebase frontend, the client is typically created once and shared via context:
const client = createRebaseClient({ baseUrl: API_URL, websocketUrl: WS_URL });
// Pass to Rebase provider<Rebase client={client} ...>Access it from any component:
import { useRebaseClient } from "@rebasepro/core";
function MyComponent() { const client = useRebaseClient(); // Use client.data, client.auth, client.storage}SDK Generator
Section titled “SDK Generator”Generate a fully typed client SDK from your collection definitions:
rebase generate-sdkThis creates TypeScript types for all your entities, so you get autocomplete and type checking when using the client. Both scalar foreign keys and relation objects are included in the generated Database types.
Next Steps
Section titled “Next Steps”- Relations — Define relations between collections
- Frontend Overview — React framework and components
- Backend Overview — Server configuration