Piloto privadoDisponibilidad y límites actuales ↗
Docs/Plataforma·
.mdEN

Hosting de frontend (Sites)

Estado: Disponible en el piloto (sites.zip)

Un Site es el frontend estático de un proyecto. Subes un ZIP precompilado en la consola, lo publicas y Plurabase lo sirve con un archivo de configuración generado que lo conecta con el backend del proyecto. Publicar o revertir un Site nunca cambia la base de datos. En el piloto, el operador habilita Sites para cada proyecto. Los estados se definen en la página de datos.

Publicar una versión

  1. Compila el frontend en archivos estáticos con index.html en la raíz.
  2. Comprime el contenido de la salida del build (no la carpeta que lo contiene).
  3. En la consola, abre Sites (/platform/sites/), elige el proyecto y crea el Site.
  4. Sube el ZIP y elige Publicar. La consola vuelve a leer por HTTP los bytes y la configuración publicados antes de confirmar.
  5. Para volver atrás, elige una versión anterior y pulsa Volver a esta versión.

Conectar el frontend con su backend

Cada versión se sirve con ./__simplybase/config.json, que contiene api_url y publishable_key (la clave anon), además de project_ref, release_id y version (el número de formato del archivo), nunca una clave secreta:

ts
import { createClient } from '@supabase/supabase-js'

export async function connect() {
  const reply = await fetch('./__simplybase/config.json', {
    credentials: 'omit',
    cache: 'no-store',
    redirect: 'error',
  })
  if (!reply.ok) throw new Error('Project connection unavailable')
  const config = await reply.json()
  return createClient(config.api_url, config.publishable_key, {
    auth: { persistSession: false, detectSessionInUrl: false },
    global: {
      fetch: (input, init) => fetch(input, { ...init, credentials: 'omit' }),
    },
  })
}

Llama a connect() una vez al arrancar y conserva el cliente que devuelve. El código va dentro de una función porque el único build comprobado es un bundle IIFE de esbuild, que rechaza el await de nivel superior.

Reglas del ZIP

  • index.html en la raíz y nombres de archivo ASCII. Tipos de archivo admitidos: .html, .css, .js, .mjs, .json, .map, .webmanifest, .txt, .xml, .svg, .png, .jpg, .jpeg, .gif, .webp, .avif, .ico, .woff, .woff2, .ttf, .otf y .wasm.
  • Cada versión se sirve bajo su propia ruta, /__sites/r/<release>/, y las rutas fuera de ella devuelven un error. Por eso las URLs de tus propios archivos en HTML, CSS y JavaScript deben ser relativas (./assets/app.js, ../logo.svg); una URL relativa a la raíz como /assets/app.js falla.
  • La Content Security Policy carga scripts, hojas de estilo y fuentes solo desde archivos de la versión. Están bloqueados los elementos <script> y <style> en línea, los atributos style="…", los manejadores de eventos en línea, eval y new Function, las fuentes data:, la compilación de WebAssembly y las CDNs de terceros. Las imágenes pueden ser archivos o URLs data:. Empaqueta todas las dependencias, incluido @supabase/supabase-js.
  • La página corre en un sandbox sin envío de formularios: un <form> nunca dispara su evento submit, así que inicia las acciones desde el click de un botón y la tecla Enter.
  • El sandbox también bloquea alert, confirm y prompt (confirm devuelve false al instante, así que pide la confirmación con un diálogo dentro de la página), las ventanas emergentes y los enlaces en pestaña nueva (window.open, target="_blank") y las descargas (<a download>).
  • Las peticiones del navegador (fetch, XHR, WebSocket) solo llegan a la versión y a la API del proyecto, nunca a una API de terceros. Están bloqueados los iframes, el audio y el vídeo, los web workers y los elementos <style> que librerías de CSS-in-JS como emotion y styled-components añaden en tiempo de ejecución.
  • Sin renderizado en servidor, paso de build, instalación de paquetes ni cabeceras de respuesta propias.
  • Sin fallback de SPA: un enlace directo a una ruta del cliente devuelve 404. Usa rutas con hash o enlaza a index.html.
  • El código del Site corre en un origen opaco, así que no puede usar cookies, localStorage ni service workers. Los usuarios vuelven a iniciar sesión al recargar.

Builds de frameworks

Sites se ha comprobado con un solo build: el starter de la consola, un bundle de script clásico (esbuild, formato IIFE) y una hoja de estilo, ambos referenciados como ./assets/…, con @supabase/supabase-js empaquetado. Juzga cualquier otra salida con las reglas de arriba:

BuildEn SitesMotivo
Bundle de esbuild referenciado con rutas ./, como el starterComprobadoScript clásico, hoja de estilo externa, URLs relativas
App de una sola página con Vite (React, Vue, Svelte)Sin comprobarNecesita base: './', build.assetsInlineLimit: 0 (para que las fuentes pequeñas sigan siendo archivos) y no usar @vitejs/plugin-legacy (añade scripts en línea). Su salida <script type="module"> todavía no se ha ejecutado en Sites.
Plantillas de Vue compiladas en el navegadorBloqueadoEl compilador en tiempo de ejecución usa new Function; los componentes de un solo archivo precompilados no
Salida estática de AstroNo soportadoURLs /_astro/ relativas a la raíz, hojas de estilo pequeñas en línea por defecto, islas iniciadas con scripts en línea
Next.js con output: 'export'No soportadoScripts de hidratación en línea y URLs /_next/ relativas a la raíz

