Referência de configuração

Nesta página

O EmDash é configurado através de dois arquivos: astro.config.mjs para integração e src/live.config.ts para coleções de conteúdo.

Integração Astro

Configure o EmDash como uma integração Astro:

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: [],
		}),
	],
});

Opções de integração

database

Obrigatório. Configuração do adaptador de banco de dados.

// 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 de @emdash-cms/cloudflare)
database: d1({ binding: "DB" });

Consulte Opções de banco de dados para obter detalhes.

storage

Obrigatório. Configuração do adaptador de armazenamento de mídia.

// Sistema de arquivos local (desenvolvimento)
storage: local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

// Vinculação R2 (Cloudflare Workers)
storage: r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev", // optional
});

// S3-compatible (any platform) — all fields from S3_* environment variables
storage: s3()

// Or with explicit values
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", // optional, default: "auto"
	publicUrl: "https://cdn.example.com", // optional
});

Consulte Opções de armazenamento para obter detalhes.

plugins

Opcional. Array de plugins EmDash.

import seoPlugin from "@emdash-cms/plugin-seo";

plugins: [seoPlugin()];

auth

Opcional. Configuração de autenticação.

auth: {
  // Configuração de autoinscrição
  selfSignup: {
    domains: ["example.com"],
    defaultRole: 20, // Contributor
  },
  
  // Provedores 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,
    },
  },
  
  // Configuração de sessão
  session: {
    maxAge: 30 * 24 * 60 * 60, // 30 dias
    sliding: true, // Redefinir expiração na atividade
  },
  
  // OU usar 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,
    },
  },
}

auth.selfSignup

Permita que os usuários se registrem automaticamente se o domínio de e-mail for permitido.

OpçãoTipoPadrãoDescrição
domainsstring[][]Domínios de e-mail permitidos
defaultRolenumber20Função para autoinscrições
selfSignup: {
  domains: ["example.com", "acme.org"],
  defaultRole: 20, // Contributor
}

auth.oauth

Configure provedores de login 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,
  },
}

auth.session

Configuração da sessão.

OpçãoTipoPadrãoDescrição
maxAgenumber2592000 (30d)Duração da sessão em segundos
slidingbooleantrueRedefinir expiração na atividade

auth.cloudflareAccess

Use o Cloudflare Access como provedor de autenticação em vez de passkeys.

OpçãoTipoPadrãoDescrição
teamDomainstringobrigatórioO domínio da sua equipe de Access
audiencestringobrigatórioTag de público do aplicativo (AUD)
autoProvisionbooleantrueCriar usuários no primeiro login
defaultRolenumber30Função padrão para novos usuários
syncRolesbooleanfalseAtualizar função em cada login
roleMappingobjectMapear grupos IdP para funções

siteUrl

Opcional. A origem pública voltada para o navegador do site (esquema + host + porta opcional, sem caminho).

Atrás de um proxy reverso com terminação TLS, Astro.url retorna o endereço interno (http://localhost:4321) em vez do público (https://cms.example.com). Isso quebra passkeys, correspondência de origem CSRF, redirecionamentos OAuth, redirecionamentos de login, descoberta MCP, exportações de snapshots, sitemap, robots.txt e dados estruturados JSON-LD. Defina siteUrl para corrigir tudo isso de uma só vez.

A integração valida esse valor no carregamento: ele deve ser uma URL válida com o protocolo http: ou https: e é normalizada para origin (o caminho é removido).

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

Quando siteUrl não está definido na configuração, o EmDash verifica as variáveis de ambiente em ordem: EMDASH_SITE_URL, depois SITE_URL. Isso é útil para implantações em contêiner onde a URL pública é definida em tempo de execução.

Configuração do proxy reverso

O Astro reflete apenas X-Forwarded-* quando o host público é permitido. Configure security.allowedDomains para o nome do host (e esquemas) que seus usuários acessam. Em astro dev, adicione vite.server.allowedHosts correspondente para que o Vite aceite o cabeçalho Host do proxy.

Prefira corrigir allowedDomains (e cabeçalhos encaminhados) primeiro; use siteUrl quando a URL reconstruída ainda divergir da origem do navegador (típico quando o TLS é terminado na frente e a solicitação upstream permanece http://).

Com TLS na frente, vincular o servidor de desenvolvimento ao loopback (astro dev --host 127.0.0.1) geralmente é suficiente: o proxy se conecta localmente enquanto siteUrl corresponde à origem HTTPS pública.

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",
			}),
			siteUrl: "https://cms.example.com",
		}),
	],
});

Adaptadores de banco de dados

Importar de emdash/db:

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

sqlite(config)

Banco de dados SQLite usando better-sqlite3.

OpçãoTipoDescrição
urlstringCaminho do arquivo com prefixo file:
sqlite({ url: "file:./data.db" });

libsql(config)

Banco de dados libSQL.

OpçãoTipoDescrição
urlstringURL do banco de dados
authTokenstringToken de autenticação (opcional para arquivos locais)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

