Référence de configuration

Sur cette page

EmDash est configuré via deux fichiers : astro.config.mjs pour l’intégration et src/live.config.ts pour les collections de contenu.

Intégration Astro

Configurez EmDash en tant qu’intégration 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: [],
		}),
	],
});

Options d’intégration

database

Obligatoire. Configuration de l’adaptateur de base de données.

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

Voir Options de base de données pour plus de détails.

storage

Obligatoire. Configuration de l’adaptateur de stockage multimédia.

// Système de fichiers local (développement)
storage: local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

// Binding 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
});

Voir Options de stockage pour plus de détails.

plugins

Optionnel. Tableau de plugins EmDash.

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

plugins: [seoPlugin()];

auth

Optionnel. Configuration de l’authentification.

auth: {
  // Configuration de l'inscription libre
  selfSignup: {
    domains: ["example.com"],
    defaultRole: 20, // Contributor
  },
  
  // Fournisseurs 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,
    },
  },
  
  // Configuration des sessions
  session: {
    maxAge: 30 * 24 * 60 * 60, // 30 jours
    sliding: true, // Réinitialiser l'expiration à chaque activité
  },
  
  // OU utiliser Cloudflare Access (mode exclusif)
  cloudflareAccess: {
    teamDomain: "myteam.cloudflareaccess.com",
    audience: "your-app-audience-tag",
    autoProvision: true,
    defaultRole: 30,
    syncRoles: false,
    roleMapping: {
      "Admins": 50,
      "Editors": 40,
    },
  },
}

auth.selfSignup

Autorisez les utilisateurs à s’inscrire si leur domaine e-mail est autorisé.

OptionTypeDéfautDescription
domainsstring[][]Domaines e-mail autorisés
defaultRolenumber20Rôle pour les auto-inscriptions
selfSignup: {
  domains: ["example.com", "acme.org"],
  defaultRole: 20, // Contributor
}

auth.oauth

Configurez les fournisseurs de connexion 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

Configuration des sessions.

OptionTypeDéfautDescription
maxAgenumber2592000 (30j)Durée de vie de la session en secondes
slidingbooleantrueRéinitialiser l’expiration à chaque activité

auth.cloudflareAccess

Utilisez Cloudflare Access comme fournisseur d’authentification au lieu des passkeys.

OptionTypeDéfautDescription
teamDomainstringrequisDomaine de votre équipe Access
audiencestringrequisApplication Audience (AUD) tag
autoProvisionbooleantrueCréer les utilisateurs à la première connexion
defaultRolenumber30Rôle par défaut pour les nouveaux utilisateurs
syncRolesbooleanfalseMettre à jour le rôle à chaque connexion
roleMappingobjectMapper les groupes IdP aux rôles

siteUrl

Optionnel. L’origine publique accessible au navigateur pour le site (schéma + hôte + port optionnel, pas de chemin).

