Ir al contenido

Referencia de configuración

EmDash se configura mediante dos archivos: astro.config.mjs para la integración y src/live.config.ts para las colecciones de contenido.

Configura EmDash como una integración de Astro:

astro.config.mjs
import { defineConfig } from "astro/config";
import emdash, { local, r2, s3 } from "emdash/astro";
import { sqlite, libsql, d1 } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
plugins: [],
}),
],
});

Obligatorio. Configuración del adaptador de base de datos.

// SQLite (Node.js)
database: sqlite({ url: "file:./data.db" });
// PostgreSQL
database: postgres({ connectionString: process.env.DATABASE_URL });
// libSQL
database: libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
});
// Cloudflare D1 (importar desde @emdash-cms/cloudflare)
database: d1({ binding: "DB" });

Consulta Opciones de Base de Datos para más detalles.

Obligatorio. Configuración del adaptador de almacenamiento de medios.

// Sistema de archivos local (desarrollo)
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
// Enlace R2 (Cloudflare Workers)
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev", // opcional
});
// Compatible con S3 (cualquier plataforma)
storage: s3({
endpoint: "https://s3.amazonaws.com",
bucket: "my-bucket",
accessKeyId: process.env.S3_ACCESS_KEY_ID,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
region: "us-east-1", // opcional, valor por defecto: "auto"
publicUrl: "https://cdn.example.com", // opcional
});

Consulta Opciones de Almacenamiento para más detalles.

Opcional. Array de plugins de EmDash.

import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];

Opcional. Configuración de autenticación.

auth: {
// Configuración de auto-registro
selfSignup: {
domains: ["example.com"],
defaultRole: 20, // Contributor
},
// Proveedores OAuth
oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
},
// Configuración de la sesión
session: {
maxAge: 30 * 24 * 60 * 60, // 30 days
sliding: true, // Reset expiry on activity
},
// O usa Cloudflare Access (modo exclusivo)
cloudflareAccess: {
teamDomain: "myteam.cloudflareaccess.com",
audience: "your-app-audience-tag",
autoProvision: true,
defaultRole: 30,
syncRoles: false,
roleMapping: {
"Admins": 50,
"Editors": 40,
},
},
}

Permite a los usuarios registrarse por sí mismos si su dominio de correo electrónico está permitido.

OpciónTipoPor defectoDescripción
domainsstring[][]Dominios de correo permitidos
defaultRolenumber20Rol para auto-registros
selfSignup: {
domains: ["example.com", "acme.org"],
defaultRole: 20, // Contributor
}

Configura proveedores de inicio de sesión OAuth.

oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
}

Configuración de sesión.

OpciónTipoPor defectoDescripción
maxAgenumber2592000 (30d)Duración de la sesión en segundos
slidingbooleantrueReiniciar expiración con actividad

Usa Cloudflare Access como proveedor de autenticación en lugar de passkeys.

OpciónTipoPor defectoDescripción
teamDomainstringrequeridoTu dominio de equipo de Access
audiencestringrequeridoEtiqueta de Audiencia de Aplicación (AUD)
autoProvisionbooleantrueCrear usuarios en el primer inicio de sesión
defaultRolenumber30Rol por defecto para nuevos usuarios
syncRolesbooleanfalseActualizar rol en cada inicio de sesión
roleMappingobject—Mapear grupos del IdP a roles

Opcional. Proporciona un origen completo orientado al navegador (esquema + host + puerto opcional, sin ruta) para que el rpId y origin de WebAuthn coincidan con lo que el navegador del usuario envía en clientData.origin.

Por defecto, las passkeys siguen Astro.url / request.url. Detrás de un proxy inverso que termina TLS, la aplicación a menudo aún ve http:// en el salto interno mientras la pestaña está en https://, o el host reconstruido no coincide con el nombre público — lo que rompe la verificación de passkeys. Establece passkeyPublicOrigin al origen que los usuarios escriben en la barra de direcciones (por ejemplo https://cms.example.com o https://cms.example.com:8443).

La integración valida este valor al cargar: debe ser una URL válida con protocolo http: o https: y se normaliza a origin.

emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
passkeyPublicOrigin: "https://cms.example.com",
});

Astro solo refleja X-Forwarded-* cuando el host público está permitido. Configura security.allowedDomains para el nombre de host (y esquemas) que tus usuarios visitan. En astro dev, añade vite.server.allowedHosts coincidentes para que Vite acepte el encabezado Host del proxy.

