EmDashは2つのファイルで設定されます:統合用のastro.config.mjsとコンテンツコレクション用のsrc/live.config.tsです。
Astro統合
astro.config.mjsでEmDashをAstro統合として設定します:
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 (@emdash-cms/cloudflareからインポート)
database: d1({ binding: "DB" });
詳細についてはデータベースオプションを参照してください。
storage
必須。 メディアストレージアダプター設定。1つのアダプターを選択してください:
// ローカルファイルシステム (開発環境)
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", // オプション
});
詳細についてはストレージオプションを参照してください。
plugins
オプション。 EmDashプラグインの配列。次の例は1つのプラグインを登録します:
import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];
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 | — | アプリケーションオーディエンス(AUD)タグ。WorkersではaudienceEnvVarを優先してください。 |
audienceEnvVar | string | "CF_ACCESS_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プロトコルネットワーク)。環境変数は不要です。{ allowedDIDs, allowedHandles, defaultRole }を受け入れます。Atmosphereログインガイドを参照してください。
サードパーティパッケージは、同じAuthProviderDescriptor形式を使用して独自のプロバイダーを登録できます — ログインプロバイダーを参照してください。
siteUrl
オプション。 サイトの公開ブラウザ向けオリジン(スキーム + ホスト + オプションのポート、パスなし)。
TLS終端リバースプロキシの背後では、Astro.urlは公開アドレス(https://cms.example.com)ではなく内部アドレス(http://localhost:4321)を返します。これにより、パスキー、CSRFオリジンマッチング、OAuthリダイレクト、ログインリダイレクト、MCP検出、スナップショットエクスポート、サイトマップ、robots.txt、JSON-LD構造化データが壊れます。すべてを一度に修正するにはsiteUrlを設定してください。
統合はロード時にこの値を検証します:**http:またはhttps:**プロトコルを持つ有効なURLである必要があり、オリジンに正規化されます(パスは削除されます)。
次の例は公開オリジンを設定します:
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が実行時に設定されるコンテナデプロイメントに便利です。
マルチオリジンパスキー検証
siteUrlは単一の正規オリジンを定義します。同じEmDashデプロイメントが登録可能な親ドメインを共有する複数のホスト名(例:https://example.comとhttps://preview.example.com)でアクセス可能な場合、パスキー検証はsiteUrlと正確に一致しないオリジンのアサーションを拒否します — WebAuthnは同じrpIdの下のサブドメイン間でパスキーが有効であることを許可しているにもかかわらず。
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.allowedOriginsとconfig.siteUrlの両方がastro.config.mjsから来る場合 — コード内のタイプミスはビルドを失敗させます。 - 最初のパスキー検証時、いずれかの値が
EMDASH_ALLOWED_ORIGINSまたはEMDASH_SITE_URLから来る場合 — 環境の不一致は最初の検証試行時に500として表示されます。
リバースプロキシの設定
Astroは公開ホストが許可されている場合にのみ**X-Forwarded-*を反映します。ユーザーがヒットするホスト名(およびスキーム)に対してsecurity.allowedDomainsを設定してください。astro devでは、ViteがプロキシのHostヘッダーを受け入れるように、一致するvite.server.allowedHosts**を追加してください。
まず**allowedDomains(および転送されたヘッダー)を修正することを優先してください;再構築されたURLがブラウザオリジンからまだ乖離している場合(TLSが前で終了し、アップストリームリクエストが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
オプション。 許可される最大メディアファイルアップロードサイズ(バイト単位)。直接マルチパートアップロードと署名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で拒否されます。
データベースアダプター
emdash/dbからアダプターをインポートします:
import { sqlite, libsql, postgres } from "emdash/db";
sqlite(config)
better-sqlite3を使用するSQLiteデータベース。次の例はローカルファイルに接続します:
| オプション | 型 | 説明 |
|---|---|---|
url | string | file:プレフィックス付きのファイルパス |
sqlite({ url: "file:./data.db" });
libsql(config)
libSQLデータベース。次の例はリモートlibSQLデータベースに接続します:
| オプション | 型 | 説明 |
|---|---|---|
url | string | データベースURL |
authToken | string | 認証トークン(ローカルファイルではオプション) |
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) |
次の例は接続文字列で接続します:
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" | セッションブックマークのクッキー名 |
次の例は基本的なバインディングと読み取りレプリカを有効にしたものを示します:
// 基本
d1({ binding: "DB" });
// 読み取りレプリカを使用
d1({ binding: "DB", session: "auto" });
sessionが"auto"または"primary-first"の場合、EmDashはD1 Sessions APIを使用して読み取りクエリを近くのレプリカにルーティングします。認証されたユーザーは、ブックマークベースの読み取り後の書き込み一貫性を取得します。詳細についてはデータベースオプション — 読み取りレプリカを参照してください。
ストレージアダプター
emdash/astroからlocalとs3をインポートします。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_*環境変数から解決されます。明示的な値は常に優先されます。
前提条件: プロジェクトに@aws-sdk/client-s3と@aws-sdk/s3-request-presignerをインストールしてください。
EmDash coreは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) |
次の例は、すべてのフィールドを環境から解決するか、設定と環境を混在させるか、すべてのフィールドを明示的に渡します:
// すべてのフィールドを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では、シークレットと変数はfetchハンドラーのenvパラメータを介して公開され、
process.envを介しては公開されないため、S3_*環境変数は取得されません。
Workersデプロイメントはr2(config)アダプターを使用するか、
s3({...})に明示的な値を渡す必要があります。詳細については
ストレージオプションを参照してください。
ライブコレクション
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シークレットのオプション上書き。未設定の場合、サイトごとの安定値が生成されデータベースに保存されます。 |
EMDASH_IP_SALT | コメンターIPハッシュソルトのオプション上書き。未設定の場合、サイトごとの安定値が生成されデータベースに保存されます。 |
EMDASH_AUTH_SECRET | レガシー。設定されている場合はIPソルトソースとして使用されます;既存のインストールはアップグレード時に安定したコメンターIPハッシュを保持するためにこれを保持する必要があります。 |
EMDASH_URL | スキーマ同期用のリモートEmDash URL |
次のコマンドで暗号化キーを生成します:
npx emdash secrets generate
package.json設定
テンプレートとサイトは、package.jsonのemdashキーの下にオプションのメタデータを宣言できます:
{
"emdash": {
"label": "My Blog Template",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev"
}
}
| オプション | 説明 |
|---|---|
label | 表示用のテンプレート名 |
seed | シードJSONファイルへのパス |
url | スキーマ同期用のリモートURL |
TypeScript設定
EmDashは.emdash/types.tsに型を生成します。tsconfig.jsonにパスエイリアスを追加します:
{
"compilerOptions": {
"paths": {
"@emdash-cms/types": ["./.emdash/types.ts"]
}
}
}
次のコマンドで型を生成します:
npx emdash types