Derrière un proxy inverse terminant TLS, Astro.url renvoie l’adresse interne (http://localhost:4321) au lieu de l’adresse publique (https://cms.example.com). Cela casse les passkeys, la correspondance d’origine CSRF, les redirections OAuth, les redirections de connexion, la découverte MCP, les exports de snapshots, le sitemap, robots.txt et les données structurées JSON-LD. Définir siteUrl corrige tout cela en une seule fois.

L’intégration valide cette valeur au chargement : elle doit être une URL valide avec le protocole http: ou https: et est normalisée en origin (le chemin est supprimé).

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

Lorsque siteUrl n’est pas défini dans la configuration, EmDash vérifie les variables d’environnement dans l’ordre : EMDASH_SITE_URL, puis SITE_URL. Cela est utile pour les déploiements en conteneur où l’URL publique est définie à l’exécution.

Configuration du proxy inverse

Astro ne reflète X-Forwarded-* que lorsque l’hôte public est autorisé. Configurez security.allowedDomains pour le nom d’hôte (et les schémas) utilisés par vos utilisateurs. Dans astro dev, ajoutez vite.server.allowedHosts correspondant pour que Vite accepte l’en-tête Host du proxy.

Préférez corriger allowedDomains (et les en-têtes transférés) en premier ; utilisez siteUrl lorsque l’URL reconstruite diverge toujours de l’origine du navigateur (typique lorsque TLS se termine devant et que la requête en amont reste en http://).

Avec TLS en frontal, lier le serveur de développement au loopback (astro dev --host 127.0.0.1) est souvent suffisant : le proxy se connecte localement tandis que siteUrl correspond à l’origine HTTPS publique.

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

Adaptateurs de base de données

Import depuis emdash/db :

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

sqlite(config)

Base de données SQLite utilisant better-sqlite3.

OptionTypeDescription
urlstringChemin de fichier avec préfixe file:
sqlite({ url: "file:./data.db" });

libsql(config)

Base de données libSQL.

OptionTypeDescription
urlstringURL de la base de données
authTokenstringJeton d’authentification (optionnel en local)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

Base de données PostgreSQL avec pool de connexions.

OptionTypeDescription
connectionStringstringURL de connexion PostgreSQL
hoststringHôte de la base de données
portnumberPort de la base de données
databasestringNom de la base de données
userstringUtilisateur de la base de données
passwordstringMot de passe de la base de données
sslbooleanActiver SSL
pool.minnumberTaille minimale du pool (défaut : 0)
pool.maxnumberTaille maximale du pool (défaut : 10)
postgres({ connectionString: process.env.DATABASE_URL });

d1(config)

Base de données Cloudflare D1. Import depuis @emdash-cms/cloudflare.

OptionTypeDéfautDescription
bindingstringNom du binding D1 depuis wrangler.jsonc
sessionstring"disabled"Mode de réplication en lecture : "disabled", "auto" ou "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"Nom du cookie pour les signets de session
// Basique
d1({ binding: "DB" });

// Avec répliques de lecture
d1({ binding: "DB", session: "auto" });

Lorsque session est "auto" ou "primary-first", EmDash utilise l’API D1 Sessions pour acheminer les requêtes de lecture vers les répliques à proximité. Les utilisateurs authentifiés bénéficient d’une cohérence lecture-écriture basée sur les signets. Voir Options de base de données — Répliques de lecture pour plus de détails.

Adaptateurs de stockage

Import depuis emdash/astro :

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

local(config)

Stockage sur le système de fichiers local.

OptionTypeDescription
directorystringChemin du répertoire
baseUrlstringURL de base pour servir les fichiers
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Binding Cloudflare R2.

OptionTypeDescription
bindingstringNom du binding R2
publicUrlstringURL publique optionnelle
r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

s3(config?)

Stockage compatible S3. Tous les champs de configuration sont optionnels : tout champ omis dans s3({...}) est résolu depuis la variable d’environnement S3_* correspondante au démarrage du processus Node. Les valeurs explicites ont toujours la priorité.

Prérequis : installez @aws-sdk/client-s3 et @aws-sdk/s3-request-presigner dans votre projet. Le noyau d’EmDash ne fournit pas le SDK AWS. Voir Options de stockage → Stockage compatible S3 pour plus de détails.

OptionTypeDescription
endpointstringURL du point de terminaison S3 (S3_ENDPOINT)
bucketstringNom du bucket (S3_BUCKET)
accessKeyIdstringClé d’accès (S3_ACCESS_KEY_ID)
secretAccessKeystringClé secrète (S3_SECRET_ACCESS_KEY)
regionstringRégion, défaut "auto" (S3_REGION)
publicUrlstringURL CDN optionnelle (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",
})

La résolution des variables d’environnement à l’exécution est une fonctionnalité Node uniquement. Sur Cloudflare Workers, les secrets et variables sont exposés via le paramètre env du gestionnaire fetch, et non via process.env, donc les variables d’environnement S3_* ne sont pas lues. Les déploiements Workers doivent utiliser l’adaptateur r2(config) ou passer des valeurs explicites à s3({...}). Voir Options de stockage pour plus de détails.

Live Collections

Configurez le chargeur EmDash dans src/live.config.ts :

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

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

Options du chargeur

La fonction emdashLoader() accepte une configuration optionnelle :

emdashLoader({
	// Aucune option actuellement - réservé pour une utilisation future
});

Variables d’environnement

EmDash respecte ces variables d’environnement :

VariableDescription
EMDASH_SITE_URLOrigine publique côté navigateur (se rabat sur SITE_URL)
EMDASH_DATABASE_URLRemplacer l’URL de la base de données
EMDASH_AUTH_SECRETSecret pour l’authentification par passkey
EMDASH_PREVIEW_SECRETSecret pour la génération de jetons d’aperçu
EMDASH_URLURL EmDash distante pour la synchronisation du schéma

Générez un secret d’authentification avec :

npx emdash auth secret

Configuration package.json

Configuration optionnelle dans 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"
	}
}
OptionDescription
labelNom du modèle à afficher
descriptionDescription du modèle
seedChemin vers le fichier JSON seed
urlURL distante pour la synchronisation du schéma
previewURL du site de démo pour l’aperçu du modèle

Configuration TypeScript

EmDash génère les types dans .emdash/types.ts. Ajoutez à votre tsconfig.json :

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

Générez les types avec :

npx emdash types