Konfigurationsreferenz

Auf dieser Seite

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

Astro-Integration

Konfiguriere EmDash als Astro-Integration in astro.config.mjs:

import { defineConfig } from "astro/config";
import emdash, { local, s3 } from "emdash/astro";
import { sqlite, libsql } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
			plugins: [],
		}),
	],
});

Integrationsoptionen

database

Erforderlich. Datenbank-Adapter-Konfiguration. Wähle einen Adapter:

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

Siehe Datenbankoptionen für Details.

storage

Erforderlich. Medienspeicher-Adapter-Konfiguration. Wähle einen Adapter:

// 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) — alle Felder aus S3_*-Umgebungsvariablen
storage: s3()

// Oder mit expliziten Werten
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
});

Siehe Speicheroptionen für Details.

objectCache

Optional. Cached Content- und Konfigurations-Abfrageergebnisse in einem Key/Value-Store, sodass Lesevorgänge ohne Datenbankabfrage bei jeder Anfrage bedient werden. Deaktiviert wenn weggelassen. Wähle einen Adapter:

// Cloudflare KV (geteilt über alle Isolates)
import { kvCache } from "@emdash-cms/cloudflare";
objectCache: kvCache({ binding: "CACHE" });

// In-Memory (Node.js / Entwicklung)
import { memoryCache } from "emdash/astro";
objectCache: memoryCache();

Siehe Object Cache für Einrichtung und Optionen.

plugins

Optional. Array von EmDash-Plugins. Das folgende Beispiel registriert ein Plugin:

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

plugins: [seoPlugin()];

fonts

Optional. Schriftart-Konfiguration der Admin-Oberfläche.

Standardmäßig lädt EmDash Noto Sans über die Astro Font API. Schriftarten werden zur Build-Zeit von Google heruntergeladen und selbst gehostet, sodass keine Runtime-CDN-Anfragen entstehen. Die Basisschrift deckt lateinische, kyrillische, griechische, Devanagari- und vietnamesische Schriften ab.

Um Unterstützung für zusätzliche Schriftsysteme hinzuzufügen, übergib Schriftnamen. Das folgende Beispiel fügt Arabisch und Japanisch hinzu:

emdash({
  fonts: {
    scripts: ["arabic", "japanese"],
  },
})

Die verfügbaren Schriften sind arabic, armenian, bengali, chinese-simplified, chinese-traditional, chinese-hongkong, devanagari, ethiopic, farsi, georgian, gujarati, gurmukhi, hebrew, japanese, kannada, khmer, korean, lao, malayalam, myanmar, oriya, sinhala, tamil, telugu, thai und tibetan.

Jedes Skript wird der entsprechenden Noto-Sans-Variante auf Google Fonts zugeordnet (z.B. "arabic" lädt Noto Sans Arabic). Alle Font-Faces teilen einen einzigen font-family-Namen und verwenden unicode-range, sodass der Browser nur die Dateien herunterlädt, die er für die Zeichen auf der Seite benötigt.

Auf false setzen, um die Schrifteinspeisung vollständig zu deaktivieren und Systemschriften zu verwenden:

emdash({
	fonts: false,
})

Das Admin-CSS verwendet die CSS-Variable --font-emdash. Diese wird automatisch durch die obige Schriftkonfiguration gesetzt.

auth

Optional. Ein Authentifizierungs-Adapter. EmDash’s eingebautes Login verwendet Passkeys; das Setzen von auth ersetzt sie durch einen externen Anbieter. Der Cloudflare-Access-Adapter access() wird von @emdash-cms/cloudflare bereitgestellt:

import { access } from "@emdash-cms/cloudflare";

emdash({
	auth: access({
		teamDomain: "myteam.cloudflareaccess.com",
		audience: "your-app-audience-tag",
		roleMapping: {
			Admins: 50,
			Editors: 40,
		},
	}),
});

Optionen für access():