Revisa el directorio del build antes de subirlo, porque cada Site acepta dos subidas durante toda su vida, incluidas las fallidas. Ningún comando debe imprimir nada (cambia dist por tu directorio de salida; el último omite los bloques de datos JSON como <script type="application/json">, que están permitidos):

sh
grep -rnoE '(src|href)=[^.a-zA-Z0-9]?/' dist --include='*.html'   # URLs relativas a la raíz
grep -rnoE 'url\([^.a-zA-Z0-9]?/' dist --include='*.css'          # URLs relativas a la raíz en CSS
grep -rnoE '<style|style=' dist --include='*.html'                # estilos en línea
grep -rnoE '<script[^>]*>' dist --include='*.html' | grep -v 'src=' | grep -vE 'type="application/(ld\+)?json"'   # scripts en línea

Límites

  • ZIP de 4 MiB, 16 MiB descomprimido.
  • Dos subidas por Site durante toda su vida, incluidas las fallidas, y dos versiones retenidas.
  • Pausar el proyecto también detiene su Site; las versiones siguen siendo válidas al reanudar.

Lo que todavía no está disponible

Estado: En desarrollo (sites.every-project)

Sites para cada proyecto (ADR-0037) está en el repositorio y no se ha ejecutado en un host. Da al Site de cada proyecto su propio origen del navegador en lugar de una ruta bajo el host de la API del proyecto:

  • En la red privada, un Site recibe su propio puerto en el nombre de Tailscale del piloto. Conserva el sandbox y las reglas de arriba, porque un puerto comparte el nombre de host y las cookies de la consola, y ahí solo las organizaciones del propio operador tienen Sites. Cualquier página web que el navegador del operador abra en la red privada puede leer esos Sites, archivo de configuración incluido: no pongas en ellos nada que no publicarías.
  • En un dominio público de Sites, un Site recibe su propio nombre de host (s-<id del site>.<dominio de sites>). Ahí desaparece el sandbox: la página puede usar localStorage, sus propias cookies, formularios, diálogos, ventanas emergentes y descargas. Los scripts se cargan desde el Site y desde elementos <script> en línea cuyo hash se calcula al servirlos; los estilos pueden ir en línea. La versión vigente se sirve en /, la query string se ignora al buscar el archivo (así funcionan las redirecciones de inicio de sesión con ?code=) y una ruta sin extensión vuelve a index.html.
  • Lo que sigue bloqueado en un Site público: los manejadores de eventos en línea (onclick="…") y las URLs javascript:, eval, new Function y la compilación de WebAssembly, los service workers y que otra página lo muestre en un frame.
  • Los scripts en línea reciben hash solo cuando la página se lee sin ambigüedad. Una página de más de 1 MiB, con más de 64 elementos <script> (cuentan también los externos), con un <script> dentro de un comentario HTML, o con <!-- o <script dentro del texto de un script no recibe ningún hash, así que no se ejecuta ninguno de sus scripts en línea. Mueve ese código a archivos .js.
  • El owner define una lista de hasta 16 orígenes https para llamadas a APIs, scripts, estilos, fuentes, medios, frames y destinos de formularios, con los comandos get_site_policy y set_site_policy. La consola todavía no tiene una pantalla para eso.
  • Los límites de subida vienen del plan de la organización, como máximo un ZIP de 4 MiB y 16 MiB descomprimido, con un número diario de subidas y publicaciones en lugar de dos subidas en toda la vida del Site.
  • Los Sites públicos aún no llegan a la API de su proyecto: las APIs de proyecto solo están en la red privada, así que ahí no se entrega el archivo de configuración.
  • Mientras el dominio de Sites no esté en la Public Suffix List, y en navegadores cuya copia de esa lista sea anterior a la inclusión, todos los Sites que viven en él comparten un dominio registrable: cualquier Site puede leer y sobrescribir una cookie que otro Site fije con Domain=. Hasta esa inclusión, solo las organizaciones del propio operador tienen Sites públicos. Usa cookies __Host- o localStorage, nunca una cookie con Domain=.
  • Un Site se sigue sirviendo mientras el backend de su proyecto está en pausa o ocupado con una operación de ciclo de vida. Una clave del proyecto rotada lo detiene hasta que se vuelva a publicar.

El edge público (certificados TLS y DNS) está apagado hasta que el dueño apruebe la exposición pública.

Estado: En desarrollo (sites.git)

Estado: En desarrollo (sites.domains)

Estado: Planificado (sites.previews)

Los despliegues desde GitHub están en desarrollo: conexión mediante una GitHub App, una receta de build revisada, builds en una máquina virtual aislada y publicación automática en cada push. Los dominios propios están en desarrollo: el código para servirlos existe y el edge público está apagado. Las vistas previas están planificadas. Durante el piloto, los Sites se sirven en un nombre de host privado de Tailscale.

Estado: Planificado (access.public-domain)

El diseño público previsto da a los frontends de clientes su propio dominio registrable (s-<site>.plurabase.app), separado de la consola (app.plurabase.com) y de las APIs de proyecto (<project_ref>.api.plurabase.com), para que el JavaScript del cliente nunca pueda leer cookies de la consola. Ninguno de esos dominios sirve tráfico todavía.