EmDash のメイン設定は astro.config.mjs にあり、src/live.config.ts がコンテンツローダーを登録します。デプロイメント固有の値は環境変数からも取得できます。package.json の小さな emdash メタデータブロックは、テンプレートラベルとレガシーのローカル CLI フローをサポートします。
Astro 統合
EmDash を Astro 統合として 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: [],
}),
],
});
統合オプション
database
必須。 データベースアダプターの設定です。アダプターを 1 つ選択します。
// 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" });
詳細は データベースオプション を参照してください。
migrations
任意。 EmDash の内部データベースマイグレーションのランタイム処理を制御します。このオプションを省略すると { runtime: "auto" } がデフォルトになります。
migrations: {
runtime: "check", // "auto" | "check" | "manual"
dev: "auto", // 開発環境向けの任意の上書き
}
auto は保留中のマイグレーションを確認して適用します。check は実行中のビルドが認識している保留マイグレーションがある場合に 503 を返します。manual はランタイムでのマイグレーションクエリを行いません。EMDASH_MIGRATIONS_MODE が実効的なランタイムモードを上書きします。check または manual を採用する前に コアデータベースマイグレーションの管理 を参照してください。
storage
任意。 メディアストレージアダプターの設定です。このオプションを省略すると、EmDash は ./.emdash/uploads にファイルを保存し、/_emdash/api/media/file 経由で配信します。デフォルトのローカルディレクトリが適さない場合はアダプターを選択します。
// ローカルファイルシステム(開発)
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
// R2 バインディング(Cloudflare Workers)
storage: r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev", // 任意
});
// S3 互換(任意のプラットフォーム)— すべてのフィールドを S3_* 環境変数から
storage: s3()
// 明示的な値を指定する場合
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", // 任意、デフォルト: "auto"
publicUrl: "https://cdn.example.com", // 任意
});
詳細は ストレージオプション を参照してください。
images
任意。 保存済みメディアを Astro の画像最適化と統合するかどうかを制御します。デフォルトは true です。
有効にすると、EmDash は Astro の画像エンドポイントをラップし、<Image> と getImage() が設定済みストレージアダプターからソースバイトを直接読み取れるようにします。元のメディア URL が Cloudflare Access の背後にある場合も動作します。別の画像サービスがメディアを扱う場合、または EmDash のエンドポイントラッパーなしですべての画像を描画したい場合は images: false に設定します。
emdash({
images: false,
});
mediaProviders
任意。 メディアライブラリにメディアサービスを追加します。ストレージベースのローカルプロバイダーは自動的に利用可能なままです。この配列の各記述子は、編集者がメディアを閲覧またはアップロードできる場所を 1 つ追加します。
次の例では Cloudflare Images と Cloudflare Stream を追加します。
import { cloudflareImages, cloudflareStream } from "@emdash-cms/cloudflare";
emdash({
mediaProviders: [cloudflareImages({}), cloudflareStream({})],
});
プロバイダーの資格情報はランタイムで解決されます。上記の空設定は、cloudflareImages(config) および cloudflareStream(config) アダプターセクションで説明するデフォルトの Cloudflare 環境変数を使用します。バインディングとレンダリングのセットアップは メディアライブラリ: メディアプロバイダー を参照してください。
objectCache
任意。 コンテンツと設定のクエリ結果をキー/値ストアにキャッシュし、リクエストごとにデータベースを問い合わせずに読み取りを提供します。省略すると無効です。アダプターを 1 つ選択します。
// Cloudflare KV(すべての isolate で共有)
import { kvCache } from "@emdash-cms/cloudflare";
objectCache: kvCache({ binding: "CACHE" });
// メモリ内(Node.js / 開発)
import { memoryCache } from "emdash/astro";
objectCache: memoryCache();
セットアップとオプションは オブジェクトキャッシュ を参照してください。
middleware.outer
任意。 完全な EmDash ミドルウェアスタックの外側に Astro ミドルウェアモジュールを登録します。統合は Astro の order: "pre" で登録するため、src/middleware.ts で定義したミドルウェアより前にも実行されます。ヒット時にランタイムとデータベースの初期化を避ける必要があるリクエストゲートや完全レスポンスキャッシュ、または EmDash の最終 HTML に依存するレスポンスヘッダーに使用します。
emdash({
middleware: {
outer: "./src/outer-middleware.ts",
},
});
実行順序は次のとおりです。
- 外側ミドルウェアが
await next()まで実行されます。 - EmDash がランタイムとデータベースを初期化し、セットアップ、認証、リクエストコンテキストのミドルウェアを実行します。
- Astro ルートがレンダリングされます。
- EmDash がビジュアル編集 HTML やセキュリティ/タイミングヘッダーを含むレスポンス変更を適用します。
next()がその最終レスポンスで外側ミドルウェアに解決されます。
next() を呼ぶ前、ミドルウェアは通常の Astro リクエストとプラットフォーム実行コンテキストを持ちますが、locals.emdash、locals.user、データベース、リクエストスコープの EmDash 状態は利用できません。早期の Response は EmDash を完全にスキップするため、必要なセキュリティとキャッシュヘッダーを含める必要があります。next() 解決後は、CSP nonce の確定、完全なボディのキャッシュ、Content-Length の設定が安全です。ミドルウェアがボディを変更する場合は、既存の Content-Length ヘッダーを削除または再計算してください。
このフックは Node と Cloudflare の両方で Astro のミドルウェア API を使用します。次の最小限の Cloudflare Cache API の例は、匿名 HTML レスポンスのみをキャッシュし、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;
});
Node では、Redis など Node 互換キャッシュで同じミドルウェア形状を使用します。キャッシュキーとバイパスルールには、レンダリング結果を変えるリクエスト属性をすべて含める必要があります。
playground
任意。 使い捨てのブラウザベース EmDash プレイグラウンドで使用するミドルウェアを有効にします。セッションごとに書き込み可能な Durable Object データベースを作成し、設定済みシードを適用し、通常の EmDash ミドルウェアの前に訪問者を匿名管理者としてサインインします。
import { playgroundDatabase } from "@emdash-cms/cloudflare";
emdash({
database: playgroundDatabase({ binding: "PLAYGROUND_DB" }),
playground: {
middlewareEntrypoint: "@emdash-cms/cloudflare/db/playground-middleware",
},
});
このモードには @emdash-cms/cloudflare と Durable Object バインディングが必要です。通常のセットアップと認証ミドルウェアをバイパスするため、本番 CMS ではなく一時的なデモサイト専用に使用してください。
plugins
任意。 Astro サイトと同じプロセスで実行するプラグインの配列です。ネイティブプラグインはここに置きます。プロセスへの完全アクセスを信頼し、分離が不要な場合、サンドボックス互換プラグインもここで実行できます。
次の例ではネイティブプラグインを登録します。
import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];
ネイティブプラグインはサーバーとフレームワーク API を直接使用できるため、パッケージがサンドボックス互換のプラグインエントリポイントも提供しない限り sandboxed へ移せません。作成とデプロイの違いは プラグイン形式の選択 を参照してください。
sandboxed
任意。 EmDash が宣言するプラグイン API を使用し、分離されたランタイムで実行するサンドボックス互換プラグインの配列です。ネイティブプラグインはここに置かないでください。ネイティブコードはサンドボックスが提供しないプロセスとフレームワークアクセスに依存する場合があります。
import thirdPartyPlugin from "third-party-emdash-plugin";
import { sandbox } from "@emdash-cms/cloudflare";
emdash({
sandboxed: [thirdPartyPlugin()],
sandboxRunner: sandbox(),
});
使用可能なサンドボックスランナーが設定されていない場合、サンドボックス化プラグインはスキップされます。Cloudflare と Node.js のランナーセットアップは プラグインサンドボックス を参照してください。
sandboxRunner
任意。 分離されたプラグインランタイムを起動するファクトリのモジュール指定子です。sandboxed 内のプラグインおよびマーケットプレイスまたはレジストリプラグインに必須です。
Cloudflare Workers では sandbox() アダプターを使用します。
import { sandbox } from "@emdash-cms/cloudflare";
emdash({
sandboxRunner: sandbox(),
});
Node.js デプロイメントでは、プラグインサンドボックス: Node.js に記載の workerd ランナーモジュールを使用します。
sandbox
任意。 設定済みサンドボックスランナーがプラグインを分離するかどうかを制御します。sandboxRunner が設定されているとサンドボックス化は有効です。問題がプラグイン由来かサンドボックスランタイム由来かを診断するときだけ sandbox: false に設定してください。
emdash({
sandboxRunner: sandbox(),
sandbox: false,
});
false の場合、sandboxed で宣言されマーケットプレイスからインストールされたプラグインは、分離やリソース制限なしでメインサーバープロセスで実行されます。診断後はサンドボックス化を復元してください。
registry
任意。 プラグインレジストリ のアグリゲーターとポリシーを設定します。明示的な値がない場合、sandboxRunner が設定され sandbox が false でなければ、EmDash は https://registry.emdashcms.com を使用します。
registry: false にすると、レジストリの検出とレジストリ経由でインストールされたプラグインを無効にしつつ、sandboxed で宣言したプラグインとレガシー Marketplace プラグイン向けにサンドボックスランナーは利用可能なままにできます。
emdash({
sandboxRunner: sandbox(),
registry: false,
});
レジストリサービスの URL を文字列で渡すか、モデレーションソースやリリース年齢ポリシーが必要な場合はオブジェクトを使用します。次の例はオブジェクト形式です。
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"],
},
},
});
| オプション | 型 | 説明 |
|---|---|---|
aggregatorUrl | string | レジストリサービスのベース URL。本番では HTTPS を使用してください。 |
acceptLabelers | string | リクエストが受け入れるモデレーションサービスの、任意のカンマ区切り分散識別子(DID)。DID は安定した Atmosphere アカウント識別子です。この設定はレジストリサービスのポリシーを上書きできません。 |
policy.minimumReleaseAge | string | number | この年齢より新しいリリースを保留します。期間文字列("48h"、"7d")または秒数。 |
policy.minimumReleaseAgeExclude | string[] | 保留の対象外とするパブリッシャー DID、または <did>/<plugin-slug> ペア。 |
リリース年齢ポリシーは、レジストリが保持リリースを 1 件報告し、パッケージを継続的に観測したと確認した場合にのみ、パッケージの初回リリースを免除します。バックフィルされたパッケージ、削除された以前のリリース、履歴証拠の欠如は保留を維持します。明示的なパブリッシャーとパッケージの免除は履歴に関係なく適用されます。
インストールワークフローと信頼モデルは プラグインレジストリ を参照してください。
marketplace
非推奨。 レガシー Marketplace からインストールしたプラグインを更新するために使用するベース URL。Marketplace の閲覧と新規インストールは管理画面に表示されません。このオプションが設定されている間、既存の Marketplace プラグインは更新とアンインストールが可能です。
emdash({
marketplace: "https://marketplace.emdashcms.com",
sandboxRunner: sandbox(),
});
本番 URL は HTTPS 必須です。HTTP は開発中の localhost と 127.0.0.1 のみ許可されます。すべての Marketplace プラグインを置き換えるかアンインストールするまでこのオプションを維持し、その後削除してください。完全な手順は Marketplace からの移行 に従ってください。
fonts
任意。 管理 UI のフォント設定。
デフォルトでは、EmDash は Astro Font API 経由で Noto Sans を読み込みます。フォントはビルド時に Google からダウンロードされ自己ホストされるため、ランタイムの CDN リクエストはありません。ベースフォントはラテン、キリル、ギリシャ、デーヴァナーガリー、ベトナムの文字体系をカバーします。
追加の文字体系をサポートするにはスクリプト名を渡します。次の例ではアラビア語と日本語を追加します。
emdash({
fonts: {
scripts: ["arabic", "japanese"],
},
})
利用可能なスクリプトは 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、tibetan です。
各スクリプトは Google Fonts 上の対応する Noto Sans バリアントにマップされます(例: "arabic" は Noto Sans Arabic を読み込みます)。すべてのフォントフェイスは単一の font-family 名を共有し、unicode-range を使用して、ページ上の文字に必要なファイルだけブラウザがダウンロードするようにします。
フォント注入を完全に無効にしてシステムフォントを使うには false に設定します。
emdash({
fonts: false,
})
管理 CSS は --font-emdash CSS 変数を使用します。これは上記のフォント設定によって自動的に設定されます。
auth
任意。 認証アダプター。EmDash の組み込みログインはパスキーです。auth を設定すると外部プロバイダーに置き換わります。Cloudflare Access アダプター access() は @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,
},
}),
});
access() のオプション:
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
teamDomain | string | 必須 | Cloudflare Access のチームドメイン |
audience | string | — | Application Audience (AUD) タグ。Workers では audienceEnvVar を推奨。 |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | ランタイムで audience タグを読み取る環境変数 |
autoProvision | boolean | true | 初回ログイン時に EmDash ユーザーを作成 |
defaultRole | number | 30 | roleMapping に一致しないユーザーのロールレベル(ユーザーロール を参照) |
syncRoles | boolean | false | プロビジョニング時だけでなく、ログインのたびに roleMapping を再適用 |
roleMapping | object | — | IdP グループ名を EmDash ロールレベルにマップ。最初の一致が優先 |
authProviders
任意。 差し替え可能なログインプロバイダーの配列(auth と並ぶトップレベル)。各エントリは、下記のようにプロバイダーファクトリを呼び出した結果です。
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()],
});
組み込みプロバイダー:
github()—EMDASH_OAUTH_GITHUB_CLIENT_ID/EMDASH_OAUTH_GITHUB_CLIENT_SECRET(またはプレフィックスなしのフォールバック)を読み取ります。google()—EMDASH_OAUTH_GOOGLE_CLIENT_ID/EMDASH_OAUTH_GOOGLE_CLIENT_SECRETを読み取ります。atproto()— Atmosphere アカウントログイン(Bluesky と AT Protocol ネットワーク全体)。環境変数は不要。{ allowedDIDs, allowedHandles, defaultRole }を受け付けます。Atmosphere ログインガイド を参照してください。
サードパーティパッケージは同じ AuthProviderDescriptor 形状で独自プロバイダーを登録できます — ログインプロバイダー を参照してください。
mcp
任意。 /_emdash/api/mcp の Model Context Protocol (MCP) エンドポイントを有効にします。エンドポイントはデフォルトで有効で bearer トークンが必要なため、有効化しても匿名アクセスは付与されません。
サイトが MCP エンドポイントを公開してはならない場合は false に設定します。
emdash({
mcp: false,
});
トークン作成とクライアント設定は MCP サーバーリファレンス を参照してください。
siteUrl
サイトの公開ブラウザ向けオリジン(スキーム + ホスト + 任意のポート、パスなし)。本番セットアップを実行する前に設定してください。設定済みオリジンなしでセットアップを完了できるのはループバック開発ホストのみです。
TLS 終端リバースプロキシの背後では、Astro.url は公開アドレス(https://cms.example.com)ではなく内部アドレス(http://localhost:4321)を返します。これによりパスキー、CSRF オリジン一致、OAuth リダイレクト、ログインリダイレクト、MCP ディスカバリ、スナップショットエクスポート、サイトマップ、robots.txt、JSON-LD 構造化データが壊れます。siteUrl を設定するとこれらを一度に修正できます。
統合は読み込み時にこの値を検証します。有効な URL で http: または https: プロトコルである必要があり、オリジンに正規化されます(パスは除去されます)。
次の例では公開オリジンを設定します。
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
siteUrl: "https://cms.example.com",
});
設定で siteUrl が未設定の場合、EmDash は環境変数を順に確認します: EMDASH_SITE_URL、次に SITE_URL。公開 URL をランタイムで設定するコンテナデプロイメントに有用です。
どちらのソースも未設定で非ループバックホストの場合、セットアップは SITE_URL_REQUIRED で失敗します。これにより、最初の未認証セットアップリクエストが後続の認証メールで使うオリジンを選ぶことを防ぎます。
Cloudflare Workers では、環境変数フォールバックは process.env を読みます。nodejs_compat では、互換性日付が 2025-04-01 以降の場合、Cloudflare はデフォルトで process.env を投入します。より古い日付に固定したプロジェクトは 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
任意。 複数ホスト名で利用可能なデプロイメント向けに、パスキー検証が受け入れる追加のブラウザオリジン。
siteUrl は単一の正規オリジンを定義します。同じ EmDash デプロイメントが登録可能な親ドメインを共有する複数ホスト名(例: https://example.com と https://preview.example.com)で到達可能な場合、WebAuthn が同一 rpId 下のサブドメイン間でパスキーを有効にできても、オリジンが siteUrl と完全一致しないアサーションはパスキー検証で拒否されます。
追加の受け入れオリジンは、astro.config.mjs の allowedOrigins または EMDASH_ALLOWED_ORIGINS 環境変数で宣言します。正規 siteUrl は rpId のソースのままです。ここに列挙したエントリは検証時に受け入れられます。2 つのソースはランタイムでマージされるため、設定で安定したオリジン(バージョン管理、コードレビュー)を宣言し、環境変数で環境固有の追加(例: 一時的な PR プレビュー)を足せます。
次の例では設定で追加オリジンを 1 つ宣言します。
emdash({
siteUrl: "https://example.com",
allowedOrigins: ["https://preview.example.com"],
})
同等の値は環境変数からも指定できます。
EMDASH_SITE_URL=https://example.com
EMDASH_ALLOWED_ORIGINS=https://preview.example.com,https://staging.example.com
検証
EmDash はブラウザが決して尊重しない無効な設定を防ぐため、これらを検証します。
- 各エントリは、末尾ドットなし、ホスト名に空ラベルなしの解析可能な
http:またはhttps:URL である必要があります。 allowedOriginsが空でない場合、siteUrlが設定されている必要があります(どちらのソースでも)。IP リテラルや末尾ドット付きホスト名であってはなりません。- 各オリジンは
siteUrlと同じホスト名、またはそのサブドメインである必要があります(WebAuthn ではrpIdがすべてのオリジンの登録可能サフィックスである必要があります)。
検証に失敗すると、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. のようなソース付きエラーが表示されます。
エラーが表面化するタイミングは値の宣言場所によります。
astro.config.mjsからconfig.allowedOriginsとconfig.siteUrlの両方が来る場合 — Astro 起動時。コードの typo はビルド失敗になります。EMDASH_ALLOWED_ORIGINSまたはEMDASH_SITE_URLからどちらかが来る場合 — 初回パスキー検証時。環境変数の不一致は最初の verify 試行で 500 になります。
リバースプロキシのセットアップ
Astro は公開ホストが許可されている場合にのみ X-Forwarded-* を反映します。ユーザーがアクセスするホスト名(とスキーム)向けに security.allowedDomains を設定してください。astro dev では、Vite がプロキシの Host ヘッダーを受け入れるよう、一致する vite.server.allowedHosts を追加します。
まず allowedDomains(と forwarded ヘッダー)の修正を優先してください。再構築 URL が依然としてブラウザオリジンと乖離する場合(TLS が前段で終端し upstream が http:// のままの典型)に siteUrl を使用します。
TLS が前段にある場合、開発サーバーをループバックにバインド(astro dev --host 127.0.0.1)するだけで十分なことが多いです。プロキシはローカル接続し、siteUrl が公開 HTTPS オリジンと一致します。
プロキシがクライアント IP ヘッダーを書き込む場合、trustedProxyHeaders を設定して、EmDash のレート制限が共有の “unknown” キーにすべてのリクエストを入れるのではなく、実クライアント IP を使えるようにしてください。
次の設定は、リバースプロキシデプロイメント向けに allowedDomains、vite.server.allowedHosts、siteUrl をまとめて設定します。
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
任意。 制御下のリバースプロキシの背後で実行するとき、クライアント IP 解決のために信頼するヘッダー。認証レート制限(マジックリンク、サインアップ、パスキー、OAuth デバイスフロー)と公開コメントエンドポイントで使用されます。
Cloudflare ではリクエストに付く cf オブジェクトが自動使用されるため、通常は設定不要です。nginx、Caddy、Traefik、Fly、Railway などの背後の自己ホストデプロイメントでは、プロキシが書き込むヘッダーを設定し、すべてのリクエストを “unknown” として扱うのではなく実クライアント IP でレート制限をバケット化します。
次の例では nginx、Caddy、Traefik が設定する x-real-ip ヘッダーを信頼します。
emdash({
database: sqlite({ url: "file:./data.db" }),
trustedProxyHeaders: ["x-real-ip"],
});
ヘッダーは順に試されます。*-forwarded-for に一致する値はカンマ区切りリストとして解析され、最初のエントリが使用されます。次の例では Fly.io のヘッダーを優先し、x-forwarded-for にフォールバックします。
emdash({
trustedProxyHeaders: ["fly-client-ip", "x-forwarded-for"],
});
設定で未指定の場合、EmDash は EMDASH_TRUSTED_PROXY_HEADERS 環境変数(カンマ区切り)を読みます。設定の明示的な空配列は環境変数を上書きします。
maxUploadSize
任意。 許可されるメディアファイルアップロードサイズの上限(バイト)。直接 multipart アップロードと署名 URL アップロードの両方に適用されます。デフォルトは 52_428_800(50 MB)。次の例では上限を 100 MB に引き上げます。
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
maxUploadSize: 100 * 1024 * 1024, // 100 MB
});
| 値 | 説明 |
|---|---|
number(バイト) | 正の有限整数である必要があります |
| 省略 | デフォルト 50 MB |
設定上限を超えるアップロードは、直接アップロードパスでは 413 Payload Too Large、署名 URL パスでは 400 Validation Error で拒否されます。
admin
任意。 管理インターフェースの EmDash ブランディングを置き換えます。これらの値は公開サイトのタイトル、ロゴ、ファビコンは変更しません。
emdash({
admin: {
logo: "/images/agency-logo.webp",
siteName: "Agency CMS",
favicon: "/favicon.ico",
},
});
| オプション | 型 | 説明 |
|---|---|---|
logo | string | ログインページとサイドバー用のロゴ URL またはパス |
siteName | string | サイドバーとブラウザタイトルに表示する名前 |
favicon | string | 管理ページ用のファビコン URL またはパス |
toolbar
任意。 編集ツールバー(公開ページの浮遊ピル)の配信方法を制御します。デフォルトは "server"。
| 値 | 動作 |
|---|---|
"server"(デフォルト) | 認証済み編集者向けにレンダリングされるすべての HTML レスポンスに、サーバー側でツールバーを注入します。 |
"client" | 公開 HTML はすべての訪問者で同一です。小さな bootstrap スクリプトが管理にログインしたブラウザに “Edit” ピルを表示します。クリックするとセッションを検証し、_edit クエリパラメータ付きでページを再読み込みし、完全なツールバー付きで常に新鮮に(キャッシュされず)レンダリングされます。 |
false | ツールバーと bootstrap スクリプトを一切レンダリングしません。 |
emdash({
toolbar: "client",
})
公開 HTML が共有キャッシュ(Cloudflare Cache Everything / Workers Cache、Fastly、Varnish など)経由で配信される場合は "client" を使用してください。サーバー側注入では、匿名訪問者が先にキャッシュを温めたとき、公開サイトを閲覧する編集者はツールバーなしのキャッシュ済み匿名バリアントを受け取るため、ツールバーはキャッシュ状態とともに現れたり消えたりします。クライアントモードでは共有可能 HTML にセッション固有のものを注入しないため、キャッシュは完全に有効でツールバーは安定します。
"client" モードの注意:
- ログアウトした訪問者が共有
?_editURL を開くと正規 URL にリダイレクトされ、パラメータが下書きを漏らしたりページ内容で余分なキャッシュエントリを温めたりしません。 - 「ログイン済み」信号は管理が設定する非秘密の
localStorageフラグです。ピルは編集ビューに入る前に実セッションを検証します。 - bootstrap は小さなインライン
<script>です。サイトが'unsafe-inline'なしの厳格なContent-Security-Policyを送る場合、そのハッシュを追加してください — サーバー注入ツールバーにも同様です。 - EmDash はセッション固有のものを注入しません — ただし独自テンプレートが
Astro.locals.userで分岐する場合(例: ログインユーザー向け “Admin” ナビリンク)、その差分は HTML に残りキャッシュを分割します。
すべてのモードで、ツールバーは × ボタンでブラウザ内で閉じられます(ブラウザごと、次に編集者が管理を開くまで)。プレビューと編集モードのレスポンスは常に Cache-Control: private, no-store でサーバー側レンダリングされます。
experimental
任意。 マイナーリリースで動作やワイヤ形式が変わったり削除されたりする可能性のあるオプトイン機能。各フィールドは独立して有効化されます。
experimental.registry
非推奨。 トップレベルの registry オプションを使用してください。トップレベルが省略されている場合、既存の experimental.registry 設定は引き続き動作します。両方ある場合、トップレベルの値が優先されます。
次の変更は既存のレジストリ URL をトップレベルへ移します。
emdash({
experimental: {
registry: "https://registry.example.com",
},
registry: "https://registry.example.com",
});
データベースアダプター
アダプターは emdash/db からインポートします。
import { sqlite, libsql, postgres } from "emdash/db";
sqlite(config)
Node.js 組み込みデータベースドライバーを使う SQLite データベース。次の例はローカルファイルに接続します。
| オプション | 型 | 説明 |
|---|---|---|
url | string | file: プレフィックス付きファイルパス |
sqlite({ url: "file:./data.db" });
libsql(config)
libSQL データベース。次の例はリモート libSQL データベースに接続します。
| オプション | 型 | 説明 |
|---|---|---|
url | string | データベース URL |
authToken | string | ランタイム認証トークン(ローカルファイルでは任意) |
migrationAuthTokenEnv | string | マイグレーショントークン変数名(デフォルト TURSO_AUTH_TOKEN) |
libsql({
url: process.env.LIBSQL_DATABASE_URL,
authToken: process.env.LIBSQL_AUTH_TOKEN,
});
postgres(config)
接続プール付き PostgreSQL データベース。
| オプション | 型 | 説明 |
|---|---|---|
connectionString | string | PostgreSQL 接続 URL |
host | string | データベースホスト |
port | number | データベースポート |
database | string | データベース名 |
user | string | データベースユーザー |
password | string | データベースパスワード |
ssl | boolean | SSL を有効化 |
pool.min | number | プール最小サイズ(デフォルト: 0) |
pool.max | number | プール最大サイズ(デフォルト: 10) |
pool.connectionTimeoutMillis | number | 接続待ち最大時間(pg デフォルト: 0、タイムアウトなし) |
pool.idleTimeoutMillis | number | アイドルクライアント存続時間(pg デフォルト: 10,000 ms) |
migrationConnectionStringEnv | string | マイグレーション接続文字列変数名(デフォルト DATABASE_URL) |
次の例は接続文字列で接続します。
postgres({ connectionString: process.env.DATABASE_URL });
d1(config)
Cloudflare D1 データベース。@emdash-cms/cloudflare からインポートします。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
binding | string | — | wrangler.jsonc の D1 バインディング名 |
session | string | "disabled" | 読み取りレプリケーションモード: "disabled"、"auto"、"primary-first" |
bookmarkCookie | string | "__em_d1_bookmark" | セッションブックマーク用 Cookie 名 |
coalesce | boolean | false | 同一イベントループターン内の同時読み取りをバッチ化。"disabled" 以外のセッションモードが必要 |
次の例は基本バインディングと読み取りレプリカ有効の例です。
// 基本
d1({ binding: "DB" });
// 読み取りレプリカあり
d1({ binding: "DB", session: "auto" });
session が "auto" または "primary-first" の場合、EmDash は D1 Sessions API で読み取りクエリを近くのレプリカへルーティングします。認証済みユーザーはブックマークベースの read-your-writes 一貫性を得ます。詳細は データベースオプション — 読み取りレプリカ を参照してください。
hyperdrive(config?)
Cloudflare Hyperdrive バインディング経由の PostgreSQL。このアダプターは @emdash-cms/cloudflare からインポートします。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
binding | string | "HYPERDRIVE" | クエリキャッシュ無効のプライマリ Hyperdrive バインディング |
cachedBinding | string | — | 匿名公開読み取り向けの任意の第 2 キャッシュ有効バインディング |
preferUncachedAfterWriteMs | number | 60_000 | cachedBinding 設定時、コンテンツ書き込み後に公開読み取りがプライマリを使う時間 |
migrationConnectionStringEnv | string | プライマリバインディングから派生 | emdash migrate で使う直接 PostgreSQL URL を含む環境変数 |
max | number | 5 | 1 Worker isolate から Hyperdrive への最大接続数 |
次の例は、認証リクエストと書き込みを非キャッシュバインディング経由にルーティングし、匿名公開読み取りはキャッシュバインディングを使えます。
hyperdrive({
binding: "HYPERDRIVE",
cachedBinding: "HYPERDRIVE_CACHED",
preferUncachedAfterWriteMs: 60_000,
});
両方のバインディングは同一データベースを指す必要があります。pg 8.16.3 以降をインストールし、nodejs_compat 互換フラグを有効化し、デプロイメントマイグレーション用の直接データベース URL を設定してください。Worker とマイグレーションの完全セットアップは データベースオプション: Hyperdrive を参照してください。
durableObjects(config)
CMS を SQLite バックエンドの 1 つの Durable Object に保存します。このアダプターは @emdash-cms/cloudflare からインポートします。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
binding | string | 必須 | EmDashDB クラス用 Durable Object 名前空間バインディング |
name | string | "emdash" | シングルトンオブジェクト名。1 バインディング背後で複数 DB を分離するときのみ変更 |
session | string | "disabled" | "auto" は匿名読み取りをレプリカへ、書き込みをプライマリへルーティング |
bookmarkCookie | string | "__em_do_bookmark" | "auto" モードでの read-your-writes 一貫性用 Cookie |
durableObjects({ binding: "DB_DO", session: "auto" });
レプリカルーティングには experimental と replica_routing 互換フラグに加え、wrangler.jsonc の Durable Object クラスとマイグレーションエントリが必要です。
previewDatabase(config)
プレビューセッションごとに Durable Object 内に分離スナップショット DB を 1 つ作成します。唯一のオプションは必須の binding 名です。
previewDatabase({ binding: "PREVIEW_DB" });
このアダプターはプレビューインフラ向けで、本番サイトのプライマリ DB ではありません。
playgroundDatabase(config)
プレイグラウンドセッションごとに Durable Object 内に書き込み可能なシード済み DB を 1 つ作成します。playground 統合オプションと組み合わせます。
playgroundDatabase({ binding: "PLAYGROUND_DB" });
必須の binding はプレイグラウンド Durable Object 名前空間を識別します。このアダプターは使い捨てデモサイト専用です。
ストレージアダプター
local と s3 は emdash/astro から、r2 アダプターは @emdash-cms/cloudflare からインポートします。
import emdash, { local, s3 } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
local(config)
ローカルファイルシステムストレージ。次の例はローカルディレクトリからアップロードを配信します。
| オプション | 型 | 説明 |
|---|---|---|
directory | string | ディレクトリパス |
baseUrl | string | ファイル配信用ベース URL |
local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
r2(config)
Cloudflare R2 バインディング。次の例は公開 URL 付き R2 バインディングを使用します。
| オプション | 型 | 説明 |
|---|---|---|
binding | string | R2 バインディング名 |
publicUrl | string | 任意の公開 URL |
r2({
binding: "MEDIA",
publicUrl: "https://pub-xxxx.r2.dev",
});
s3(config?)
S3 互換ストレージ。すべての設定フィールドは任意です。s3({...}) から省略されたフィールドは、Node プロセス起動時に対応する S3_* 環境変数から解決されます。明示値は常に優先されます。
設定と環境値をマージした後、endpoint と bucket は必須です。認証情報のどちらか一方でも設定されていれば、accessKeyId と secretAccessKey の両方が必須です。不足値は MISSING_S3_CONFIG エラーコードで起動失敗します。
前提条件: プロジェクトに @aws-sdk/client-s3 と @aws-sdk/s3-request-presigner をインストールしてください。EmDash コアは AWS SDK を同梱しません。詳細は ストレージオプション: S3 互換ストレージ を参照してください。
| オプション | 型 | 説明 |
|---|---|---|
endpoint | string | S3 エンドポイント URL(S3_ENDPOINT) |
bucket | string | バケット名(S3_BUCKET) |
accessKeyId | string | アクセスキー(S3_ACCESS_KEY_ID) |
secretAccessKey | string | シークレットキー(S3_SECRET_ACCESS_KEY) |
region | string | リージョン、デフォルト "auto"(S3_REGION) |
publicUrl | string | 任意の CDN URL(S3_PUBLIC_URL) |
次の例は、環境からすべて解決する、設定と環境を混在する、すべて明示する、の 3 パターンです。
// すべてのフィールドを S3_* 環境変数から(Node コンテナデプロイメント)
s3()
// 混在: CDN は設定、残りは環境変数
s3({ publicUrl: "https://cdn.example.com" })
// すべて明示
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",
})
ランタイム環境変数解決は Node 専用機能です。Cloudflare Workers では、シークレットと変数は process.env ではなく fetch ハンドラーの env パラメーター経由で公開されるため、S3_* 環境変数は拾われません。Workers デプロイメントでは r2(config) アダプターを使うか、s3({...}) に明示値を渡してください。詳細は ストレージオプション を参照してください。
オブジェクトキャッシュアダプター
次のいずれかを objectCache オプションに渡します。
kvCache(config)
すべての isolate で共有される Cloudflare KV バックエンド。@emdash-cms/cloudflare からインポートします。
kvCache({
binding: "CACHE", // KV バインディング名(必須)
defaultTtl: 3600, // エントリ TTL(秒、任意、KV 最小 60)
revalidate: 1000, // isolate 間の鮮度ウィンドウ(ms、任意)
timeout: 2000, // miss 前の操作タイムアウト(ms、任意、0 で無効)
keyPrefix: "em", // キャッシュキープレフィックス(任意)
})
memoryCache(config?)
Node.js と開発向けのプロセス内バックエンド。emdash/astro からインポートします。
memoryCache({
defaultTtl: 3600, // エントリ TTL(秒、任意)
revalidate: 1000, // 鮮度ウィンドウ(ms、任意)
maxEntries: 1000, // 退避前の最大キャッシュキー数(任意)
keyPrefix: "em", // キャッシュキープレフィックス(任意)
})
セットアップと動作は オブジェクトキャッシュ を参照してください。
認証とサンドボックスアダプター
これらのアダプターは auth と sandboxRunner 統合オプション用の値を返します。
access(config)
組み込みパスキーログインを Cloudflare Access 認証に置き換えます。@emdash-cms/cloudflare からインポートし、結果を auth に渡します。
import { access } from "@emdash-cms/cloudflare";
emdash({
auth: access({
teamDomain: "myteam.cloudflareaccess.com",
audienceEnvVar: "CF_ACCESS_AUDIENCE",
}),
});
teamDomain は必須です。アダプターは audience または audienceEnvVar で名付けられた変数からアプリケーション audience を読み取れます。autoProvision、defaultRole、syncRoles、roleMapping も受け付けます。auth オプションにデフォルトとロール動作が記載されています。
sandbox()
プラグインサンドボックスランナーとして Cloudflare Worker Loader を選択します。@emdash-cms/cloudflare からインポートし、戻り値を sandboxRunner に渡します。
import { sandbox } from "@emdash-cms/cloudflare";
emdash({
sandboxRunner: sandbox(),
});
サイトには Worker Loader バインディングとプラグインブリッジエントリポイントも必要です。デプロイ設定は プラグインサンドボックス: Cloudflare Workers を参照してください。
メディアプロバイダーアダプター
メディアプロバイダー記述子を mediaProviders に渡します。組み込み Cloudflare プロバイダーは両方とも @emdash-cms/cloudflare からインポートします。
下記の各 *EnvVar オプションは環境変数名を指定します。プロバイダーは次の順で読み取ります: 同名の Cloudflare Workers バインディング、次に Node アダプター上の process.env。対応する直接オプション(accountId、accountHash、apiToken)は常に両方より優先されます。
cloudflareImages(config)
画像アセットの閲覧、アップロード、削除、配信に Cloudflare Images を追加します。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
accountId | string | CF_ACCOUNT_ID から | Cloudflare アカウント ID |
accountIdEnvVar | string | "CF_ACCOUNT_ID" | accountId 省略時に使う変数 |
accountHash | string | CF_IMAGES_ACCOUNT_HASH から | 配信 URL で使うアカウントハッシュ |
accountHashEnvVar | string | "CF_IMAGES_ACCOUNT_HASH" | accountHash 省略時に使う変数 |
apiToken | string | CF_IMAGES_TOKEN から | Cloudflare Images 読み取り・編集権限付きトークン |
apiTokenEnvVar | string | "CF_IMAGES_TOKEN" | apiToken 省略時に使う変数 |
deliveryDomain | string | imagedelivery.net | カスタム画像配信ホスト名 |
defaultVariant | string | "public" | 表示に使う画像バリアント |
mediaProviders: [cloudflareImages({ defaultVariant: "public" })];
cloudflareStream(config)
動画アセットの閲覧、検索、アップロード、削除、再生に Cloudflare Stream を追加します。
| オプション | 型 | デフォルト | 説明 |
|---|---|---|---|
accountId | string | CF_ACCOUNT_ID から | Cloudflare アカウント ID |
accountIdEnvVar | string | "CF_ACCOUNT_ID" | accountId 省略時に使う変数 |
apiToken | string | CF_STREAM_TOKEN から | Cloudflare Stream 読み取り・編集権限付きトークン |
apiTokenEnvVar | string | "CF_STREAM_TOKEN" | apiToken 省略時に使う変数 |
customerSubdomain | string | Cloudflare デフォルト | カスタム Stream 配信ホスト名 |
controls | boolean | true | プレイヤーコントロールを表示 |
autoplay | boolean | false | 自動再生 |
loop | boolean | false | ループ再生 |
muted | boolean | false、autoplay 時は true | ミュート再生 |
mediaProviders: [cloudflareStream({ controls: true })];
必要なバインディングとレンダリングコンポーネントは メディアライブラリ: メディアプロバイダー を参照してください。
Astro キャッシュアダプター
cloudflareCache(config?)
レガシーアダプターは、Workers Cache API にレスポンスを保存し、Cloudflare REST API でキャッシュタグをパージする Astro cache.provider を返します。
import { cloudflareCache } from "@emdash-cms/cloudflare";
export default defineConfig({
cache: {
provider: cloudflareCache(),
},
});
cacheName(デフォルト "emdash")と bookmarkCookie(デフォルト "__em_d1_bookmark")に加え、タグ別パージ用に zoneId または zoneIdEnvVar、apiToken または apiTokenEnvVar を受け付けます。デフォルト変数名は CF_ZONE_ID と CF_CACHE_PURGE_TOKEN です。
Live コレクション
src/live.config.ts で EmDash ローダーを設定します。
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({
loader: emdashLoader(),
}),
};
ローダーオプション
emdashLoader() 関数は引数を取りません。
emdashLoader();
環境変数
EmDash は次の環境変数を尊重します。
| 変数 | 説明 |
|---|---|
EMDASH_SITE_URL | 公開ブラウザ向けオリジン(SITE_URL にフォールバック) |
EMDASH_ALLOWED_ORIGINS | パスキー検証が受け入れる追加オリジンのカンマ区切りリスト(マルチサブドメインデプロイメント)。 |
EMDASH_DATABASE_URL | データベース URL の上書き |
EMDASH_ENCRYPTION_KEY | プラグインシークレットを保存時暗号化するキー。オペレーター提供 — データベースには保存されません。 |
EMDASH_PREVIEW_SECRET | プレビュー HMAC シークレットの任意上書き。未設定時はサイトごとの安定値が生成され DB に保存されます。 |
EMDASH_IP_SALT | コメント投稿者 IP ハッシュソルトの任意上書き。未設定時はサイトごとの安定値が生成され DB に保存されます。 |
EMDASH_AUTH_SECRET | レガシー。設定時は IP ソルトソースとして使用。既存インストールはアップグレード後も安定したコメント投稿者 IP ハッシュを保つため維持してください。 |
EMDASH_TURNSTILE_SECRET_KEY | Cloudflare Turnstile シークレットキー(TURNSTILE_SECRET_KEY にフォールバック)。設定時、コメント送信には有効な Turnstile トークンが必要 — <CommentForm> の turnstileSiteKey prop と組み合わせてください。 |
EMDASH_URL | スキーマ同期用のリモート EmDash URL |
暗号化キーは次のコマンドで生成します。
npx emdash secrets generate
package.json の設定
テンプレートとサイトは package.json の emdash キー下に任意メタデータを宣言できます。
{
"emdash": {
"label": "My Blog Template",
"schema": ".emdash/schema.sql",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev"
}
}
| オプション | 説明 |
|---|---|
label | 表示用テンプレート名 |
schema | emdash init が読む任意の SQL スキーマ |
seed | シード JSON ファイルのパス |
url | 非推奨 emdash dev --types フローで使うリモート URL |
TypeScript の設定
ローカル開発中、Astro 統合はプロジェクトルートに emdash-env.d.ts を生成し、スキーマ変更後に更新します。このファイルは emdash モジュールを拡張するため、標準の getEmDashCollection() と getEmDashEntry() インポートはパスエイリアスなしでローカルコレクションフィールドを推論します。
別コマンド emdash types は実行中のローカルまたはリモートインスタンスからスキーマを取得し、デフォルトで .emdash/types.ts に書き込みます。アプリケーションコードがそのスタンドアロン出力を直接インポートするときだけエイリアスを追加してください。
{
"compilerOptions": {
"paths": {
"@emdash-cms/types": ["./.emdash/types.ts"]
}
}
}
スタンドアロンのリモートスキーマ型は次のコマンドで生成します。
npx emdash types