OptionTypStandardBeschreibung
teamDomainstringerforderlichDeine Cloudflare Access Team-Domain
audiencestringApplication Audience (AUD) Tag. Auf Workers bevorzuge audienceEnvVar.
audienceEnvVarstring"CF_ACCESS_AUDIENCE"Umgebungsvariable, aus der der Audience-Tag zur Laufzeit gelesen wird
autoProvisionbooleantrueEmDash-Benutzer beim ersten Login erstellen
defaultRolenumber30Rollenstufe für Benutzer, die nicht durch roleMapping zugeordnet werden (siehe Benutzerrollen)
syncRolesbooleanfalseroleMapping bei jedem Login erneut anwenden statt nur bei der Bereitstellung
roleMappingobjectIdP-Gruppennamen auf EmDash-Rollenstufen abbilden; erster Treffer gewinnt

authProviders

Optional. Ein Array von einsteckbaren Login-Providern (auf oberster Ebene, neben auth). Jeder Eintrag ist das Ergebnis des Aufrufs einer Provider-Factory, wie unten gezeigt:

import { github } from "emdash/auth/providers/github";
import { google } from "emdash/auth/providers/google";
import { atproto } from "@emdash-cms/auth-atproto";

emdash({
	authProviders: [github(), google(), atproto()],
});

Eingebaute Provider:

  • github() — liest EMDASH_OAUTH_GITHUB_CLIENT_ID / EMDASH_OAUTH_GITHUB_CLIENT_SECRET (oder unpräfixierte Fallbacks).
  • google() — liest EMDASH_OAUTH_GOOGLE_CLIENT_ID / EMDASH_OAUTH_GOOGLE_CLIENT_SECRET.
  • atproto() — Atmosphere-Konto-Login (Bluesky und das weitergehende AT-Protokoll-Netzwerk). Keine Umgebungsvariablen erforderlich. Akzeptiert { allowedDIDs, allowedHandles, defaultRole }. Siehe den Atmosphere-Login-Guide.

Drittanbieter-Pakete können ihre eigenen Provider mit der gleichen AuthProviderDescriptor-Form registrieren — siehe Login-Provider.

siteUrl

Optional. Der öffentliche, browserseitige Origin für die Seite (Schema + Host + optionaler Port, kein Pfad).

