Aller au contenu

SDK Client

Le package @rebasepro/client fournit un SDK JavaScript typé pour interagir avec votre backend Rebase. Il gère :

  • Opérations sur les données — CRUD avec filtrage, tri et pagination
  • Récupération des relations — Inclure les entités liées avec .include()
  • Abonnements en temps réel — Mises à jour en direct basées sur WebSocket
  • Authentification — Gestion des jetons, connexion, inscription
  • Stockage — Téléchargement et envoi de fichiers
pnpm add @rebasepro/client
import { createRebaseClient } from "@rebasepro/client";
const client = createRebaseClient({
baseUrl: "http://localhost:3001",
websocketUrl: "ws://localhost:3001"
});

Le client gère automatiquement les jetons d’authentification — une fois qu’un utilisateur est connecté, toutes les requêtes subséquentes incluent le JWT.

Accédez à toute collection via client.data.<collectionName> (camelCase) ou 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 slug
client.data.collection("blog-posts")
// All products (default limit: 20)
const { data, meta } = await client.data.products.find();
// With pagination, filtering, and sorting
const { 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 }
const product = await client.data.products.findById(42);
// Entity<M> | undefined
const newProduct = await client.data.products.create({
name: "New Product",
price: 29.99,
active: true
});
// With a specific ID
const newProduct = await client.data.products.create(
{ name: "Custom ID Product" },
"my-custom-id"
);
const updated = await client.data.products.update(42, {
name: "Updated Name",
price: 39.99
});
await client.data.products.delete(42);

Chaînez les méthodes pour des requêtes plus expressives :

const { data } = await client.data.products
.where("price", ">=", 100)
.where("active", "==", true)
.orderBy("created_at", "desc")
.limit(10)
.find();
MéthodeDescriptionExemple
.where(field, op, value)Ajoute une condition de filtre.where("age", ">=", 18)
.orderBy(field, dir)Trie les résultats.orderBy("name", "asc")
.limit(n)Limite le nombre de résultats.limit(25)
.offset(n)Saute les N premiers résultats.offset(50)
.search(text)Recherche plein texte.search("laptop")
.include(...relations)Inclut les entités liées.include("author", "tags")
.find()Exécute la requêteRetourne FindResponse<M>
.listen(onUpdate)S’abonne aux mises à jour en temps réelRetourne unsubscribe()
OpérateurAliasDescription
"==""eq"Égal à
"!=""neq"Différent de
">""gt"Supérieur à
">=""gte"Supérieur ou égal à
"<""lt"Inférieur à
"<=""lte"Inférieur ou égal à
"in"Valeur dans le tableau
"not-in""nin"Valeur non présente dans le tableau
"array-contains""cs"Champ tableau contient la valeur
"array-contains-any""csa"Champ tableau contient l’une des valeurs

Les relations peuvent être incluses dans les résultats de requête afin que les entités liées soient retournées avec les données primaires, au lieu de leurs seuls IDs de clé étrangère.

// Include specific relations
const { data } = await client.data.posts
.include("author", "categories")
.find();
// Include all defined relations
const { data } = await client.data.posts
.include("*")
.find();
const { data } = await client.data.posts.find({
include: ["author", "categories"]
});
const { data } = await client.data.posts
.where("status", "==", "published")
.include("author")
.orderBy("published_at", "desc")
.limit(10)
.find();

Lorsque les relations sont incluses, la réponse contient à la fois la clé étrangère scalaire et l’objet de relation hydraté :

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 : Sans .include("author"), seul le champ scalaire author_id est retourné. L’objet author hydraté sera undefined.

Les noms de relation que vous passez à include() doivent correspondre au relationName défini dans le tableau relations de la collection. Par exemple :

// Collection definition
relations: [
{ relationName: "author", target: () => usersCollection, ... },
{ relationName: "categories", target: () => categoriesCollection, ... }
]
// SDK usage — names must match
client.data.articles.include("author", "categories").find()

Abonnez-vous aux changements de collection via WebSocket :

// Subscribe to all active products
const unsubscribe = client.data.products.listen(
{ where: { active: true }, limit: 50 },
(response) => {
console.log("Products updated:", response.data);
}
);
// Unsubscribe when done
unsubscribe();

Abonnez-vous à une seule entité :

const unsubscribe = client.data.products.listenById(
42,
(entity) => {
console.log("Product changed:", entity);
}
);

Vous pouvez également vous abonner via le constructeur de requêtes fluide :

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)
);

Le client WebSocket gère la reconnexion automatiquement.

// Connexion
const session = await client.auth.signIn("user@example.com", "password");
// Inscription
const session = await client.auth.signUp("user@example.com", "password");
// OAuth Google
const session = await client.auth.signInWithGoogle(googleIdToken);
// Rafraîchir le jeton
await client.auth.refreshToken();
// Déconnexion
await client.auth.signOut();
// Obtenir l'utilisateur actuel
const user = client.auth.getUser();
// Télécharger
const result = await client.storage.uploadFile(file, "products/image.jpg");
// Obtenir l'URL
const url = await client.storage.getDownloadURL("products/image.jpg");
// Supprimer
await client.storage.deleteFile("products/image.jpg");

Appelez les points de terminaison de serveur personnalisés (Fonctions Cloud, routes personnalisées, etc.) :

const result = await client.call<{ summary: string }>("generate-summary", {
articleId: 42
});

Dans un frontend Rebase, le client est typiquement créé une seule fois et partagé via un contexte :

const client = createRebaseClient({ baseUrl: API_URL, websocketUrl: WS_URL });
// Pass to Rebase provider
<Rebase client={client} ...>

Accédez-y depuis n’importe quel composant :

import { useRebaseClient } from "@rebasepro/core";
function MyComponent() {
const client = useRebaseClient();
// Utilisez client.data, client.auth, client.storage
}

Générez un SDK client entièrement typé à partir de vos définitions de collection :

rebase generate-sdk

Cela crée des types TypeScript pour toutes vos entités, vous bénéficiez ainsi de l’autocomplétion et de la vérification de type lors de l’utilisation du client. Les clés étrangères scalaires et les objets de relation sont inclus dans les types Database générés.