ReboFilesDocs
Empezar3
Qué es ReboFiles
Primeros pasos
Demos para ejecutar
Ponlo en tu app6
Componente de React
Headless: tu propia interfaz
Sin framework
Estilos y temas
Teclado y accesibilidad
Idiomas
Archivos9
Subidas
Vistas previas y el visor
Búsqueda
Cambios en vivo y carpetas grandes
Comentarios
Destacados y campos
Versiones, papelera y espacio
Descargar como .zip
Documentos de Word
El servidor14
La ruta
Frameworks e inicio de sesión
Quién puede hacer qué
Almacenamiento: S3, GCS, Azure y disco
Revisar las subidas
Metadatos: SQLite y Postgres
Esquema de la base de datos
Compartir y enlaces
Actividad y notificaciones
Ganchos, registros y límites
Retención, bloqueos y exportación
Escritorio y otros orígenes
Sincronizar una carpeta
Ir a producción
En equipo1
Asistentes de IA (MCP)
Referencia5
Paquetes
Componentes y hooks
API del cliente
Rutas HTTP
Estado y hoja de ruta
↑↓ para moverte↵ para abrirEsc para cerrar38 páginas

El servidor La ruta

La ruta

createDriveHandler recibe un Request y devuelve un Response. Todas las rutas del drive viven bajo una misma ruta, y ninguna transporta los bytes salvo en un disco: al navegador se le dan direcciones a las que enviarlos y desde las que leerlos.
Next.js

En Next.js

app/api/files/[...path]/route.ts
import { byRoles, createDriveHandler, s3OptionsFrom, s3Storage, sqliteMetadata } from '@rebofiles/server';
import { session } from '@/lib/auth'; // your own

const handle = createDriveHandler({
  storage: s3Storage(s3OptionsFrom(process.env)),
  metadata: await sqliteMetadata('drive.sqlite'),
  identify: async (request) => {
    const user = await session(request);
    return user ? { id: user.id, admin: user.isAdmin } : null;
  },
  authorize: byRoles,
  secret: process.env.REBOFILES_SECRET!,
  base: '/api/files',
});

export { handle as GET, handle as POST, handle as PATCH, handle as PUT, handle as DELETE };
Node

Sobre node:http

nodeHandler lo convierte en un listener, para node:http, Express y lo que esté construido encima.

server.ts
import { createServer } from 'node:http';
import { createDriveHandler, diskStorage, everyone, memoryMetadata, nodeHandler } from '@rebofiles/server';

const handle = createDriveHandler({
  storage: diskStorage({ folder: './storage', secret: process.env.REBOFILES_SECRET! }),
  metadata: memoryMetadata(),
  ...everyone(), // only on your own machine: no sign-in, everyone may do everything
  secret: process.env.REBOFILES_SECRET!,
  base: '/api/files',
});

createServer(nodeHandler(handle)).listen(3000);
Opciones

Todas las opciones

