Riferimento alla configurazione

In questa pagina

La configurazione principale di EmDash si trova in astro.config.mjs, mentre src/live.config.ts registra il content loader. Valori specifici del deployment possono provenire anche da variabili d’ambiente. Un piccolo blocco di metadati emdash in package.json supporta le etichette dei template e i flussi CLI locali legacy.

Integrazione Astro

Configura EmDash come integrazione Astro 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: [],
		}),
	],
});

Opzioni di integrazione

database

Obbligatorio. Configurazione dell’adapter del database. Scegli un 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 from @emdash-cms/cloudflare)
database: d1({ binding: "DB" });

Vedi Opzioni database per i dettagli.

migrations

Opzionale. Controlla la gestione a runtime delle migrazioni interne del database di EmDash. Se omessa, l’opzione predefinita è { runtime: "auto" }.

migrations: {
	runtime: "check", // "auto" | "check" | "manual"
	dev: "auto",     // override opzionale in sviluppo
}

auto verifica e applica le migrazioni in sospeso, check restituisce 503 quando ci sono migrazioni note al build in esecuzione ancora in sospeso e manual non esegue alcuna query di migrazione a runtime. EMDASH_MIGRATIONS_MODE sovrascrive la modalità runtime effettiva. Prima di adottare check o manual, vedi Gestire le migrazioni del database principale.

storage

Opzionale. Configurazione dell’adapter di storage media. Se omessa, EmDash salva i file in ./.emdash/uploads e li serve tramite /_emdash/api/media/file. Scegli un adapter quando la directory locale predefinita non è adatta:

// Local filesystem (development)
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-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
});

Vedi Opzioni di storage per i dettagli.

images

Opzionale. Controlla se EmDash integra i media memorizzati con l’ottimizzazione immagini di Astro. Il valore predefinito è true.

Se abilitata, EmDash avvolge l’endpoint immagini di Astro così <Image> e getImage() possono leggere i byte sorgente direttamente dall’adapter di storage configurato. Funziona anche quando l’URL media originale è dietro Cloudflare Access. Imposta images: false quando un altro servizio immagini gestisce i media o quando ogni immagine deve essere renderizzata senza il wrapper dell’endpoint di EmDash.

emdash({
	images: false,
});

mediaProviders

Opzionale. Aggiunge servizi media alla libreria media. Il provider locale basato su storage resta disponibile automaticamente; ogni descrittore in questo array aggiunge un altro punto in cui gli editor possono sfogliare o caricare media.

L’esempio seguente aggiunge Cloudflare Images e Cloudflare Stream:

import { cloudflareImages, cloudflareStream } from "@emdash-cms/cloudflare";

emdash({
	mediaProviders: [cloudflareImages({}), cloudflareStream({})],
});

Le credenziali del provider vengono risolte a runtime. Le configurazioni vuote sopra usano le variabili d’ambiente Cloudflare predefinite descritte nelle sezioni adapter cloudflareImages(config) e cloudflareStream(config). Per binding e setup di rendering, vedi Libreria media: provider media.

objectCache

Opzionale. Memorizza in cache i risultati delle query su contenuto e configurazione in un archivio chiave/valore, così le letture non interrogano il database a ogni richiesta. Disabilitato se omesso. Scegli un adapter:

// Cloudflare KV (shared across all isolates)
import { kvCache } from "@emdash-cms/cloudflare";
objectCache: kvCache({ binding: "CACHE" });

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

Vedi Object Cache per configurazione e opzioni.

middleware.outer

Opzionale. Registra un modulo middleware Astro esterno allo stack middleware completo di EmDash. Poiché l’integrazione lo registra in Astro con order: "pre", viene eseguito anche prima del middleware definito in src/middleware.ts. Usalo per gate sulle richieste o cache dell’intera risposta che devono evitare l’inizializzazione di runtime e database in caso di hit, o per header di risposta che dipendono dall’HTML finale di EmDash.

emdash({
	middleware: {
		outer: "./src/outer-middleware.ts",
	},
});

L’ordine di esecuzione è:

  1. Il middleware esterno viene eseguito fino a await next().
  2. EmDash inizializza runtime e database, poi esegue setup, autenticazione e middleware del contesto richiesta.
  3. La route Astro viene renderizzata.
  4. EmDash applica mutazioni alla risposta, inclusi HTML per la modifica visuale e header di sicurezza/timing.
  5. next() risolve verso il middleware esterno con quella risposta finale.

Prima di chiamare next(), il middleware ha il normale contesto di richiesta Astro e di esecuzione piattaforma, ma locals.emdash, locals.user, il database e lo stato EmDash scoped alla richiesta non sono disponibili. Una Response anticipata salta completamente EmDash, quindi deve includere gli header di sicurezza e cache necessari. Dopo che next() risolve, è sicuro finalizzare i nonce CSP, mettere in cache il body completo o impostare Content-Length. Se il middleware modifica il body, rimuovi o ricalcola qualsiasi header Content-Length esistente.

L’hook usa l’API middleware di Astro sia su Node che su Cloudflare. Questo esempio minimale con Cloudflare Cache API mette in cache solo risposte HTML anonime e restituisce i hit prima dell’inizializzazione di EmDash:

