Modo snapshot
El modo snapshot permite que el cliente de la API de Content Island sirva todos sus métodos de lectura desde un fichero local en lugar de hacer una petición a la API en cada lectura. El contenido completo de un proyecto se exporta una vez como un único documento JSON — el snapshot (se transfiere comprimido con gzip desde el endpoint de exportación y se guarda como JSON plano en disco) — y el cliente lo lee comportándose exactamente igual que la API en vivo: los mismos métodos, las mismas estructuras y los mismos resultados.
El modo snapshot está pensado para aplicaciones que necesitan leer contenido con frecuencia sin llamar a la API en cada operación.
Exporta el proyecto una vez, guarda el snapshot en local y resuelve todas las lecturas directamente desde ese snapshot. Así reduces la latencia, eliminas tráfico innecesario a la API y tu aplicación aguanta mejor los problemas de red, los límites de peticiones o las caídas temporales de la API.
La generación de sitios estáticos encaja de forma natural, pero el mismo enfoque sirve también para SSR, ISR, server functions, trabajos en segundo plano y otras cargas en servidor.
Elegir un modo
El cliente opera en uno de estos dos modos:
| Modo | Las lecturas vienen de | Por defecto |
|---|---|---|
'api' | La API REST en vivo de Content Island. | sí |
'snapshot' | Un fichero snapshot local (snapshotPath). | — |
Defines el modo al crear el cliente:
import { createClient } from '@content-island/api-client';
const client = createClient({ accessToken: 'YOUR_ACCESS_TOKEN', mode: 'snapshot',});En modo 'snapshot' las lecturas se sirven desde el fichero snapshot local sin ninguna petición a la API y devolviendo exactamente los mismos resultados que la API en vivo. Cuando se omite mode, el cliente usa 'api' por defecto y se comporta exactamente como siempre.
El fichero snapshot
En modo snapshot el cliente lee de un fichero snapshot en disco. Lo indicas con la opción opcional snapshotPath:
const client = createClient({ accessToken: 'YOUR_ACCESS_TOKEN', mode: 'snapshot', snapshotPath: './content-island-snapshot.json',});snapshotPath es opcional y por defecto vale './content-island-snapshot.json'. No es obligatorio: omitirlo simplemente usa la ruta por defecto. Solo se lanza un error cuando el fichero en esa ruta está ausente, no se puede leer o no es válido — nunca por el mero hecho de no haber pasado la opción.
Dónde se fija el modo
El modo se fija en dos sitios:
-
A nivel de cliente — la opción
modeencreateClientfija el valor por defecto para todas las lecturas. -
Por lectura — los cinco métodos de lectura aceptan un
modedentro del objeto de consulta, que afecta solo a esa llamada:getContentListgetContentgetRawContentListgetRawContentgetContentListSize
// El cliente lee de la API por defecto;// esta única lectura se sirve desde el snapshot:const client = createClient({ accessToken: 'YOUR_ACCESS_TOKEN', snapshotPath: './content-island-snapshot.json',});
const posts = await client.getContentList({ contentType: 'post', mode: 'snapshot', // solo esta lectura});getProject sí funciona en modo snapshot: se sirve desde el objeto project del snapshot (idiomas incluidos). Simplemente no recibe objeto de consulta, así que no admite un mode por lectura: siempre sigue el modo a nivel de cliente. Para inspeccionar el snapshot en disco sin cargar el proyecto, usa getSnapshotInfo.
onRelatedContentMeta
onRelatedContentMeta es un callback opcional por consulta que informa de cómo fue la resolución del contenido relacionado. Se ejecuta en los mismos cinco métodos de lectura y tiene la firma:
onRelatedContentMeta: ({ resolvedDepth, partial }) => void;Se invoca exactamente una vez por llamada:
resolvedDepth— hasta qué profundidad llegó realmente la resolución del contenido relacionado.partial—truecuando un límite de profundidad o de presupuesto de resolución dejó parte del grafo de contenido relacionado sin resolver.
El callback funciona en ambos modos y, para los mismos datos y la misma consulta, informa de valores idénticos:
- En modo api, los valores provienen de las cabeceras de respuesta
X-Related-Content-Resolved-DepthyX-Related-Content-Partial(la ausencia de la cabecerapartialse interpreta comofalse). - En modo snapshot, los valores provienen de la resolución en anchura local sobre el snapshot.
const list = await client.getContentList({ contentType: 'post', includeRelatedContent: 'all', onRelatedContentMeta: ({ resolvedDepth, partial }) => { console.log({ resolvedDepth, partial }); },});Cuando se omite onRelatedContentMeta, el comportamiento y las estructuras devueltas no cambian. Como mode, es una opción exclusiva del cliente y nunca se serializa en la cadena de consulta.
Las escrituras no están disponibles en modo snapshot
Un cliente en modo snapshot sirve solo lecturas. Un snapshot es una copia congelada y de solo lectura de tu contenido, así que no hay nada en lo que escribir. Todos los métodos de escritura y de gestión del esquema rechazan con un ApiClientError cuyo código es SNAPSHOT_MODE, y no realizan ninguna petición a la API — el rechazo ocurre localmente, antes de que se enviara petición alguna:
createContentpublishContentupdateContentFieldValueuploadMediacreateModelupdateModeldeleteModelcreateEnumupdateEnumdeleteEnum
import { createClient, ApiClientError } from '@content-island/api-client';
const client = createClient({ accessToken: 'YOUR_ACCESS_TOKEN', mode: 'snapshot',});
try { await client.createContent(/* … */);} catch (error) { if (error instanceof ApiClientError && error.code === 'SNAPSHOT_MODE') { // Las escrituras se rechazan en modo snapshot — no se envió ninguna petición. }}Si necesitas leer de un snapshot y además escribir, crea un segundo cliente independiente en modo 'api' para las escrituras, autenticado con un Write Token:
import { createClient } from '@content-island/api-client';
// Lector: sirve las lecturas desde el snapshot local.const reader = createClient({ accessToken: 'YOUR_READ_TOKEN', mode: 'snapshot',});
// Escritor: un cliente independiente en modo api para las escrituras.const writer = createClient({ accessToken: 'YOUR_WRITE_TOKEN', // mode usa 'api' por defecto});
const posts = await reader.getContentList({ contentType: 'post' });await writer.createContent(/* … */);Exportar un snapshot desde la CLI
Genera un snapshot con el comando content-island export. Exporta el contenido de tu proyecto y lo escribe en disco:
npx content-island export \ --access-token <your-read-token> \ --snapshot-path ./content-island-snapshot.json--snapshot-path es opcional; si lo omites, el snapshot se escribe en ./content-island-snapshot.json, relativo al directorio de trabajo actual.
El comando refleja la API programática exportSnapshot() uno a uno (la CLI está construida sobre ella). Sus flags son:
| Flag | Descripción | Por defecto |
|---|---|---|
--access-token | Obligatorio. El token de acceso para la exportación. Si no, usa la variable de abajo. | env CONTENT_ISLAND_ACCESS_TOKEN |
--snapshot-path | Dónde se escribe el fichero snapshot. | ./content-island-snapshot.json |
--domain | Sobrescribe el dominio de Content Island (para instancias self-hosted). | — |
--secure-protocol | Usa HTTPS explícitamente (es el valor por defecto). | HTTPS |
--no-secure-protocol | Usa HTTP en lugar de HTTPS (instancias locales / self-hosted). | — |
--api-version | Sobrescribe la versión de la API usada para la exportación. | — |
La exportación usa HTTPS por defecto. Pasa --no-secure-protocol solo para una instancia local o self-hosted servida sobre HTTP plano:
npx content-island export \ --access-token <your-read-token> \ --domain localhost:3000 \ --no-secure-protocolSi tiene éxito, el comando imprime un resumen — la ruta de salida, el tamaño del fichero, la marca de tiempo exportedAt y la vista — y termina con código 0.
Si falta el token, la petición falla, o el snapshot descargado no pasa la validación, el comando escribe el error en stderr (la salida de error estándar) y termina con un código de salida distinto de cero. Como escribe a través de un fichero temporal que se renombra a su ubicación final solo tras una descarga completa y validada, una ejecución fallida no deja ningún fichero parcial o inválido en --snapshot-path: o bien obtienes un snapshot completo, o se deja intacto el fichero anterior.
Un patrón habitual
Un montaje frecuente —depende del equipo y del proyecto— usa modo api en el desarrollo local y modo snapshot en las builds de producción:
- Desarrollo local (
mode: 'api') — contenido siempre fresco, sin un paso de exportación que recordar. - Build de producción (
mode: 'snapshot') — rápido, reproducible y sin peticiones a la API por cada lectura.
Controla la elección con una variable de entorno para que el mismo código funcione en ambos casos:
import { createClient } from '@content-island/api-client';
const client = createClient({ accessToken: process.env.CONTENT_ISLAND_ACCESS_TOKEN, mode: process.env.NODE_ENV === 'production' ? 'snapshot' : 'api',});En producción, genera el snapshot primero (un paso de exportación) y luego ejecuta tu build para que lea del fichero recién exportado.
GitHub Action
Este workflow exporta un snapshot en tiempo de build y luego construye tu sitio en modo snapshot:
name: Build
on: push: branches: [main]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6
- uses: actions/setup-node@v6 with: node-version: 24
- run: npm ci
- name: Export content snapshot env: CONTENT_ISLAND_ACCESS_TOKEN: ${{ secrets.CONTENT_ISLAND_ACCESS_TOKEN }} run: npx content-island export
- name: Build (snapshot mode) env: NODE_ENV: production run: npm run build