Zum Inhalt springen

Konfigurationsreferenz

EmDash wird über zwei Dateien konfiguriert: astro.config.mjs für die Integration und src/live.config.ts für Live-Content-Collections.

Konfigurieren Sie EmDash als Astro-Integration:

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

Erforderlich. Konfiguration des Datenbank-Adapters.

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

Details finden Sie unter Datenbankoptionen.

Erforderlich. Konfiguration des Media-Speicher-Adapters.

// Lokales Dateisystem (Entwicklung)
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
// R2-Binding (Cloudflare Workers)
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev", // optional
});
// S3-kompatibel (jede Plattform)
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, Standard: "auto"
publicUrl: "https://cdn.example.com", // optional
});

Details finden Sie unter Speicheroptionen.

Optional. Array von EmDash-Plugins.

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

Optional. Authentifizierungskonfiguration.

auth: {
// Konfiguration für Selbstregistrierung
selfSignup: {
domains: ["example.com"],
defaultRole: 20, // Contributor
},
// OAuth-Anbieter
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,
},
},
// Sitzungs-Konfiguration
session: {
maxAge: 30 * 24 * 60 * 60, // 30 days
sliding: true, // Reset expiry on activity
},
// Oder Cloudflare Access verwenden (exklusiver Modus)
cloudflareAccess: {
teamDomain: "myteam.cloudflareaccess.com",
audience: "your-app-audience-tag",
autoProvision: true,
defaultRole: 30,
syncRoles: false,
roleMapping: {
"Admins": 50,
"Editors": 40,
},
},
}

Erlaubt Benutzern die Selbstregistrierung, wenn ihre E-Mail-Domain erlaubt ist.

OptionTypStandardBeschreibung
domainsstring[][]Erlaubte E-Mail-Domains
defaultRolenumber20Rolle für Selbstregistrierungen
selfSignup: {
domains: ["example.com", "acme.org"],
defaultRole: 20, // Contributor
}

Konfiguriert OAuth-Login-Provider.

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,
},
}

Sitzungskonfiguration.

OptionTypStandardBeschreibung
maxAgenumber2592000 (30d)Sitzungslebensdauer in Sekunden
slidingbooleantrueAblauf bei Aktivität zurücksetzen

Verwendet Cloudflare Access als Authentifizierungsprovider anstelle von Passkeys.

OptionTypStandardBeschreibung
teamDomainstringerforderlichIhre Access-Team-Domain
audiencestringerforderlichApplication Audience (AUD) Tag
autoProvisionbooleantrueBenutzer beim ersten Login erstellen
defaultRolenumber30Standardrolle für neue Benutzer
syncRolesbooleanfalseRolle bei jedem Login aktualisieren
roleMappingobject—IdP-Gruppen auf Rollen abbilden

Optional. Geben Sie einen vollständigen browserseitigen Origin (Schema + Host + optionaler Port, kein Pfad) an, damit die WebAuthn-rpId und der origin mit dem übereinstimmen, was der Browser des Benutzers in clientData.origin sendet.

Standardmäßig folgen Passkeys Astro.url / request.url. Hinter einem TLS-terminierenden Reverse-Proxy sieht die App oft immer noch http:// auf dem internen Hop, während der Tab https://, ist oder der rekonstruierte Host nicht mit dem öffentlichen Namen übereinstimmt – was die Passkey-Überprüfung unterbricht. Setzen Sie passkeyPublicOrigin auf den Origin, den Benutzer in die Adressleiste eingeben (z.B. https://cms.example.com oder https://cms.example.com:8443).

Die Integration validiert diesen Wert beim Laden: Es muss eine gültige URL mit http: oder https: Protokoll sein und wird auf origin normalisiert.

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

Astro reflektiert X-Forwarded-* nur, wenn der öffentliche Host erlaubt ist. Konfigurieren Sie security.allowedDomains für den Hostnamen (und Schemata), den Ihre Benutzer erreichen. In astro dev fügen Sie passende vite.server.allowedHosts hinzu, damit Vite den Proxy-Host-Header akzeptiert.

Beheben Sie zuerst allowedDomains (und weitergeleitete Header); verwenden Sie passkeyPublicOrigin, wenn die rekonstruierte URL immer noch vom Browser-Origin abweicht (typisch, wenn TLS davor terminiert wird und die Upstream-Anfrage http:// bleibt).

Mit TLS davor reicht es oft aus, den Dev-Server an Loopback zu binden (astro dev --host 127.0.0.1): Der Proxy verbindet sich lokal, während passkeyPublicOrigin mit dem öffentlichen HTTPS-Origin übereinstimmt.

astro.config.mjs (Ausschnitt)
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",
}),
],
});