OpciónTypeWhat it does
storageStorageDónde están los bytes: s3Storage(s3OptionsFrom(process.env)), gcsStorage(…), azureStorage(…) o diskStorage({ folder, secret }).
metadataMetadataStoreDónde están las entradas: memoryMetadata(), sqliteMetadata(path) o postgresMetadata(pool).
identify(request) => User | nullQuién pregunta, a partir de tu sesión; null responde 401. { id, admin: true } puede configurar el drive con byRoles.
authorize(user, action, entry, drive) => booleanSe consulta en cada ruta; false responde 403. byRoles, o reglas propias alrededor.
secretstringCon qué se firman los tokens: largo, aleatorio, el mismo en cada proceso.
basestringLa ruta bajo la que están las rutas: /api/files.
top'own' | 'everyone'Lo que muestra Mis archivos arriba del todo: lo de cada persona (por defecto), o todo lo que uno puede leer, para un solo drive de todo un equipo.
maxSizenumberEl archivo más grande que se acepta, en bytes; 5 GiB si no se dice.
settingsPartial<DriveSettings>Los valores por defecto hasta que alguien los cambie: idioma, tema, color de marca, imágenes, quota, trashDays, y company, el nombre que muestra la página de una solicitud de archivos.
cors{ origins: string[] }Páginas de otros orígenes que pueden usar las rutas: la ventana de escritorio, una página de otro dominio.
onShare(event) => voidCada compartición guardada, con quién, por quién y si es la primera: para avisar a la persona.
beforeUpload(upload, drive) => boolean | voidSe pregunta antes de dar direcciones a una subida, con su nombre, tipo, tamaño y carpeta: lanza un Refused, o devuelve false, para rechazarla.
inspect(upload, drive) => boolean | voidSe pregunta cuando llegaron los bytes, antes de listar el archivo, con un read de ellos: checkType(), clamav() o el tuyo. Un rechazo quita los bytes.
livefalse | { poll }Los cambios dichos en /events en el momento; los de otro proceso sobre el mismo store, en poll ms (2000). false para ninguno.
deriveDeriveLo que el servidor hace de un archivo guardado, para lo que la página no hizo: imágenes, un placeholder, su texto (de un PDF, un Word, un libro de Excel; de una imagen con ocr()). deriveAll() de @rebofiles/server/derive.
onChange({ activity, entry }) => voidCada cosa hecha al drive, como la dice su actividad: para webhooks, una auditoría, otro índice, cobrar por espacio.
onComment({ comment, entry, mentions, by }) => voidCada comentario, con a quién nombra con @: para avisarles.
onReceived({ entry, from, item, request, got }) => voidCada archivo que llegó por una solicitud, con quién lo envió, para qué documento y lo que llegó hasta ahora: para avisar al dueño.
onReview({ entry, status, reason, from, by }) => voidCada archivo aceptado o devuelto: para avisar a quien lo envió.
reminders{ send(reminder) }A quien se le envió una solicitud, recordado cada remind días de lo que falta, y al momento: mailReminders({ mail: resend(…), url }), o el tuyo.
checkfalse | ({ entry, item, text }) => …Lo escrito en lo que llegó, contra las words y find de su documento: checkWritten salvo el tuyo; false para ninguno.
expiringfalse | { field, days, onExpiring }Al dueño de un archivo cuyo campo expires llega en days (15) se le avisa en la campana, y onExpiring; false para nada.
onRead({ action, user, link, entries, path }) => voidCada cosa abierta, vista o bajada: una carpeta listada, un archivo visto o descargado, un .zip; por alguien o por un enlace. Para una auditoría.
people{ search(query, user), names?(ids, user) }Quién es quién, de tu directorio: las personas y los grupos que coinciden con lo escrito al compartir, y sus nombres, que se muestran en lugar de los ids.
loggerLoggerDónde se escribe lo que salió mal y no se respondió: pino(), console si no se da.
onRequest(done) => voidTras cada petición, su ruta, estado, tiempo y quién: para métricas, como openTelemetry(meter).
limitsLimits | falseCuántas subidas, archivos .zip, búsquedas de texto, contraseñas erróneas de un enlace y peticiones puede hacer cada uno; un 429 pasado eso.
limiterLimiterDónde se guardan las cuentas de limits: en el proceso si no se da; Redis para más de uno.
clientIp(request) => stringLa dirección de quien pregunta, para contar también por ella las contraseñas erróneas de un enlace.
now() => DateEl reloj, para tests.
newId() => stringLos ids de las entradas nuevas; UUID aleatorios si no se da.
Velocidad

Guardado en memoria

El drive se lee una vez y se guarda, y solo se vuelve a leer cuando el almacén dice que cambió, por este proceso o por otro: un listado de 20 000 entradas pasó de 36 ms a menos de 1. Suficiente para un equipo y mucho más; no para millones de entradas.

API

Todas las rutas

Rutas HTTP las enumera, tal como las guarda el código.