Hinter einem TLS-terminierenden Reverse Proxy gibt Astro.url die interne Adresse (http://localhost:4321) statt der öffentlichen (https://cms.example.com) zurück. Dies bricht Passkeys, CSRF-Origin-Matching, OAuth-Weiterleitungen, Login-Weiterleitungen, MCP-Erkennung, Snapshot-Exporte, Sitemap, robots.txt und JSON-LD strukturierte Daten. Setze siteUrl, um all das auf einmal zu beheben.

Die Integration validiert diesen Wert beim Laden: Er muss eine gültige URL mit http:- oder https:-Protokoll sein und wird auf Origin normalisiert (Pfad wird entfernt).

Das folgende Beispiel setzt den öffentlichen Origin:

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

Wenn siteUrl nicht in der Konfiguration gesetzt ist, prüft EmDash Umgebungsvariablen in dieser Reihenfolge: EMDASH_SITE_URL, dann SITE_URL. Dies ist nützlich für Container-Deployments, bei denen die öffentliche URL zur Laufzeit gesetzt wird.

Auf Cloudflare Workers liest der Env-Var-Fallback process.env, was leer ist, es sei denn, das Kompatibilitäts-Flag nodejs_compat_populate_process_env ist aktiviert. Um dort die Env-Var anstelle der Konfigurationsoption zu verwenden, setze beides:

// wrangler.jsonc
{
	"compatibility_flags": ["nodejs_compat", "nodejs_compat_populate_process_env"],
	"vars": { "EMDASH_SITE_URL": "https://cms.example.com" },
}

Multi-Origin Passkey-Verifizierung

siteUrl definiert einen einzelnen kanonischen Origin. Wenn dasselbe EmDash-Deployment unter mehreren Hostnamen erreichbar ist, die eine gemeinsame registrierbare Eltern-Domain teilen (z.B. https://example.com und https://preview.example.com), lehnt die Passkey-Verifizierung Assertions ab, deren Origin nicht exakt mit siteUrl übereinstimmt — obwohl WebAuthn erlaubt, dass Passkeys über Subdomains unter derselben rpId gültig sind.

Deklariere zusätzlich akzeptierte Origins entweder über allowedOrigins in astro.config.mjs oder die EMDASH_ALLOWED_ORIGINS Umgebungsvariable. Der kanonische siteUrl bleibt die Quelle der rpId; hier aufgeführte Einträge werden bei der Verifizierung akzeptiert. Die beiden Quellen werden zur Laufzeit zusammengeführt, sodass die Konfiguration die stabilen Origins deklarieren kann (versioniert, code-reviewed), während Umgebungsvariablen umgebungsspezifische Extras hinzufügen (z.B. ephemere PR-Vorschauen).

Das folgende Beispiel deklariert einen zusätzlichen Origin in der Konfiguration:

emdash({
	siteUrl: "https://example.com",
	allowedOrigins: ["https://preview.example.com"],
})

Die äquivalenten Werte können auch aus Umgebungsvariablen stammen:

EMDASH_SITE_URL=https://example.com
EMDASH_ALLOWED_ORIGINS=https://preview.example.com,https://staging.example.com
Validierung

EmDash validiert diese, um tote Konfigurationen zu verhindern, die der Browser nie respektieren würde:

  • Jeder Eintrag muss eine parsbare http:- oder https:-URL sein, ohne abschließenden Punkt und ohne leere Labels im Hostnamen.
  • Wenn allowedOrigins nicht leer ist, muss siteUrl gesetzt sein (aus jeder Quelle) und darf kein IP-Literal oder ein Hostname mit abschließendem Punkt sein.
  • Jeder Origin muss derselbe Hostname wie siteUrl oder eine Subdomain davon sein. (WebAuthn erfordert, dass rpId ein registrierbares Suffix jedes Origins ist.)

Wenn die Validierung fehlschlägt, siehst du einen quellenattribuierten Fehler wie EmDash config error in EMDASH_ALLOWED_ORIGINS: "https://other-site.com" is not a subdomain of siteUrl "https://example.com". Allowed origins must be the same hostname as siteUrl or a subdomain of it.

Wo der Fehler auftritt, hängt davon ab, wo die Werte deklariert sind:

  • Beim Astro-Start, wenn sowohl config.allowedOrigins als auch config.siteUrl aus astro.config.mjs stammen — Tippfehler im Code lassen den Build fehlschlagen.
  • Bei der ersten Passkey-Verifizierung, wenn einer der Werte aus EMDASH_ALLOWED_ORIGINS oder EMDASH_SITE_URL stammt — Env-Fehlanpassungen zeigen sich als 500er beim ersten Verifizierungsversuch.

Reverse-Proxy-Einrichtung

Astro reflektiert X-Forwarded-* nur, wenn der öffentliche Host erlaubt ist. Konfiguriere security.allowedDomains für den Hostnamen (und Schemas), den deine Benutzer verwenden. In astro dev füge passendes vite.server.allowedHosts hinzu, damit Vite den Proxy-Host-Header akzeptiert.

Bevorzuge die Korrektur von allowedDomains (und weitergeleiteten Headern) zuerst; verwende siteUrl wenn die rekonstruierte URL weiterhin vom Browser-Origin abweicht (typisch wenn TLS davor terminiert wird und die Upstream-Anfrage http:// bleibt).

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

Wenn dein Proxy einen Client-IP-Header schreibt, setze trustedProxyHeaders, damit EmDash’s Rate-Limits die echte Client-IP verwenden können anstatt jede Anfrage unter einem gemeinsamen “unknown”-Schlüssel einzuordnen.

Die folgende Konfiguration setzt allowedDomains, vite.server.allowedHosts und siteUrl zusammen für ein Reverse-Proxy-Deployment:

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

trustedProxyHeaders

Optional. Header, denen für die Client-IP-Auflösung vertraut wird, wenn hinter einem von dir kontrollierten Reverse Proxy. Wird von Auth-Rate-Limits (Magic-Link, Registrierung, Passkey, OAuth Device Flow) und dem öffentlichen Kommentar-Endpunkt verwendet.

Auf Cloudflare wird das an die Anfrage angehängte cf-Objekt automatisch verwendet — du musst dies normalerweise nicht setzen. Bei selbst gehosteten Deployments hinter nginx, Caddy, Traefik, Fly, Railway oder ähnlichen, setze dies auf den Header, den dein Proxy schreibt, damit Rate-Limits nach echter Client-IP gruppieren können anstatt jede Anfrage als “unknown” zu behandeln.

Das folgende Beispiel vertraut dem x-real-ip-Header, der von nginx, Caddy oder Traefik gesetzt wird:

emdash({
	database: sqlite({ url: "file:./data.db" }),
	trustedProxyHeaders: ["x-real-ip"],
});

Header werden der Reihe nach versucht. Werte, die auf *-forwarded-for passen, werden als kommagetrennte Listen geparst und der erste Eintrag wird verwendet. Das folgende Beispiel bevorzugt Fly.ios Header und fällt auf x-forwarded-for zurück:

emdash({
	trustedProxyHeaders: ["fly-client-ip", "x-forwarded-for"],
});

Wenn nicht in der Konfiguration gesetzt, liest EmDash die Umgebungsvariable EMDASH_TRUSTED_PROXY_HEADERS (kommagetrennt). Ein explizites leeres Array in der Konfiguration überschreibt die Umgebungsvariable.

maxUploadSize

Optional. Maximal erlaubte Mediendatei-Upload-Größe in Bytes. Gilt sowohl für direkte Multipart-Uploads als auch für Signed-URL-Uploads. Standard ist 52_428_800 (50 MB). Das folgende Beispiel erhöht das Limit auf 100 MB:

emdash({
	database: sqlite({ url: "file:./data.db" }),
	storage: local({
		directory: "./uploads",
		baseUrl: "/_emdash/api/media/file",
	}),
	maxUploadSize: 100 * 1024 * 1024, // 100 MB
});
WertBeschreibung
number (Bytes)Muss eine positive endliche Ganzzahl sein
weggelassenStandard 50 MB

Uploads, die das konfigurierte Limit überschreiten, werden mit einer 413 Payload Too Large-Antwort auf dem direkten Upload-Pfad oder einem 400 Validation Error auf dem Signed-URL-Pfad abgelehnt.

toolbar

Optional. Steuert, wie die Editor-Toolbar (die schwebende Pille auf öffentlichen Seiten) ausgeliefert wird. Standard ist "server".

WertVerhalten
"server" (Standard)Die Toolbar wird serverseitig in jede HTML-Antwort injiziert, die für einen authentifizierten Editor gerendert wird.
"client"Öffentliches HTML ist identisch für jeden Besucher. Ein kleines Bootstrap-Skript zeigt eine “Edit”-Pille in Browsern, die sich im Admin angemeldet haben; ein Klick verifiziert die Sitzung und lädt die Seite mit einem _edit-Query-Parameter neu, der immer frisch gerendert wird (nie gecacht) mit der vollständigen Toolbar.
falseToolbar oder Bootstrap-Skript niemals rendern.
emdash({
	toolbar: "client",
})

Verwende "client", wenn dein öffentliches HTML über einen gemeinsamen Cache bereitgestellt wird (Cloudflare Cache Everything / Workers Cache, Fastly, Varnish, …). Mit serverseitiger Injection erhält ein Editor, der die öffentliche Seite durchsucht, die gecachte anonyme Variante — ohne die Toolbar — wann immer ein anonymer Besucher den Cache zuerst befüllt hat, sodass die Toolbar mit dem Cache-Zustand erscheint und verschwindet. Im Client-Modus wird nichts Sitzungsspezifisches in teilbares HTML injiziert, sodass der Cache vollständig effektiv bleibt und die Toolbar zuverlässig ist.

Hinweise zum "client"-Modus:

  • Abgemeldete Besucher, die eine geteilte ?_edit-URL öffnen, werden zur kanonischen URL weitergeleitet, sodass der Parameter keine Entwürfe verraten oder zusätzliche Cache-Einträge mit Seiteninhalt anlegen kann.
  • Das “angemeldet”-Signal ist ein nicht-geheimes localStorage-Flag, das vom Admin gesetzt wird; die Pille verifiziert die echte Sitzung, bevor sie die Bearbeitungsansicht betritt.
  • Das Bootstrap ist ein kleines Inline-<script>. Wenn deine Seite eine strikte Content-Security-Policy ohne 'unsafe-inline' sendet, füge einen Hash dafür hinzu — dasselbe gilt für die serverseitig injizierte Toolbar.
  • EmDash injiziert nichts Sitzungsspezifisches — aber wenn deine eigenen Templates auf Astro.locals.user verzweigen (z.B. ein “Admin”-Nav-Link für angemeldete Benutzer), ist diese Varianz weiterhin in deinem HTML und fragmentiert den Cache weiterhin.

In jedem Modus kann die Toolbar im Browser über die ×-Schaltfläche geschlossen werden (pro Browser, bis zum nächsten Mal, wenn ein Editor den Admin öffnet). Vorschau- und Bearbeitungsmodus-Antworten werden immer serverseitig mit Cache-Control: private, no-store gerendert.

experimental

Optional. Opt-in Features, deren Verhalten oder Datenformat sich in einem Minor-Release ändern oder entfernt werden kann. Jedes Feld wird unabhängig aktiviert.

experimental.registry

Optional. Lenkt die Plugin-Browse- und Installations-Flows des Admin-Dashboards auf eine föderierte Plugin-Registry statt auf den zentralen Marktplatz. Erfordert sandboxRunner, da Registry-Plugins sandboxed ausgeführt werden.

Übergib eine einfache Aggregator-URL-Zeichenkette oder ein Objekt, wenn du einen Labeller oder eine Release-Age-Policy benötigst. Das folgende Beispiel verwendet die Objekt-Form:

emdash({
	sandboxRunner: "@emdash-cms/sandbox-cloudflare",
	experimental: {
		registry: {
			aggregatorUrl: "https://registry.emdashcms.com",
			acceptLabelers: "did:plc:emdashverification",
			policy: {
				minimumReleaseAge: "48h",
				minimumReleaseAgeExclude: ["did:plc:yourfirstpartydid"],
			},
		},
	},
});
OptionTypBeschreibung
aggregatorUrlstringAggregator-Origin, wo die XRPC-Endpunkte der Registry gemountet sind. HTTPS in Produktion.
acceptLabelersstringKommagetrennte Labeller-DIDs, die an den Aggregator für Takedown- und Verifizierungs-Labels weitergeleitet werden.
policy.minimumReleaseAgestring | numberReleases zurückhalten, die neuer als dieses Alter sind. Dauer-String ("48h", "7d") oder Sekunden.
policy.minimumReleaseAgeExcludestring[]DIDs (oder <did>/<slug>-Paare), die vom Holdback ausgenommen sind.

Siehe Die Plugin-Registry für den vollständigen Workflow, das Vertrauensmodell und wie du die Registry von deiner eigenen Seite abfragen kannst.

Datenbank-Adapter

Importiere die Adapter aus emdash/db:

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

sqlite(config)

SQLite-Datenbank mit better-sqlite3. Das folgende Beispiel verbindet sich mit einer lokalen Datei:

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

libsql(config)

libSQL-Datenbank. Das folgende Beispiel verbindet sich mit einer entfernten 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,
});

postgres(config)

PostgreSQL-Datenbank mit Connection Pooling.

OptionTypBeschreibung
connectionStringstringPostgreSQL-Verbindungs-URL
hoststringDatenbank-Host
portnumberDatenbank-Port
databasestringDatenbankname
userstringDatenbankbenutzer
passwordstringDatenbankpasswort
sslbooleanSSL aktivieren
pool.minnumberMinimale Pool-Größe (Standard: 0)
pool.maxnumberMaximale Pool-Größe (Standard: 10)

Das folgende Beispiel verbindet sich mit einem Connection-String:

postgres({ connectionString: process.env.DATABASE_URL });

d1(config)

Cloudflare D1-Datenbank. Importiere aus @emdash-cms/cloudflare.

OptionTypStandardBeschreibung
bindingstringD1-Binding-Name aus wrangler.jsonc
sessionstring"disabled"Lesereplikationsmodus: "disabled", "auto" oder "primary-first"
bookmarkCookiestring"__em_d1_bookmark"Cookie-Name für Session-Lesezeichen

Das folgende Beispiel zeigt ein einfaches Binding und eines mit aktivierten Leserepliken:

// Einfach
d1({ binding: "DB" });

// Mit Leserepliken
d1({ binding: "DB", session: "auto" });

Wenn session "auto" oder "primary-first" ist, nutzt EmDash die D1 Sessions API, um Leseabfragen an nahegelegene Repliken weiterzuleiten. Authentifizierte Benutzer erhalten Bookmark-basierte Read-your-writes-Konsistenz. Siehe Datenbankoptionen — Leserepliken für Details.

Speicher-Adapter

Importiere local und s3 aus emdash/astro. Der r2-Adapter wird aus @emdash-cms/cloudflare importiert:

import emdash, { local, s3 } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";

local(config)

Lokaler Dateisystem-Speicher. Das folgende Beispiel stellt Uploads aus einem lokalen Verzeichnis bereit:

OptionTypBeschreibung
directorystringVerzeichnispfad
baseUrlstringBasis-URL für die Dateibereitstellung
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Cloudflare R2-Binding. Das folgende Beispiel verwendet ein R2-Binding mit einer öffentlichen URL:

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

s3(config?)

S3-kompatibler Speicher. Alle Konfigurationsfelder sind optional: jedes Feld, das in s3({...}) weggelassen wird, wird aus der entsprechenden S3_*-Umgebungsvariable aufgelöst, wenn der Node-Prozess startet. Explizite Werte haben immer Vorrang.

Voraussetzung: Installiere @aws-sdk/client-s3 und @aws-sdk/s3-request-presigner in deinem Projekt. EmDash Core bündelt das AWS SDK nicht. Siehe Speicheroptionen: S3-kompatibler Speicher für Details.

OptionTypBeschreibung
endpointstringS3-Endpunkt-URL (S3_ENDPOINT)
bucketstringBucket-Name (S3_BUCKET)
accessKeyIdstringZugriffsschlüssel (S3_ACCESS_KEY_ID)
secretAccessKeystringGeheimer Schlüssel (S3_SECRET_ACCESS_KEY)
regionstringRegion, Standard "auto" (S3_REGION)
publicUrlstringOptionale CDN-URL (S3_PUBLIC_URL)

Die folgenden Beispiele lösen alle Felder aus der Umgebung auf, mischen Konfiguration und Umgebung oder übergeben jedes Feld explizit:

// Alle Felder aus S3_*-Umgebungsvariablen (Node-Container-Deployments)
s3()

// Mix: CDN aus Konfiguration, Rest aus Umgebung
s3({ publicUrl: "https://cdn.example.com" })

// Alle explizit
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",
})

