SDK tipado — Primeros pasos
Descripción general
Sección titulada «Descripción general»El paquete @rebasepro/client proporciona un SDK de JavaScript con seguridad de tipos para interactuar con tu backend de Rebase. Gestiona:
- Operaciones de datos — CRUD con filtrado, ordenación y paginación
- Obtención de relaciones — Incluye entidades relacionadas con
.include() - Suscripciones en tiempo real — Actualizaciones en vivo basadas en WebSocket
- Sincronización local-first y offline — Base de datos local de filas opcional, escrituras instantáneas offline, consultas en vivo
- Autenticación — Gestión de tokens, inicio de sesión, registro, OAuth
- Almacenamiento — Subida, descarga y gestión de archivos
- Funciones personalizadas — Llama a endpoints personalizados del servidor
Instalación
Sección titulada «Instalación»pnpm add @rebasepro/clientCreación de un cliente
Sección titulada «Creación de un cliente»rebase dev deriva un puerto libre a partir de la ruta del proyecto en lugar de usar uno fijo, por lo que debes leer baseUrl de la URL que imprimió; no hay un puerto compartido por todos los proyectos. En un frontend con Vite, ese es el VITE_API_URL que el scaffold escribe en .env; en un script, una variable de entorno propia.
import { createRebaseClient } from "@rebasepro/client";
const client = createRebaseClient({ baseUrl: import.meta.env.VITE_API_URL,});La websocketUrl se deriva automáticamente de baseUrl (http → ws, https → wss). Puedes sobrescribirla explícitamente si es necesario:
const client = createRebaseClient({ baseUrl: import.meta.env.VITE_API_URL, websocketUrl: import.meta.env.VITE_WS_URL,});Opciones de configuración
Sección titulada «Opciones de configuración»| Opción | Tipo | Descripción |
|---|---|---|
baseUrl |
string |
URL del backend. Léela de lo que imprimió rebase dev, o de tu despliegue |
websocketUrl |
string |
URL de WebSocket — derivada automáticamente de baseUrl si se omite |
token |
string |
Token JWT estático para llamadas de servidor a servidor |
apiPath |
string |
Prefijo de la API (por defecto: "/api") |
fetch |
typeof fetch |
Implementación personalizada de fetch (p. ej. para SSR) |
onUnauthorized |
() => Promise<boolean> |
Controlador personalizado para 401 — devuelve true para reintentar |
realtime |
boolean |
Abre el WebSocket (por defecto true) — establece false en scripts de ejecución única |
collections |
Record<string, string> |
Mapea nombres de accesores a slugs de colecciones |
offline |
boolean | OfflineConfig |
Sincronización local-first — desactivada por defecto |
impersonate |
string |
Ejecuta cada petición como este usuario (por uid), para comprobar qué ve un usuario. Solo con la sesión de un administrador: la API de datos, las funciones y el tiempo real se ejecutan como ese usuario, y cualquier otra ruta la rechaza |
Generación de SDK tipado
Sección titulada «Generación de SDK tipado»Genera un cliente totalmente tipado a partir de las definiciones de tus colecciones:
rebase generate-sdkMientras rebase dev está en ejecución no hace falta: regenera los tipos en generated/sdk/ al arrancar y en cada guardado bajo config/collections/. Ejecuta el comando tú mismo en CI, en un repositorio de frontend que no tiene colecciones (rebase generate-sdk --from link), o en cualquier lugar donde rebase dev no se esté ejecutando.
En 0.23, rebase dev deja los tipos del SDK como están, así que ejecuta
el comando después de cada cambio de colección.
Luego pasa el parámetro de tipo Database a createRebaseClient para obtener autocompletado completo:
import { createRebaseClient } from "@rebasepro/client";import { collectionsDictionary, type Database } from "./generated/sdk/database.types";
const client = createRebaseClient<Database>({ baseUrl: import.meta.env.VITE_API_URL, collections: collectionsDictionary,});
// Full autocomplete on collection names and field typesconst { data } = await client.data.products.find();Cuando se proporciona Database, createRebaseClient devuelve una instancia de CreateRebaseClientResult<DB>. Esto mapea los accesores de colecciones en camelCase directamente en client.data a sus tipos correspondientes, brindándote autocompletado completo en las operaciones y tipos de colecciones (p. ej., client.data.products.find()).
collectionsDictionary mapea cada accesor de vuelta al slug que se usa en la transmisión de datos. Pásalo siempre que un slug no sea ya un nombre de propiedad válido — my-notes es accesible como client.data.myNotes solo porque el diccionario así lo indica.
Algunos nombres de client.data están ocupados: collection es la función dinámica collection(slug), y then, toJSON y $$typeof se dejan intactos para las comprobaciones de promesas y de serialización. Una colección cuyo accesor fuera uno de ellos se genera como <name>Collection — el slug collection es client.data.collectionCollection — y generate-sdk imprime una advertencia que nombra ambos. client.data.collection("collection") también llega a ella.
Nombres de campos
Sección titulada «Nombres de campos»El nombre de un campo en la transmisión es su clave de propiedad, y la API utiliza camelCase en su totalidad. Una propiedad createdAt almacenada en una columna created_at es row.createdAt, y la clave foránea de una relación es authorId aunque la columna se mantenga como author_id. where y orderBy se basan en el mismo tipo Row, por lo que lo que compila es a lo que el backend responde.
Una clave de propiedad que tú escribiste es tu clave, cualquiera que sea su formato — nada renombra un nombre que hayas elegido. Las dos claves que se derivan en lugar de declararse, la clave foránea de una relación y una columna leída mediante introspección, están en camelCase.
Row describe una lectura, Insert un create() y Update un update() — no tienen la misma forma. Una columna que no es obligatoria es T | null en las tres, de modo que una escritura pueda vaciarla; la clave primaria siempre está presente en una lectura y nunca se puede establecer en una actualización; un destino belongsTo se puede escribir tanto como la relación ({ author: 5 }) o como su clave foránea ({ authorId: 5 }); y una pertenencia hasMany o manyToMany se escribe como una lista de ids de destino u objetos { id } ({ tags: ["t-1"] }), cada uno con un _pivot cuando la tabla de unión declara columnas de payload. Un campo que nadie puede escribir (access: { write: [] }) no está ni en Insert ni en Update. Una columna date se lee como una cadena ISO, y una escritura acepta esa cadena o un Date.
Ejemplo rápido
Sección titulada «Ejemplo rápido»// Createconst product = await client.data.products.create({ name: "Camera", price: 299,});
// Query with filtersconst { data } = await client.data.products .where("price", ">=", 100) .orderBy("createdAt", "desc") .limit(10) .find();
// Real-time subscriptionconst unsubscribe = client.data.products.listen( { where: { active: ["==", true] } }, (response) => console.log("Updated:", response.data));Uso con React
Sección titulada «Uso con React»En un frontend de Rebase, el cliente se crea una vez y se comparte a través del contexto:
import { createRebaseClient } from "@rebasepro/client";
const client = createRebaseClient({ baseUrl: API_URL });
<Rebase client={client} ...>Accede a él desde cualquier componente:
import { useRebaseClient } from "@rebasepro/app";
function MyComponent() { const client = useRebaseClient(); // client.data, client.auth, client.storage, client.functions}Siguientes pasos
Sección titulada «Siguientes pasos»- Consultar datos — CRUD, filtros, paginación y relaciones
- Autenticación — Inicio de sesión, registro, OAuth, sesiones
- Suscripciones en tiempo real — Datos en vivo con WebSockets
- Sincronización local-first y offline — Trabaja sin conexión y sincroniza cuando vuelva
- Almacenamiento y archivos — Sube, descarga y gestiona archivos