import { waitUntil } from "cloudflare:workers";
import { defineMiddleware } from "astro:middleware";

export const onRequest = defineMiddleware(async ({ request }, next) => {
	if (request.method !== "GET" || request.headers.has("cookie")) {
		return next();
	}

	const cacheKey = new Request(request.url, { method: "GET" });
	const cached = await caches.default.match(cacheKey);
	if (cached) return cached;

	const response = await next();
	const isHtml = response.headers.get("content-type")?.includes("text/html");
	const isPrivate = response.headers.get("cache-control")?.includes("no-store");
	if (response.ok && isHtml && !isPrivate) {
		waitUntil(caches.default.put(cacheKey, response.clone()));
	}

	return response;
});

Su Node, usa la stessa forma di middleware con una cache compatibile con Node come Redis. Chiavi di cache e regole di bypass devono includere ogni proprietà della richiesta che cambia la risposta renderizzata.

playground

Opzionale. Abilita il middleware usato dai playground EmDash usa e getta basati sul browser. Crea un database Durable Object scrivibile per ogni sessione, applica il seed configurato e autentica il visitatore come amministratore anonimo prima che venga eseguito il middleware EmDash normale.

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

emdash({
	database: playgroundDatabase({ binding: "PLAYGROUND_DB" }),
	playground: {
		middlewareEntrypoint: "@emdash-cms/cloudflare/db/playground-middleware",
	},
});

Questa modalità richiede @emdash-cms/cloudflare e un binding Durable Object. Bypassa il middleware di setup e autenticazione normale, quindi usala solo per siti demo effimeri, non per un CMS di produzione.

plugins

Opzionale. Array di plugin che girano nello stesso processo del sito Astro. I plugin nativi vanno qui. Un plugin compatibile con la sandbox può girare qui se ti fidi del pieno accesso al processo e non ti serve l’isolamento.

L’esempio seguente registra un plugin nativo:

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

plugins: [seoPlugin()];

I plugin nativi possono usare direttamente le API di server e framework, quindi non possono essere spostati in sandboxed a meno che il pacchetto non esponga anche un entry point plugin compatibile con la sandbox. Vedi Scegliere un formato plugin per le differenze di authoring e deployment.

sandboxed

Opzionale. Array di plugin compatibili con la sandbox che usano le API plugin dichiarate da EmDash e girano in runtime isolati. Non mettere qui un plugin nativo: il codice nativo può dipendere da accesso a processo e framework che la sandbox non fornisce.

import thirdPartyPlugin from "third-party-emdash-plugin";
import { sandbox } from "@emdash-cms/cloudflare";

emdash({
	sandboxed: [thirdPartyPlugin()],
	sandboxRunner: sandbox(),
});

I plugin in sandbox vengono saltati se non è configurato un sandbox runner utilizzabile. Vedi Sandbox dei plugin per la configurazione del runner su Cloudflare e Node.js.

sandboxRunner

Opzionale. Specifier del modulo per la factory che avvia runtime plugin isolati. È obbligatorio per i plugin in sandboxed e per i plugin del marketplace o del registry.

Su Cloudflare Workers, usa l’adapter sandbox():

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

emdash({
	sandboxRunner: sandbox(),
});

I deployment Node.js usano il modulo runner workerd documentato in Sandbox dei plugin: Node.js.

sandbox

Opzionale. Controlla se un sandbox runner configurato isola i plugin. La sandbox è abilitata quando sandboxRunner è configurato. Imposta sandbox: false solo per capire se un problema proviene dal plugin o dal suo runtime sandbox:

emdash({
	sandboxRunner: sandbox(),
	sandbox: false,
});

Con false, i plugin dichiarati in sandboxed e installati dal marketplace girano nel processo server principale senza isolamento né limiti di risorse. Ripristina la sandbox dopo la diagnosi.

registry

Opzionale. Configura aggregatore e policy del registry plugin. Senza valore esplicito, EmDash usa https://registry.emdashcms.com quando sandboxRunner è configurato e sandbox non è false.

Imposta registry: false per disabilitare la scoperta del registry e i plugin installati dal registry, mantenendo il sandbox runner disponibile per i plugin in sandboxed e i plugin legacy del Marketplace:

emdash({
	sandboxRunner: sandbox(),
	registry: false,
});

Passa l’URL del servizio registry come stringa, oppure usa un oggetto quando il sito richiede fonti di moderazione o una policy sull’età delle release. L’esempio seguente usa la forma oggetto:

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

emdash({
	sandboxRunner: sandbox(),
	registry: {
		aggregatorUrl: "https://registry.emdashcms.com",
		acceptLabelers: "did:web:labels.emdashcms.com",
		policy: {
			minimumReleaseAge: "48h",
			minimumReleaseAgeExclude: ["did:plc:yourfirstpartydid"],
		},
	},
});
OpzioneTipoDescrizione
aggregatorUrlstringURL base del servizio registry. Usa HTTPS in produzione.
acceptLabelersstringOpzionale: identificatori decentralizzati (DID) separati da virgola per i servizi di moderazione accettati dalla richiesta. Un DID è un identificatore stabile di account Atmosphere. Questa impostazione non può sovrascrivere la policy del servizio registry.
policy.minimumReleaseAgestring | numberTrattiene le release più recenti di questa età. Stringa durata ("48h", "7d") o secondi.
policy.minimumReleaseAgeExcludestring[]DID publisher o coppie <did>/<plugin-slug> esenti dal trattenimento.