Importieren Sie aus emdash/db:

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

SQLite-Datenbank mit better-sqlite3.

OptionTypBeschreibung
urlstringDateipfad mit file:-Präfix
sqlite({ url: "file:./data.db" });

libSQL-Datenbank.

OptionTypBeschreibung
urlstringDatenbank-URL
authTokenstringAuth-Token (optional für lokale Dateien)
libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
});

PostgreSQL-Datenbank mit Connection-Pooling.

OptionTypBeschreibung
connectionStringstringPostgreSQL-Verbindungs-URL
hoststringDatenbank-Host
portnumberDatenbank-Port
databasestringDatenbank-Name
userstringDatenbank-Benutzer
passwordstringDatenbank-Passwort
sslbooleanSSL aktivieren
pool.minnumberMinimale Pool-Größe (Standard: 0)
pool.maxnumberMaximale Pool-Größe (Standard: 10)
postgres({ connectionString: process.env.DATABASE_URL });

Cloudflare D1-Datenbank. Importieren Sie aus @emdash-cms/cloudflare.

OptionTypeDefaultBeschreibung
bindingstring—D1-Bindungsname aus wrangler.jsonc
sessionstring"disabled"Lesereplikationsmodus: "disabled", "auto" oder "primary-first"
bookmarkCookiestring"__ec_d1_bookmark"Cookie-Name für Sitzungs-Lesezeichen
// Basic
d1({ binding: "DB" });
// Mit Lesereplikaten
d1({ binding: "DB", session: "auto" });

Wenn session auf "auto" oder "primary-first" gesetzt ist, verwendet EmDash die D1 Sessions API, um Leseabfragen an nahegelegene Replikate zu leiten. Authentifizierte Benutzer erhalten Lesezeichen-basierte “Read-Your-Writes”-Konsistenz. Weitere Details finden Sie unter Datenbankoptionen — Lesereplikate.

Importieren Sie aus emdash/astro:

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

Lokales Dateisystem-Speicher.

OptionTypeBeschreibung
directorystringVerzeichnispfad
baseUrlstringBasis-URL für das Bereitstellen von Dateien
local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});

Cloudflare R2-Bindung.

OptionTypeBeschreibung
bindingstringR2-Bindungsname
publicUrlstringOptionale öffentliche URL
r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev",
});

S3-kompatibler Speicher.

OptionTypeBeschreibung
endpointstringS3-Endpunkt-URL
bucketstringBucket-Name
accessKeyIdstringZugriffsschlüssel
secretAccessKeystringGeheimer Schlüssel
regionstringRegion (Standard: "auto")
publicUrlstringOptionale CDN-URL
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",
});

Konfigurieren Sie den EmDash-Loader in 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(),
}),
};

Die Funktion emdashLoader() akzeptiert optionale Konfiguration:

emdashLoader({
// Aktuell keine Optionen; für spätere Erweiterungen reserviert
});

EmDash berücksichtigt diese Umgebungsvariablen:

VariableBeschreibung
EMDASH_DATABASE_URLDatenbank-URL überschreiben
EMDASH_AUTH_SECRETGeheimnis für Passkey-Authentifizierung
EMDASH_PREVIEW_SECRETGeheimnis für die Vorschau-Token-Generierung
EMDASH_URLRemote-EmDash-URL für Schema-Synchronisation

Generieren Sie ein Authentifizierungsgeheimnis mit:

Terminal-Fenster
npx emdash auth secret

Optionale Konfiguration in package.json:

package.json
{
"emdash": {
"label": "Blog-Vorlage",
"description": "Eine schlichte, minimalistische Blog-Vorlage",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev",
"preview": "https://emdash-blog.pages.dev"
}
}
OptionBeschreibung
labelVorlagenname zur Anzeige
descriptionVorlagenbeschreibung
seedPfad zur Seed-JSON-Datei
urlRemote-URL für Schema-Synchronisation
previewDemo-Site-URL für Vorlagenvorschau

EmDash generiert Typen in .emdash/types.ts. Fügen Sie dies zu Ihrer tsconfig.json hinzu:

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

Generieren Sie Typen mit:

Terminal-Fenster
npx emdash types