Banco de dados PostgreSQL com pool de conexões.

OpçãoTipoDescrição
connectionStringstringURL de conexão PostgreSQL
hoststringHost do banco de dados
portnumberPorta do banco de dados
databasestringNome do banco de dados
userstringUsuário do banco de dados
passwordstringSenha do banco de dados
sslbooleanHabilitar SSL
pool.minnumberTamanho mínimo do pool (padrão: 0)
pool.maxnumberTamanho máximo do pool (padrão: 10)
postgres({ connectionString: process.env.DATABASE_URL });

d1(config)

Banco de dados Cloudflare D1. Importe de @emdash-cms/cloudflare.

OpçãoTipoPadrãoDescrição
bindingstringNome da vinculação D1 de wrangler.jsonc
sessionstring"disabled"Modo de replicação de leitura: "disabled", "auto" ou "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"Nome do cookie para marcadores de sessão
// Básico
d1({ binding: "DB" });

// Com réplicas de leitura
d1({ binding: "DB", session: "auto" });

Quando session é "auto" ou "primary-first", o EmDash usa a API de sessões D1 para rotear consultas de leitura para réplicas próximas. Os usuários autenticados obtêm consistência de leitura-após-escrita baseada em marcadores. Consulte Opções de banco de dados — Réplicas de leitura para obter detalhes.

Adaptadores de armazenamento

Importar de emdash/astro:

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

local(config)

Armazenamento de sistema de arquivos local.

OpçãoTipoDescrição
directorystringCaminho do diretório
baseUrlstringURL base para servir arquivos
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Vinculação Cloudflare R2.

OpçãoTipoDescrição
bindingstringNome da vinculação R2
publicUrlstringURL público opcional
r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

s3(config?)

Armazenamento compatível com S3. Todos os campos de configuração são opcionais: qualquer campo omitido em s3({...}) é resolvido a partir da variável de ambiente S3_* correspondente quando o processo Node inicia. Valores explícitos sempre têm precedência.

Pré-requisito: instale @aws-sdk/client-s3 e @aws-sdk/s3-request-presigner no seu projeto. O núcleo do EmDash não inclui o AWS SDK. Consulte Opções de armazenamento → Armazenamento compatível com S3 para detalhes.

OpçãoTipoDescrição
endpointstringURL do endpoint S3 (S3_ENDPOINT)
bucketstringNome do bucket (S3_BUCKET)
accessKeyIdstringChave de acesso (S3_ACCESS_KEY_ID)
secretAccessKeystringChave secreta (S3_SECRET_ACCESS_KEY)
regionstringRegião, padrão "auto" (S3_REGION)
publicUrlstringURL CDN opcional (S3_PUBLIC_URL)
// All fields from S3_* environment variables (Node container deployments)
s3()

// Mix: CDN from config, rest from environment
s3({ publicUrl: "https://cdn.example.com" })

// All explicit (unchanged from before)
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",
})

A resolução de variáveis de ambiente em tempo de execução é uma funcionalidade exclusiva do Node. No Cloudflare Workers, segredos e variáveis são expostos através do parâmetro env do manipulador fetch, não através de process.env, então as variáveis de ambiente S3_* não são lidas. Implantações no Workers devem usar o adaptador r2(config) ou passar valores explícitos para s3({...}). Consulte Opções de armazenamento para detalhes.

Coleções ao vivo

Configure o carregador EmDash em src/live.config.ts:

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
	_emdash: defineLiveCollection({
		loader: emdashLoader(),
	}),
};

Opções do carregador

A função emdashLoader() aceita configuração opcional:

emdashLoader({
	// Atualmente sem opções - reservado para uso futuro
});

Variáveis de ambiente

O EmDash respeita estas variáveis de ambiente:

VariávelDescrição
EMDASH_SITE_URLOrigem pública voltada para o navegador (recorre a SITE_URL)
EMDASH_DATABASE_URLSubstituir URL do banco de dados
EMDASH_AUTH_SECRETSegredo para autenticação de passkey
EMDASH_PREVIEW_SECRETSegredo para geração de token de visualização
EMDASH_URLURL EmDash remoto para sincronização de esquema

Gere um segredo de autenticação com:

npx emdash auth secret

Configuração package.json

Configuração opcional em package.json:

{
	"emdash": {
		"label": "My Blog Template",
		"description": "A clean, minimal blog template",
		"seed": ".emdash/seed.json",
		"url": "https://my-site.pages.dev",
		"preview": "https://emdash-blog.pages.dev"
	}
}
OpçãoDescrição
labelNome do modelo para exibição
descriptionDescrição do modelo
seedCaminho para o arquivo JSON seed
urlURL remoto para sincronização de esquema
previewURL do site de demonstração para visualização do modelo

Configuração TypeScript

EmDash gera tipos em .emdash/types.ts. Adicione ao seu tsconfig.json:

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

Gere tipos com:

npx emdash types