La policy sull’età delle release esenta la prima release di un pacchetto solo quando il registry segnala una release conservata e conferma di aver osservato il pacchetto in modo continuo. Un pacchetto backfillato, una release precedente eliminata o prove di storico mancanti mantengono il trattenimento. Le esenzioni esplicite per publisher e pacchetto si applicano indipendentemente dallo storico.

Vedi Il registry plugin per il flusso di installazione e il modello di fiducia.

marketplace

Deprecato. URL base usato per aggiornare i plugin installati dal Marketplace legacy. La navigazione del Marketplace e le nuove installazioni non compaiono nell’admin. I plugin Marketplace esistenti restano aggiornabili e disinstallabili finché questa opzione è configurata.

emdash({
	marketplace: "https://marketplace.emdashcms.com",
	sandboxRunner: sandbox(),
});

Gli URL di produzione devono usare HTTPS; HTTP è accettato solo per localhost e 127.0.0.1 in sviluppo. Mantieni questa opzione finché ogni plugin Marketplace non è stato sostituito o disinstallato, poi rimuovila. Segui Migrare dal Marketplace per la procedura completa.

fonts

Opzionale. Configurazione dei font dell’interfaccia admin.

Per impostazione predefinita, EmDash carica Noto Sans tramite l’Astro Font API. I font vengono scaricati da Google al build time e self-hosted, quindi non ci sono richieste CDN a runtime. Il font base copre latino, cirillico, greco, devanagari e vietnamita.

Per aggiungere supporto ad altri sistemi di scrittura, passa i nomi degli script. L’esempio seguente aggiunge arabo e giapponese:

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

Gli script disponibili sono 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 e tibetan.

Ogni script corrisponde alla variante Noto Sans su Google Fonts (ad es. "arabic" carica Noto Sans Arabic). Tutti i font face condividono un unico nome font-family e usano unicode-range così il browser scarica solo i file necessari per i caratteri presenti nella pagina.

Imposta false per disabilitare del tutto l’iniezione dei font e usare i font di sistema:

emdash({
	fonts: false,
})

Il CSS admin usa la variabile CSS --font-emdash, impostata automaticamente dalla configurazione font sopra.

auth

Opzionale. Un adapter di autenticazione. Il login integrato di EmDash usa le passkey; impostare auth le sostituisce con un provider esterno. L’adapter Cloudflare Access, access(), è fornito da @emdash-cms/cloudflare:

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

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

Opzioni per access():

OpzioneTipoPredefinitoDescrizione
teamDomainstringobbligatorioDominio team Cloudflare Access
audiencestring—Tag Application Audience (AUD). Su Workers, preferisci audienceEnvVar.
audienceEnvVarstring"CF_ACCESS_AUDIENCE"Variabile d’ambiente da cui leggere il tag audience a runtime
autoProvisionbooleantrueCrea un utente EmDash al primo login
defaultRolenumber30Livello ruolo per utenti non corrispondenti in roleMapping (vedi Ruoli utente)
syncRolesbooleanfalseRiapplica roleMapping a ogni login invece che solo al provisioning
roleMappingobject—Mappa nomi gruppo IdP a livelli ruolo EmDash; vince la prima corrispondenza

authProviders

Opzionale. Array di provider di login collegabili (top-level, accanto a auth). Ogni voce è il risultato della chiamata a una factory del provider, come nell’esempio:

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

Provider integrati:

  • github() — legge EMDASH_OAUTH_GITHUB_CLIENT_ID / EMDASH_OAUTH_GITHUB_CLIENT_SECRET (o fallback senza prefisso).
  • google() — legge EMDASH_OAUTH_GOOGLE_CLIENT_ID / EMDASH_OAUTH_GOOGLE_CLIENT_SECRET.
  • atproto() — login account Atmosphere (Bluesky e la rete AT Protocol più ampia). Nessuna variabile d’ambiente richiesta. Accetta { allowedDIDs, allowedHandles, defaultRole }. Vedi la guida login Atmosphere.

I pacchetti di terze parti possono registrare provider propri con la stessa forma AuthProviderDescriptor — vedi Provider di login.

mcp

Opzionale. Abilita l’endpoint Model Context Protocol (MCP) su /_emdash/api/mcp. L’endpoint è abilitato per impostazione predefinita e richiede un bearer token, quindi abilitarlo non concede accesso anonimo.

Imposta l’opzione su false quando il sito non deve esporre un endpoint MCP:

emdash({
	mcp: false,
});

Vedi Riferimento server MCP per la creazione del token e la configurazione del client.

siteUrl

Origin pubblico visibile al browser per il sito (schema + host + porta opzionale, senza path). Impostalo prima di eseguire il setup di produzione. Solo gli host di sviluppo loopback possono completare il setup senza un origin configurato.