Die Laufzeitauflösung von Umgebungsvariablen ist eine Node-only-Funktion. Auf Cloudflare Workers werden Secrets und Variablen über den env-Parameter des Fetch-Handlers bereitgestellt, nicht über process.env, sodass S3_*-Umgebungsvariablen nicht erfasst werden. Workers-Deployments sollten entweder den r2(config)-Adapter verwenden oder explizite Werte an s3({...}) übergeben. Siehe Speicheroptionen für Details.

Object-Cache-Adapter

Übergib einen dieser an die objectCache-Option.

kvCache(config)

Cloudflare KV-Backend, geteilt über alle Isolates. Importiere aus @emdash-cms/cloudflare.

kvCache({
	binding: "CACHE", // KV-Binding-Name (erforderlich)
	defaultTtl: 3600, // Eintrags-TTL in Sekunden (optional, KV-Minimum 60)
	revalidate: 1000, // Cross-Isolate Staleness-Fenster in ms (optional)
	timeout: 2000, // Per-Op Timeout in ms vor einem Miss (optional, 0 deaktiviert)
	keyPrefix: "em", // Cache-Schlüssel-Präfix (optional)
})

memoryCache(config?)

In-Process Backend für Node.js und Entwicklung. Importiere aus emdash/astro.

memoryCache({
	defaultTtl: 3600, // Eintrags-TTL in Sekunden (optional)
	revalidate: 1000, // Staleness-Fenster in ms (optional)
	maxEntries: 1000, // Max gecachte Schlüssel vor Eviction (optional)
	keyPrefix: "em", // Cache-Schlüssel-Präfix (optional)
})

