
Documentación
Introducción
MatecitoDB es un Backend-as-a-Service (BaaS) con autenticación, bases de datos en tiempo real, storage y más. Soporta JavaScript/TypeScript y Flutter/Dart. El SDK soporta API v1 (default) y v2 (recomendada).
API v1 vs v2
El SDK soporta ambas versiones. Por defecto usa v1 para compatibilidad. Activá v2 para Functions, Analytics, AI, Remote Config, Forms, filtros avanzados y fixes de seguridad.
Compatible con todos los proyectos existentes.
// API v1 (default) — Compatibilidad con proyectos existentes
export const db = createClient<Database>({
url: process.env.MATECITODB_URL!,
apiKey: process.env.MATECITODB_API_KEY!,
apiVersion: 'v1', // default, no hace falta especificarlo
})Incluye todos los módulos nuevos y security hardening.
// API v2 (recomendada) — Features avanzadas + security fixes
export const db = createClient<Database>({
url: process.env.MATECITODB_URL!,
apiKey: process.env.MATECITODB_API_KEY!,
apiVersion: 'v2',
})
// Con serviceKey (server-side / admin)
export const dbAdmin = createClient<Database>({
url: process.env.MATECITODB_URL!,
serviceKey: process.env.MATECITODB_SERVICE_KEY!,
apiVersion: 'v2',
})Inicialización
Inicializá el cliente con tus variables de entorno. Nunca expongas serviceKey en el cliente.
import { createClient } from 'matecitodb'
import type { Database } from '@/matecito/database'
export const db = createClient<Database>({
url: process.env.MATECITODB_URL!,
apiKey: process.env.NEXT_PUBLIC_MATECITODB_API_KEY!,
// serviceKey: process.env.MATECITODB_SERVICE_KEY!, // server-side
// apiVersion: 'v2', // descomentá para v2
})Auth — Básico
Registro, login, logout y perfil del usuario actual.
// Registro
const { user } = await db.auth.signUp({
email: 'user@example.com',
password: 'secure-password',
name: 'Juan Pérez',
})
// Login
const { token, user } = await db.auth.signIn({
email: 'user@example.com',
password: 'secure-password',
})
// Logout
await db.auth.signOut()
// Usuario actual
const me = await db.auth.getMe()Auth — Sesión
Gestión de tokens, refresh y listener de cambios de sesión.
// Persistir sesión manualmente
await db.auth.setSession(token)
// Refresh de token expirado
const { token: newToken } = await db.auth.refreshSession()
// Escuchar cambios de sesión
const unsub = db.auth.onAuthChange((event, session) => {
// event: 'SIGNED_IN' | 'SIGNED_OUT' | 'TOKEN_REFRESHED'
if (event === 'SIGNED_IN') console.log('User:', session?.user)
if (event === 'SIGNED_OUT') router.push('/login')
})
// unsub() para dejar de escucharAuth — Contraseña
// Solicitar reset de contraseña
await db.auth.requestPasswordReset('user@example.com')
// Confirmar reset (con token del email)
await db.auth.resetPassword({ token: 'reset-token', newPassword: 'new-pass' })
// Verificar email
await db.auth.verifyEmail(token)
await db.auth.resendVerification('user@example.com')
// Actualizar perfil
await db.auth.updateProfile({ name: 'New Name', avatar_url: 'https://...' })Auth — OAuth (v2)
Login con Google, GitHub, Discord y Apple. Solo disponible en proyectos v2.
// Obtener URL OAuth (v2)
const { url } = await db.auth.getOAuthUrl('google')
window.location.href = url
// Manejar callback en /auth/callback
const { token, user } = await db.auth.handleOAuthCallback(window.location.href)Auth — Magic Link (v2)
Login sin contraseña por email. El usuario recibe un link que lo autentica automáticamente.
// Magic link (v2 only)
await db.auth.magicLink('user@example.com')
// El usuario recibe email → link → autenticado automáticamenteAuth — TOTP / 2FA (v2)
Autenticación de dos factores con Google Authenticator, Authy o cualquier app TOTP.
// TOTP / 2FA (v2 only)
// 1. Setup — devuelve secret + QR URL
const { secret, qr_url } = await db.auth.totpSetup()
// 2. Confirmar con código del authenticator
await db.auth.totpConfirm({ code: '123456' })
// 3. Verificar en cada login
await db.auth.totpVerify({ code: '123456' })
// 4. Desactivar 2FA
await db.auth.totpDisable({ password: 'current-password' })Auth — Admin & Roles
Gestión de usuarios y roles desde el servidor. Requiere serviceKey.
// Auth Admin (serviceKey requerida)
// Listar usuarios
const { users } = await db.auth.admin.listUsers({ page: 1, limit: 50 })
// Crear usuario como admin
const { user } = await db.auth.admin.createUser({
email: 'user@example.com', password: 'pass', name: 'Juan',
})
// Banear / desbanear
await db.auth.admin.banUser(userId)
await db.auth.admin.unbanUser(userId)
// Eliminar usuario
await db.auth.admin.deleteUser(userId)
// Roles
await db.auth.roles.assign(userId, 'moderator')
await db.auth.roles.revoke(userId, 'moderator')// Invitaciones
const { link } = await db.auth.invitations.create({
email: 'nuevo@example.com',
role: 'editor',
expiresInHours: 48,
})
// Listar invitaciones pendientes
const { invitations } = await db.auth.invitations.list()
// Revocar
await db.auth.invitations.revoke(invitationId)QueryBuilder — Filtros
API fluida y tipada para consultar datos. Todos los métodos son encadenables.
// QueryBuilder — API fluida y tipada
const posts = await db
.from('posts')
.eq('status', 'published')
.order('created_at', 'desc')
.limit(20)
.get()
// Múltiples filtros
const results = await db
.from('products')
.gte('price', 100)
.lte('price', 500)
.like('name', '%laptop%')
.in('category', ['tech', 'gaming'])
.notIn('status', ['draft', 'archived'])
.limit(10)
.get()
// Búsqueda por campo nullable
const noPhone = await db.from('users').isNull('phone').get()
// Contiene en array (v2)
const tagged = await db.from('posts').has('tags', 'javascript').get()QueryBuilder — Avanzado
Full-text search, vector search, OR conditions, relaciones y más.
// Full-text search (v2)
const articles = await db
.from('articles')
.search('base de datos')
.order('relevance', 'desc')
.get()
// Vector / semántico (v2)
const similar = await db
.from('documents')
.searchFullText('machine learning')
.limit(5)
.get()
// Between
const recent = await db
.from('orders')
.between('created_at', '2024-01-01', '2024-12-31')
.get()
// OR conditions
const active = await db
.from('users')
.or([{ field: 'status', op: 'eq', value: 'active' }, { field: 'role', op: 'eq', value: 'admin' }])
.get()
// Relaciones (populate)
const withAuthor = await db
.from('posts')
.populate('author_id', 'users')
.limit(10)
.get()
// Soft-deleted + expirados
const all = await db.from('items').includeDeleted().includeExpired().get()QueryBuilder — Mutaciones
Insert, upsert, update, merge, delete, hard delete y restore.
// Crear
const post = await db.from('posts').insert({ title: 'Hola', status: 'draft' })
// Crear múltiples
const posts = await db.from('posts').insertMany([
{ title: 'Post 1' }, { title: 'Post 2' },
])
// Upsert (insert o update por clave única)
await db.from('users').upsert({ email: 'j@ex.com', name: 'Juan' }, 'email')
// Actualizar filtrado
await db.from('posts').eq('status', 'draft').update({ status: 'published' })
// Merge (actualización parcial con ID)
await db.from('products').merge(productId, { price: 299 })
// Soft delete
await db.from('posts').eq('id', postId).delete()
// Hard delete (permanente)
await db.from('posts').eq('id', postId).hardDelete()
// Restaurar soft-deleted
await db.from('posts').eq('id', postId).restore()QueryBuilder — Paginación
paginate(), findOne(), count(), select() y export().
// Paginación fluida
const page = await db
.from('products')
.eq('category', 'tech')
.order('price', 'asc')
.paginate(1, 20) // página 1, 20 por página
// Devuelve:
// { data: [...], total: 150, page: 1, limit: 20, pages: 8 }
// findOne
const user = await db.from('users').eq('email', 'j@ex.com').findOne()
// count
const total = await db.from('posts').eq('status', 'published').count()
// Seleccionar campos
const names = await db
.from('users')
.select(['id', 'name', 'email'])
.limit(100)
.get()
// Exportar (v2)
const csv = await db.from('orders').export('csv')
const json = await db.from('orders').export('json')QueryBuilder — Realtime
subscribe() y watch() directamente desde el QueryBuilder.
// Realtime desde QueryBuilder
const unsubscribe = await db
.from('messages')
.eq('room_id', 'room-123')
.subscribe((event) => {
// event.action: 'create' | 'update' | 'delete'
console.log('Nuevo evento:', event.action, event.record)
})
// watch — escucha todos los eventos de una colección
const stop = db.from('notifications').watch((event) => {
if (event.action === 'create') showToast(event.record.message)
})
unsubscribe() // o stop()Records (API clásica)
API imperativa con db.records.*. Compatible con v1 y v2.
// API clásica (db.records)
const record = await db.records.create('users', {
name: 'Juan', email: 'juan@example.com',
})
const { records, pagination } = await db.records.list('users', {
page: 1, limit: 50, sort: '-created_at',
})
await db.records.update(record.id, { name: 'Juan Updated' })
await db.records.delete(record.id)
await db.records.hardDelete(record.id)Realtime
Suscripción a eventos en tiempo real. v1 usa /ws, v2 usa /realtime (con presence).
// Suscripción básica
const unsubscribe = db.realtime.subscribe('users', (event) => {
console.log('Acción:', event.action) // create | update | delete
console.log('Registro:', event.record)
})
// Con filtro
db.realtime.subscribe('posts', (event) => {
setFeed(prev => [event.record, ...prev])
}, { status: 'published' })
unsubscribe()Almacenamiento
// Subir archivo
const file = await db.storage.upload('avatar.png', fileData, {
collection: 'users',
recordId: 'user-id-123',
public: true,
})
// Obtener URL pública
const url = db.storage.getUrl(file.path)
// Listar archivos
const { files } = await db.storage.list({ collection: 'users', recordId: 'user-id-123' })
// Eliminar
await db.storage.delete(file.id)Email (SMTP)
// Configurar SMTP
await db.emails.saveSmtp({
host: 'smtp.gmail.com',
port: 587,
username: 'noreply@myapp.com',
password: 'app-password',
secure: false,
})
// Enviar
await db.emails.send({
to: ['user@example.com'],
subject: 'Bienvenido a mi app',
html: '<h1>¡Hola!</h1><p>Gracias por registrarte.</p>',
})Functions (v2)
Ejecutar y gestionar serverless functions. Requiere proyecto v2.
// Invocar una function (v2)
const { result, duration_ms } = await db.functions.invoke('send-welcome', {
args: { email: 'user@example.com', name: 'Juan' },
})
// Crear function
await db.functions.create({
name: 'process-order',
code: `const { args, db } = context; return { ok: true }`,
timeout_ms: 5000,
is_public: false,
})
// Listar
const { functions } = await db.functions.list()
// Historial de ejecuciones
const { executions } = await db.functions.history('send-welcome')Analytics (v2)
Eventos, funnels y métricas de uso. Requiere proyecto v2.
// Trackear evento (v2)
await db.analytics.track('page_view', {
user_id: currentUser.id,
properties: { page: '/pricing', source: 'google' },
})
// Obtener eventos agrupados
const { results } = await db.analytics.events({
group_by: 'event',
days: 30,
})
// Funnel de conversión
const { funnel } = await db.analytics.funnel({
steps: ['page_view', 'signup', 'checkout', 'purchase'],
})AI Gateway (v2)
Integrá OpenAI, Anthropic o Groq sin exponer API keys al cliente.
// Configurar AI (v2)
await db.ai.setConfig({
provider: 'openai', // 'anthropic' | 'groq'
model: 'gpt-4o-mini',
api_key: 'sk-...',
})
// Chat completion
const { content } = await db.ai.chat([
{ role: 'user', content: '¿Cómo implemento auth con matecitodb?' },
])
// Con system prompt
const { content } = await db.ai.chat(messages, {
system: 'Sos un asistente técnico de MatecitoDB.',
max_tokens: 500,
})Remote Config (v2)
Feature flags y configuración remota en tiempo real.
// Remote Config (v2)
// Obtener todos los valores
const { configs } = await db.config.getAll()
// Obtener uno
const mode = await db.config.get('maintenance_mode')
// Crear / actualizar
await db.config.set('maintenance_mode', false, {
description: 'Desactiva el acceso público',
})
// Eliminar
await db.config.delete('old_flag')Notificaciones (v2)
Push notifications a dispositivos iOS, Android y Web.
// Notificaciones push (v2)
// Registrar dispositivo
await db.notifications.registerDevice({
token: fcmToken,
platform: 'android', // 'ios' | 'web'
})
// Enviar notificación
await db.notifications.send({
user_ids: [userId],
title: '¡Nueva actualización!',
body: 'Revisá las novedades de la app.',
data: { screen: 'updates' },
})
// Enviar a todos
await db.notifications.broadcast({
title: 'Mantenimiento programado',
body: 'El servicio estará caído el sábado 02:00-04:00 AM.',
})