Dietro un reverse proxy che termina TLS, Astro.url restituisce l’indirizzo interno (http://localhost:4321) invece di quello pubblico (https://cms.example.com). Questo rompe passkey, corrispondenza origin CSRF, redirect OAuth, redirect di login, discovery MCP, export snapshot, sitemap, robots.txt e dati strutturati JSON-LD. Imposta siteUrl per correggere tutto insieme.

L’integrazione valida questo valore al caricamento: deve essere un URL valido con protocollo http: o https: ed è normalizzato all’origin (il path viene rimosso).

L’esempio seguente imposta l’origin pubblico:

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

Quando siteUrl non è impostato in config, EmDash controlla le variabili d’ambiente in ordine: EMDASH_SITE_URL, poi SITE_URL. Utile per deployment container dove l’URL pubblico è impostato a runtime.

Il setup fallisce con SITE_URL_REQUIRED su un host non loopback quando nessuna delle due fonti è impostata. Evita che la prima richiesta di setup non autenticata scelga l’origin usato nelle email di autenticazione successive.

Su Cloudflare Workers, il fallback da variabili d’ambiente legge process.env. Con nodejs_compat, Cloudflare popola process.env per impostazione predefinita per date di compatibilità dal 2025-04-01 in poi. I progetti fissati a una data precedente devono aggiungere anche nodejs_compat_populate_process_env.

// wrangler.jsonc
{
	"compatibility_date": "2026-02-24",
	"compatibility_flags": ["nodejs_compat"],
	"vars": { "EMDASH_SITE_URL": "https://cms.example.com" },
}

allowedOrigins

Opzionale. Origin browser aggiuntivi accettati dalla verifica passkey per un deployment raggiungibile su più hostname.

siteUrl definisce un unico origin canonico. Quando lo stesso deployment EmDash è raggiungibile sotto più hostname che condividono un dominio genitore registrabile (ad es. https://example.com e https://preview.example.com), la verifica passkey rifiuta asserzioni il cui origin non corrisponde esattamente a siteUrl — anche se WebAuthn consente passkey valide tra sottodomini sotto lo stesso rpId.

Dichiara origin aggiuntivi accettati tramite allowedOrigins in astro.config.mjs o la variabile d’ambiente EMDASH_ALLOWED_ORIGINS. L’origin canonico siteUrl resta la fonte di rpId; le voci elencate qui sono accettate al momento della verifica. Le due fonti vengono unite a runtime, così la config può dichiarare origin stabili (versionati, revisionati nel codice) mentre l’env aggiunge extra specifici dell’ambiente (ad es. anteprime PR effimere).

L’esempio seguente dichiara un origin extra in config:

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

I valori equivalenti possono provenire anche da variabili d’ambiente:

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

EmDash valida questi valori per evitare config morta che il browser non onorerebbe mai:

  • Ogni voce deve essere un URL http: o https: analizzabile, senza punto finale e senza label vuote nell’hostname.
  • Quando allowedOrigins non è vuoto, siteUrl deve essere impostato (da una delle fonti) e non deve essere un letterale IP né avere un hostname con punto finale.
  • Ogni origin deve essere lo stesso hostname di siteUrl o un suo sottodominio. (WebAuthn richiede che rpId sia un suffisso registrabile di ogni origin.)

Se la validazione fallisce, vedrai un errore attribuito alla fonte come 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.

Dove compare l’errore dipende da dove sono dichiarati i valori:

  • All’avvio di Astro, quando sia config.allowedOrigins sia config.siteUrl provengono da astro.config.mjs — errori di battitura nel codice fanno fallire il build.
  • Alla prima verifica passkey, quando uno dei valori proviene da EMDASH_ALLOWED_ORIGINS o EMDASH_SITE_URL — mismatch env compaiono come 500 al primo tentativo di verifica.

Setup reverse proxy

Astro riflette X-Forwarded-* solo quando l’host pubblico è consentito. Configura security.allowedDomains per l’hostname (e gli schema) che i tuoi utenti usano. In astro dev, aggiungi vite.server.allowedHosts corrispondenti così Vite accetta l’header Host del proxy.

Preferisci correggere prima allowedDomains (e gli header inoltrati); usa siteUrl quando l’URL ricostruito continua a divergere dall’origin del browser (tipico quando TLS termina davanti e la richiesta upstream resta http://).

Con TLS davanti, legare il server dev al loopback (astro dev --host 127.0.0.1) spesso basta: il proxy si connette in locale mentre siteUrl corrisponde all’origin HTTPS pubblico.

Se il proxy scrive un header IP client, imposta trustedProxyHeaders così i rate limit di EmDash possono usare l’IP client reale invece di raggruppare ogni richiesta sotto una chiave condivisa “unknown”.

La configurazione seguente imposta allowedDomains, vite.server.allowedHosts e siteUrl insieme per un deployment dietro reverse proxy:

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

Opzionale. Header da considerare attendibili per la risoluzione dell’IP client quando gira dietro un reverse proxy sotto il tuo controllo. Usato dai rate limit di autenticazione (magic-link, signup, passkey, OAuth device flow) e dall’endpoint commenti pubblico.

Su Cloudflare l’oggetto cf allegato alla richiesta è usato automaticamente — di norma non serve impostarlo. Su deployment self-hosted dietro nginx, Caddy, Traefik, Fly, Railway o simili, impostalo sull’header che scrive il proxy così i rate limit raggruppano per IP client reale invece di trattare ogni richiesta come “unknown”.

L’esempio seguente considera attendibile l’header x-real-ip impostato da nginx, Caddy o Traefik:

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

Gli header sono provati in ordine. I valori che corrispondono a *-forwarded-for sono analizzati come liste separate da virgola e si usa la prima voce. L’esempio seguente preferisce l’header di Fly.io e fa fallback su x-forwarded-for:

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

Se non impostato in config, EmDash legge la variabile d’ambiente EMDASH_TRUSTED_PROXY_HEADERS (separata da virgola). Un array vuoto esplicito in config sovrascrive la variabile d’ambiente.

maxUploadSize

Opzionale. Dimensione massima consentita per l’upload di file media, in byte. Si applica sia agli upload multipart diretti sia agli upload con URL firmato. Predefinito 52_428_800 (50 MB). L’esempio seguente alza il limite a 100 MB:

emdash({
	database: sqlite({ url: "file:./data.db" }),
	storage: local({
		directory: "./uploads",
		baseUrl: "/_emdash/api/media/file",
	}),
	maxUploadSize: 100 * 1024 * 1024, // 100 MB
});
ValoreDescrizione
number (byte)Deve essere un intero finito positivo
omessoPredefinito 50 MB

Gli upload che superano il limite configurato vengono rifiutati con risposta 413 Payload Too Large sul percorso di upload diretto, o 400 Validation Error sul percorso URL firmato.

admin

Opzionale. Sostituisce il branding EmDash nell’interfaccia admin. Questi valori non cambiano titolo, logo o favicon del sito pubblico.

emdash({
	admin: {
		logo: "/images/agency-logo.webp",
		siteName: "Agency CMS",
		favicon: "/favicon.ico",
	},
});
OpzioneTipoDescrizione
logostringURL o path del logo per pagina di login e sidebar
siteNamestringNome mostrato nella sidebar e nel titolo del browser
faviconstringURL o path del favicon per le pagine admin

toolbar

Opzionale. Controlla come viene erogata la toolbar dell’editor (la pillola flottante sulle pagine pubbliche). Predefinito "server".

ValoreComportamento
"server" (predefinito)La toolbar è iniettata lato server in ogni risposta HTML renderizzata per un editor autenticato.
"client"L’HTML pubblico è identico per ogni visitatore. Un piccolo script bootstrap mostra una pillola “Edit” nei browser che hanno effettuato login nell’admin; cliccandola verifica la sessione e ricarica la pagina con il parametro query _edit, sempre renderizzato fresco (mai in cache) con la toolbar completa.
falseNon renderizzare mai la toolbar né lo script bootstrap.
emdash({
	toolbar: "client",
})

Usa "client" quando l’HTML pubblico è servito tramite cache condivisa (Cloudflare Cache Everything / Workers Cache, Fastly, Varnish, …). Con iniezione lato server, un editor che naviga il sito pubblico riceve la variante anonima in cache — senza toolbar — ogni volta che un visitatore anonimo ha riempito la cache per primo, quindi la toolbar compare e scompare con lo stato della cache. In modalità client nulla di specifico della sessione è iniettato nell’HTML condivisibile, così la cache resta pienamente efficace e la toolbar è affidabile.

Note sulla modalità "client":

  • I visitatori non autenticati che aprono un URL condiviso ?_edit vengono reindirizzati all’URL canonico, così il parametro non può far trapelare bozze o riempire voci cache extra con il contenuto della pagina.
  • Il segnale “logged in” è un flag localStorage non segreto impostato dall’admin; la pillola verifica la sessione reale prima di entrare nella vista modifica.
  • Il bootstrap è un piccolo <script> inline. Se il sito invia una Content-Security-Policy restrittiva senza 'unsafe-inline', aggiungi un hash — lo stesso vale per la toolbar iniettata lato server.
  • EmDash non inietta nulla di specifico della sessione — ma se i tuoi template ramificano su Astro.locals.user (ad es. un link nav “Admin” per utenti autenticati), quella varianza resta nel tuo HTML e frammenta ancora la cache.

In ogni modalità, la toolbar può essere chiusa nel browser con il pulsante × (per browser, fino alla prossima apertura dell’admin da un editor). Le risposte in anteprima e in modalità modifica sono sempre renderizzate lato server con Cache-Control: private, no-store.

experimental

Opzionale. Funzionalità opt-in il cui comportamento o formato wire può cambiare o essere rimosso in una release minor. Ogni campo si abilita in modo indipendente.

experimental.registry

Deprecato. Usa l’opzione top-level registry. La configurazione experimental.registry esistente continua a funzionare quando l’opzione top-level è omessa. Se entrambe sono presenti, prevale il valore top-level.

La modifica seguente sposta un URL registry esistente al livello top-level:

emdash({
	experimental: {
		registry: "https://registry.example.com",
	},
	registry: "https://registry.example.com",
});

Adapter database

Importa gli adapter da emdash/db:

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

sqlite(config)

Database SQLite tramite il driver database integrato di Node.js. L’esempio seguente si connette a un file locale:

OpzioneTipoDescrizione
urlstringPath del file con prefisso file:
sqlite({ url: "file:./data.db" });

libsql(config)

Database libSQL. L’esempio seguente si connette a un database libSQL remoto:

OpzioneTipoDescrizione
urlstringURL del database
authTokenstringToken auth a runtime (opzionale per file locali)
migrationAuthTokenEnvstringNome variabile token migrazione (predefinito TURSO_AUTH_TOKEN)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

Database PostgreSQL con connection pooling.

OpzioneTipoDescrizione
connectionStringstringURL di connessione PostgreSQL
hoststringHost del database
portnumberPorta del database
databasestringNome del database
userstringUtente del database
passwordstringPassword del database
sslbooleanAbilita SSL
pool.minnumberDimensione minima pool (predefinito: 0)
pool.maxnumberDimensione massima pool (predefinito: 10)
pool.connectionTimeoutMillisnumberAttesa massima connessione (pg predefinito: 0, nessun timeout)
pool.idleTimeoutMillisnumberDurata client idle (pg predefinito: 10.000 ms)
migrationConnectionStringEnvstringNome variabile connection string migrazione (predefinito DATABASE_URL)

L’esempio seguente si connette con una connection string:

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

d1(config)

Database Cloudflare D1. Importa da @emdash-cms/cloudflare.

OpzioneTipoPredefinitoDescrizione
bindingstring—Nome binding D1 da wrangler.jsonc
sessionstring"disabled"Modalità replica lettura: "disabled", "auto" o "primary-first"
bookmarkCookiestring"__em_d1_bookmark"Nome cookie per i bookmark di sessione
coalescebooleanfalseRaggruppa letture concorrenti nello stesso turno event-loop; richiede modalità sessione diversa da "disabled"

L’esempio seguente mostra un binding base e uno con read replica abilitate:

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

// With read replicas
d1({ binding: "DB", session: "auto" });

Quando session è "auto" o "primary-first", EmDash usa la D1 Sessions API per instradare le query di lettura verso replica vicine. Gli utenti autenticati ottengono consistenza read-your-writes basata su bookmark. Vedi Opzioni database — Read replica per i dettagli.

hyperdrive(config?)

PostgreSQL tramite un binding Cloudflare Hyperdrive. Importa questo adapter da @emdash-cms/cloudflare.

OpzioneTipoPredefinitoDescrizione
bindingstring"HYPERDRIVE"Binding Hyperdrive primario con caching query disabilitato
cachedBindingstring—Secondo binding opzionale con cache abilitata per letture pubbliche anonime
preferUncachedAfterWriteMsnumber60_000Per quanto tempo le letture pubbliche usano il primario dopo una scrittura di contenuto quando cachedBinding è impostato
migrationConnectionStringEnvstringDerivato dal binding primarioVariabile d’ambiente con l’URL PostgreSQL diretto usato da emdash migrate
maxnumber5Connessioni massime da un isolate Worker a Hyperdrive

L’esempio seguente instrada richieste autenticate e scritture tramite il binding senza cache, mentre le letture pubbliche anonime possono usare il binding con cache:

hyperdrive({
	binding: "HYPERDRIVE",
	cachedBinding: "HYPERDRIVE_CACHED",
	preferUncachedAfterWriteMs: 60_000,
});

Entrambi i binding devono puntare allo stesso database. Installa pg versione 8.16.3 o successiva, abilita il flag di compatibilità nodejs_compat e configura un URL database diretto per le migrazioni di deployment. Vedi Opzioni database: Hyperdrive per il setup completo Worker e migrazioni.

durableObjects(config)

Memorizza il CMS in un Durable Object con backend SQLite. Importa questo adapter da @emdash-cms/cloudflare.

OpzioneTipoPredefinitoDescrizione
bindingstringobbligatorioBinding namespace Durable Object per la classe EmDashDB
namestring"emdash"Nome oggetto singleton; cambialo solo per isolare più database dietro un binding
sessionstring"disabled""auto" instrada letture anonime alle replica e scritture al primario
bookmarkCookiestring"__em_do_bookmark"Cookie per consistenza read-your-writes in modalità "auto"
durableObjects({ binding: "DB_DO", session: "auto" });

Il routing verso replica richiede i flag di compatibilità experimental e replica_routing più la classe Durable Object e le voci di migrazione in wrangler.jsonc.

previewDatabase(config)

Crea un database snapshot isolato per sessione di anteprima in un Durable Object. L’unica opzione è il nome binding obbligatorio:

previewDatabase({ binding: "PREVIEW_DB" });

Questo adapter è per l’infrastruttura di anteprima, non per il database primario di un sito di produzione.

playgroundDatabase(config)

Crea un database seeded scrivibile per sessione playground in un Durable Object. Abbinalo all’opzione di integrazione playground:

playgroundDatabase({ binding: "PLAYGROUND_DB" });

Il binding obbligatorio identifica il namespace Durable Object del playground. Usa questo adapter solo per siti demo usa e getta.

Adapter di storage

Importa local e s3 da emdash/astro. L’adapter r2 si importa da @emdash-cms/cloudflare:

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

local(config)

Storage su filesystem locale. L’esempio seguente serve gli upload da una directory locale:

OpzioneTipoDescrizione
directorystringPath della directory
baseUrlstringURL base per servire i file
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Binding Cloudflare R2. L’esempio seguente usa un binding R2 con URL pubblico:

OpzioneTipoDescrizione
bindingstringNome binding R2
publicUrlstringURL pubblico opzionale
r2({
	binding: "MEDIA",
	publicUrl: "https://pub-xxxx.r2.dev",
});

s3(config?)

Storage compatibile S3. Tutti i campi di config sono opzionali: ogni campo omesso da s3({...}) viene risolto dalla variabile d’ambiente S3_* corrispondente all’avvio del processo Node. I valori espliciti hanno sempre precedenza.

Dopo l’unione di config e variabili d’ambiente, endpoint e bucket sono obbligatori. Se è impostata una credenziale, servono sia accessKeyId sia secretAccessKey. Valori mancanti fanno fallire l’avvio con codice errore MISSING_S3_CONFIG.

Prerequisito: installa @aws-sdk/client-s3 e @aws-sdk/s3-request-presigner nel progetto. Il core EmDash non include l’AWS SDK. Vedi Opzioni di storage: storage compatibile S3 per i dettagli.

OpzioneTipoDescrizione
endpointstringURL endpoint S3 (S3_ENDPOINT)
bucketstringNome bucket (S3_BUCKET)
accessKeyIdstringChiave di accesso (S3_ACCESS_KEY_ID)
secretAccessKeystringChiave segreta (S3_SECRET_ACCESS_KEY)
regionstringRegione, predefinito "auto" (S3_REGION)
publicUrlstringURL CDN opzionale (S3_PUBLIC_URL)

Gli esempi seguenti risolvono tutti i campi dall’ambiente, mescolano config e ambiente o passano ogni campo esplicitamente:

// 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
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 risoluzione delle variabili d’ambiente a runtime è una funzionalità solo Node. Su Cloudflare Workers, secret e variabili sono esposti tramite il parametro env del fetch handler, non tramite process.env, quindi le variabili d’ambiente S3_* non vengono lette. I deployment Workers dovrebbero usare l’adapter r2(config) o passare valori espliciti a s3({...}). Vedi Opzioni di storage per i dettagli.

Adapter object cache

Passane uno all’opzione objectCache.

kvCache(config)

Backend Cloudflare KV, condiviso tra tutti gli isolate. Importa da @emdash-cms/cloudflare.

kvCache({
	binding: "CACHE", // KV binding name (required)
	defaultTtl: 3600, // entry TTL in seconds (optional, KV minimum 60)
	revalidate: 1000, // cross-isolate staleness window in ms (optional)
	timeout: 2000, // per-op timeout in ms before a miss (optional, 0 disables)
	keyPrefix: "em", // cache key prefix (optional)
})

memoryCache(config?)

Backend in-process per Node.js e sviluppo. Importa da emdash/astro.

memoryCache({
	defaultTtl: 3600, // entry TTL in seconds (optional)
	revalidate: 1000, // staleness window in ms (optional)
	maxEntries: 1000, // max cached keys before eviction (optional)
	keyPrefix: "em", // cache key prefix (optional)
})

Vedi Object Cache per configurazione e comportamento.

Adapter autenticazione e sandbox

Questi adapter restituiscono valori per le opzioni di integrazione auth e sandboxRunner.

access(config)

Sostituisce il login passkey integrato con autenticazione Cloudflare Access. Importalo da @emdash-cms/cloudflare e passa il risultato a auth:

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

emdash({
	auth: access({
		teamDomain: "myteam.cloudflareaccess.com",
		audienceEnvVar: "CF_ACCESS_AUDIENCE",
	}),
});

teamDomain è obbligatorio. L’adapter può leggere l’audience dell’applicazione da audience o dalla variabile indicata da audienceEnvVar; accetta anche autoProvision, defaultRole, syncRoles e roleMapping. L’opzione auth documenta i predefiniti e il comportamento dei ruoli.

sandbox()

Seleziona Cloudflare Worker Loader come sandbox runner dei plugin. Importalo da @emdash-cms/cloudflare e passa il valore restituito a sandboxRunner:

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

emdash({
	sandboxRunner: sandbox(),
});

Il sito richiede anche un binding Worker Loader e l’entry point plugin bridge. Vedi Sandbox dei plugin: Cloudflare Workers per quelle impostazioni di deployment.

Adapter provider media

Passa descrittori provider media a mediaProviders. Entrambi i provider Cloudflare integrati si importano da @emdash-cms/cloudflare.

Ogni opzione *EnvVar sotto indica una variabile d’ambiente. Il provider la legge in questo ordine: un binding Cloudflare Workers con quel nome, poi process.env sull’adapter Node. L’opzione diretta corrispondente (accountId, accountHash, apiToken) ha sempre precedenza su entrambe.

cloudflareImages(config)

Aggiunge Cloudflare Images per sfogliare, caricare, eliminare e distribuire asset immagine.

OpzioneTipoPredefinitoDescrizione
accountIdstringDa CF_ACCOUNT_IDID account Cloudflare
accountIdEnvVarstring"CF_ACCOUNT_ID"Variabile usata quando accountId è omesso
accountHashstringDa CF_IMAGES_ACCOUNT_HASHHash account usato negli URL di delivery
accountHashEnvVarstring"CF_IMAGES_ACCOUNT_HASH"Variabile usata quando accountHash è omesso
apiTokenstringDa CF_IMAGES_TOKENToken con permessi lettura e modifica Cloudflare Images
apiTokenEnvVarstring"CF_IMAGES_TOKEN"Variabile usata quando apiToken è omesso
deliveryDomainstringimagedelivery.netHostname delivery immagini personalizzato
defaultVariantstring"public"Variante immagine usata per la visualizzazione
mediaProviders: [cloudflareImages({ defaultVariant: "public" })];

cloudflareStream(config)

Aggiunge Cloudflare Stream per sfogliare, cercare, caricare, eliminare e riprodurre asset video.

OpzioneTipoPredefinitoDescrizione
accountIdstringDa CF_ACCOUNT_IDID account Cloudflare
accountIdEnvVarstring"CF_ACCOUNT_ID"Variabile usata quando accountId è omesso
apiTokenstringDa CF_STREAM_TOKENToken con permessi lettura e modifica Cloudflare Stream
apiTokenEnvVarstring"CF_STREAM_TOKEN"Variabile usata quando apiToken è omesso
customerSubdomainstringPredefinito CloudflareHostname delivery Stream personalizzato
controlsbooleantrueMostra controlli del player
autoplaybooleanfalseAvvia riproduzione automaticamente
loopbooleanfalseRipeti riproduzione
mutedbooleanfalse, o true con autoplayAudio disattivato
mediaProviders: [cloudflareStream({ controls: true })];

Vedi Libreria media: provider media per i binding richiesti e i componenti di rendering.

Adapter cache Astro

cloudflareCache(config?)

L’adapter legacy restituisce un cache.provider Astro che memorizza le risposte nella Workers Cache API e purga i tag cache tramite Cloudflare REST API:

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

export default defineConfig({
	cache: {
		provider: cloudflareCache(),
	},
});

Accetta cacheName (predefinito "emdash") e bookmarkCookie (predefinito "__em_d1_bookmark"), più zoneId o zoneIdEnvVar e apiToken o apiTokenEnvVar per richieste purge-by-tag. I nomi variabile predefiniti sono CF_ZONE_ID e CF_CACHE_PURGE_TOKEN.

Collezioni live

Configura il loader EmDash in src/live.config.ts:

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

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

Opzioni loader

La funzione emdashLoader() non accetta argomenti:

emdashLoader();

Variabili d’ambiente

EmDash rispetta queste variabili d’ambiente:

VariabileDescrizione
EMDASH_SITE_URLOrigin pubblico visibile al browser (fallback su SITE_URL)
EMDASH_ALLOWED_ORIGINSElenco separato da virgola di origin aggiuntivi accettati dalla verifica passkey (deployment multi-sottodominio).
EMDASH_DATABASE_URLOverride URL database
EMDASH_ENCRYPTION_KEYChiave per cifrare i secret dei plugin at rest. Fornita dall’operatore — mai memorizzata nel database.
EMDASH_PREVIEW_SECRETOverride opzionale del secret HMAC anteprima. Se non impostato, viene generato e memorizzato nel database un valore stabile per sito.
EMDASH_IP_SALTOverride opzionale del salt per l’hash IP commentatori. Se non impostato, viene generato e memorizzato nel database un valore stabile per sito.
EMDASH_AUTH_SECRETLegacy. Usato come fonte salt IP se impostato; le installazioni esistenti dovrebbero mantenerlo per preservare hash IP commentatori stabili dopo l’upgrade.
EMDASH_TURNSTILE_SECRET_KEYChiave segreta Cloudflare Turnstile (fallback su TURNSTILE_SECRET_KEY). Se impostata, gli invii commento devono includere un token Turnstile valido — abbinala alla prop turnstileSiteKey su <CommentForm>.
EMDASH_URLURL EmDash remoto per sync schema

Genera una chiave di cifratura con il comando seguente:

npx emdash secrets generate

Configurazione package.json

Template e siti possono dichiarare metadati opzionali sotto una chiave emdash in package.json:

{
	"emdash": {
		"label": "My Blog Template",
		"schema": ".emdash/schema.sql",
		"seed": ".emdash/seed.json",
		"url": "https://my-site.pages.dev"
	}
}
OpzioneDescrizione
labelNome template per la visualizzazione
schemaSchema SQL opzionale letto da emdash init
seedPath al file seed JSON
urlURL remoto usato dal flusso deprecato emdash dev --types

Configurazione TypeScript

Durante lo sviluppo locale, l’integrazione Astro genera emdash-env.d.ts nella root del progetto e lo aggiorna dopo modifiche allo schema. Il file estende il modulo emdash, così gli import standard getEmDashCollection() e getEmDashEntry() inferiscono i campi delle collection locali senza alias di path.

Il comando separato emdash types recupera lo schema da un’istanza locale o remota in esecuzione e scrive .emdash/types.ts per impostazione predefinita. Aggiungi un alias solo quando il codice applicativo importa direttamente quell’output standalone:

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

Genera i tipi schema remoto standalone con il comando seguente:

npx emdash types