Prefiere arreglar primero allowedDomains (y los encabezados reenviados); usa passkeyPublicOrigin cuando la URL reconstruida aún diverge del origen del navegador (típico cuando TLS se termina al frente y la solicitud ascendente permanece http://).

Con TLS al frente, vincular el servidor de desarrollo al loopback (astro dev --host 127.0.0.1) a menudo es suficiente: el proxy se conecta localmente mientras passkeyPublicOrigin coincide con el origen HTTPS público.

astro.config.mjs (fragmento)
import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";
export default defineConfig({
security: {
allowedDomains: [
{ hostname: "cms.example.com", protocol: "https" },
{ hostname: "cms.example.com", protocol: "http" },
],
},
vite: {
server: {
allowedHosts: ["cms.example.com"],
},
},
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
passkeyPublicOrigin: "https://cms.example.com",
}),
],
});

Importa desde emdash/db:

import { sqlite, libsql, postgres, d1 } from "emdash/db";

Base de datos SQLite usando better-sqlite3.

OpciónTipoDescripción
urlstringRuta del archivo con prefijo file:
sqlite({ url: "file:./data.db" });

Base de datos libSQL.

OpciónTipoDescripción
urlstringURL de la base de datos
authTokenstringToken de autenticación (opcional para archivos locales)
libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
});

Base de datos PostgreSQL con agrupación de conexiones.

OpciónTipoDescripción
connectionStringstringURL de conexión PostgreSQL
hoststringHost de la base de datos
portnumberPuerto de la base de datos
databasestringNombre de la base de datos
userstringUsuario de la base de datos
passwordstringContraseña de la base de datos
sslbooleanHabilitar SSL
pool.minnumberTamaño mínimo del pool (por defecto: 0)
pool.maxnumberTamaño máximo del pool (por defecto: 10)
postgres({ connectionString: process.env.DATABASE_URL });

Base de datos Cloudflare D1. Importa desde @emdash-cms/cloudflare.

OpciónTipoValor por defectoDescripción
bindingstring—Nombre del binding D1 desde wrangler.jsonc
sessionstring"disabled"Modo de réplica de lectura: "disabled", "auto", o "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"Nombre de la cookie para marcadores de sesión
// Basic
d1({ binding: "DB" });
// Con réplicas de lectura
d1({ binding: "DB", session: "auto" });

Cuando session es "auto" o "primary-first", EmDash utiliza la API de Sesiones de D1 para dirigir consultas de lectura a réplicas cercanas. Los usuarios autenticados obtienen consistencia de lectura-tus-escrituras basada en marcadores. Consulta Opciones de Base de Datos — Réplicas de Lectura para más detalles.

Importa desde emdash/astro:

import emdash, { local, r2, s3 } from "emdash/astro";

Almacenamiento en sistema de archivos local.

OpciónTipoDescripción
directorystringRuta del directorio
baseUrlstringURL base para servir archivos
local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});

Binding de Cloudflare R2.

OpciónTipoDescripción
bindingstringNombre del binding R2
publicUrlstringURL pública opcional
r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev",
});

Almacenamiento compatible con S3.

OpciónTipoDescripción
endpointstringURL del endpoint S3
bucketstringNombre del bucket
accessKeyIdstringClave de acceso
secretAccessKeystringClave secreta
regionstringRegión (por defecto: "auto")
publicUrlstringURL de CDN opcional
s3({
endpoint: "https://xxx.r2.cloudflarestorage.com",
bucket: "media",
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
publicUrl: "https://cdn.example.com",
});

Configura el cargador de EmDash en src/live.config.ts:

src/live.config.ts
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({
loader: emdashLoader(),
}),
};

La función emdashLoader() acepta configuración opcional:

emdashLoader({
// De momento no hay opciones; se reserva para usos futuros
});

EmDash respeta estas variables de entorno:

VariableDescripción
EMDASH_DATABASE_URLAnula la URL de la base de datos
EMDASH_AUTH_SECRETSecreto para autenticación con claves de acceso
EMDASH_PREVIEW_SECRETSecreto para generación de tokens de vista previa
EMDASH_URLURL remota de EmDash para sincronización de esquema

Genera un secreto de autenticación con:

Ventana de terminal
npx emdash auth secret

Configuración opcional en package.json:

package.json
{
"emdash": {
"label": "Plantilla de blog",
"description": "Una plantilla de blog limpia y minimalista",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev",
"preview": "https://emdash-blog.pages.dev"
}
}
OpciónDescripción
labelNombre de la plantilla para mostrar
descriptionDescripción de la plantilla
seedRuta al archivo JSON de semilla
urlURL remota para sincronización de esquema
previewURL del sitio de demostración para vista previa de plantilla

EmDash genera tipos en .emdash/types.ts. Añade a tu tsconfig.json:

tsconfig.json
{
"compilerOptions": {
"paths": {
"@emdash-cms/types": ["./.emdash/types.ts"]
}
}
}

Genera tipos con:

Ventana de terminal
npx emdash types