Siehe Object Cache für Einrichtung und Verhalten.

Live-Sammlungen

Konfiguriere den EmDash-Loader in src/live.config.ts:

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

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

Loader-Optionen

Die emdashLoader()-Funktion nimmt keine Argumente:

emdashLoader();

Umgebungsvariablen

EmDash beachtet diese Umgebungsvariablen:

VariableBeschreibung
EMDASH_SITE_URLÖffentlicher browserseitiger Origin (fällt auf SITE_URL zurück)
EMDASH_ALLOWED_ORIGINSKommagetrennte Liste zusätzlicher Origins, die von der Passkey-Verifizierung akzeptiert werden (Multi-Subdomain-Deployments).
EMDASH_DATABASE_URLDatenbank-URL überschreiben
EMDASH_ENCRYPTION_KEYSchlüssel zum Verschlüsseln von Plugin-Secrets im Ruhezustand. Vom Betreiber bereitgestellt — wird nie in der Datenbank gespeichert.
EMDASH_PREVIEW_SECRETOptionale Überschreibung für das Vorschau-HMAC-Secret. Wenn nicht gesetzt, wird ein stabiler site-spezifischer Wert generiert und in der Datenbank gespeichert.
EMDASH_IP_SALTOptionale Überschreibung für den Kommentator-IP-Hash-Salt. Wenn nicht gesetzt, wird ein stabiler site-spezifischer Wert generiert und in der Datenbank gespeichert.
EMDASH_AUTH_SECRETLegacy. Wird als IP-Salt-Quelle verwendet, wenn gesetzt; bestehende Installationen sollten dies beibehalten, um stabile Kommentator-IP-Hashes beim Upgrade zu bewahren.
EMDASH_TURNSTILE_SECRET_KEYCloudflare Turnstile Secret Key (fällt auf TURNSTILE_SECRET_KEY zurück). Wenn gesetzt, müssen Kommentar-Einreichungen ein gültiges Turnstile-Token enthalten — kombiniere es mit der turnstileSiteKey-Prop auf <CommentForm>.
EMDASH_URLRemote EmDash URL für Schema-Sync

Generiere einen Verschlüsselungsschlüssel mit dem folgenden Befehl:

npx emdash secrets generate

package.json-Konfiguration

Templates und Sites können optionale Metadaten unter einem emdash-Schlüssel in package.json deklarieren:

{
	"emdash": {
		"label": "My Blog Template",
		"seed": ".emdash/seed.json",
		"url": "https://my-site.pages.dev"
	}
}
OptionBeschreibung
labelTemplate-Name zur Anzeige
seedPfad zur Seed-JSON-Datei
urlRemote URL für Schema-Sync

TypeScript-Konfiguration

EmDash generiert Typen in .emdash/types.ts. Füge einen Pfad-Alias zu deiner tsconfig.json hinzu:

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

Generiere Typen mit dem folgenden Befehl:

npx emdash types