EmDash 透過兩個檔案進行設定:用於整合的 astro.config.mjs 以及用於內容集合的 src/live.config.ts。
Astro 整合
將 EmDash 設定為 Astro 整合:
import { defineConfig } from "astro/config";
import emdash, { local, r2, s3 } from "emdash/astro";
import { sqlite, libsql, d1 } from "emdash/db";
export default defineConfig({
integrations: [
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
}),
plugins: [],
}),
],
});
整合選項
database
必填。 資料庫配接器設定。
// 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
必填。 媒體儲存配接器設定。
// 本地檔案系統(開發用)
storage: local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
// R2 繫結(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
});
詳見儲存選項。
plugins
選用。 EmDash 外掛陣列。
import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];
auth
選用。 驗證設定。
auth: {
// 自助註冊設定
selfSignup: {
domains: ["example.com"],
defaultRole: 20, // Contributor
},
// OAuth 提供者
oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
},
// 工作階段設定
session: {
maxAge: 30 * 24 * 60 * 60, // 30 天
sliding: true, // 活動時重設到期時間
},
// 或使用 Cloudflare Access(獨佔模式)
cloudflareAccess: {
teamDomain: "myteam.cloudflareaccess.com",
audience: "your-app-audience-tag",
autoProvision: true,
defaultRole: 30,
syncRoles: false,
roleMapping: {
"Admins": 50,
"Editors": 40,
},
},
}
auth.selfSignup
允許電子郵件網域符合的使用者自行註冊。
| 選項 | 類型 | 預設值 | 說明 |
|---|---|---|---|
domains | string[] | [] | 允許的電子郵件網域 |
defaultRole | number | 20 | 自助註冊的角色 |
selfSignup: {
domains: ["example.com", "acme.org"],
defaultRole: 20, // Contributor
}
auth.oauth
設定 OAuth 登入提供者。
oauth: {
github: {
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
},
google: {
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
},
}
auth.session
工作階段設定。
| 選項 | 類型 | 預設值 | 說明 |
|---|---|---|---|
maxAge | number | 2592000(30 天) | 工作階段存活時間(秒) |
sliding | boolean | true | 活動時重設到期時間 |
auth.cloudflareAccess
使用 Cloudflare Access 作為驗證提供者,取代通行密鑰。
| 選項 | 類型 | 預設值 | 說明 |
|---|---|---|---|
teamDomain | string | 必填 | 你的 Access 團隊網域 |
audience | string | 必填 | 應用程式 Audience (AUD) 標籤 |
autoProvision | boolean | true | 首次登入時建立使用者 |
defaultRole | number | 30 | 新使用者的預設角色 |
syncRoles | boolean | false | 每次登入時更新角色 |
roleMapping | object | — | 將 IdP 群組對應到角色 |
siteUrl
選用。 站台面向瀏覽器的公開 origin(scheme + host + 選用 port,無路徑)。
在 TLS 終止反向代理後方,Astro.url 會傳回內部位址(http://localhost:4321)而非公開位址(https://cms.example.com)。這會導致通行密鑰、CSRF origin 比對、OAuth 重新導向、登入重新導向、MCP 探索、快照匯出、sitemap、robots.txt 與 JSON-LD 結構化資料出錯。設定 siteUrl 即可一次修正所有問題。
整合在載入時驗證此值:必須是具有 http: 或 https: 協定的有效 URL,並正規化為 origin(路徑會被移除)。
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 在執行時期才設定的容器部署非常實用。
反向代理設定
Astro 只在公開主機被允許時才會反映 X-Forwarded-*。為使用者存取的主機名稱(與 scheme)設定 security.allowedDomains。在 astro dev 中,新增相符的 vite.server.allowedHosts 以便 Vite 接受代理的 Host 標頭。
優先修正 allowedDomains(以及轉發的標頭);當重建的 URL 仍然偏離瀏覽器 origin 時(通常在前方終止 TLS 而上游請求保持 http:// 時),才使用 siteUrl。
在 TLS 前方終止的情況下,將開發伺服器繫結到 loopback(astro dev --host 127.0.0.1)通常已足夠:代理在本地連線,而 siteUrl 與公開的 HTTPS origin 匹配。
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",
}),
],
});
資料庫配接器
從 emdash/db 匯入:
import { sqlite, libsql, postgres, d1 } from "emdash/db";
sqlite(config)
使用 better-sqlite3 的 SQLite 資料庫。
| 選項 | 類型 | 說明 |
|---|---|---|
url | string | 帶有 file: 前綴的檔案路徑 |
sqlite({ url: "file:./data.db" });
libsql(config)
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 | "__ec_d1_bookmark" | 工作階段書籤的 Cookie 名稱 |
// 基本
d1({ binding: "DB" });
// 搭配讀取複本
d1({ binding: "DB", session: "auto" });
當 session 為 "auto" 或 "primary-first" 時,EmDash 使用 D1 Sessions API 將讀取查詢路由到附近的複本。已驗證的使用者可獲得基於書籤的「讀取自己寫入的資料」一致性。詳見資料庫選項 — 讀取複本。
儲存配接器
從 emdash/astro 匯入:
import emdash, { local, r2, s3 } from "emdash/astro";
local(config)
本地檔案系統儲存。
| 選項 | 類型 | 說明 |
|---|---|---|
directory | string | 目錄路徑 |
baseUrl | string | 提供檔案的基礎 URL |
local({
directory: "./uploads",
baseUrl: "/_emdash/api/media/file",
});
r2(config)
Cloudflare 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 核心不包含 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) |
// 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 (unchanged from before)
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 handler 的 env 參數暴露,而非 process.env,因此 S3_* 環境變數不會被讀取。Workers 部署應使用 r2(config) 配接器,或向 s3({...}) 傳入明確值。詳見儲存選項。
Live Collections
在 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 | 面向瀏覽器的公開 origin(回退至 SITE_URL) |
EMDASH_DATABASE_URL | 覆寫資料庫 URL |
EMDASH_AUTH_SECRET | 通行密鑰驗證的密鑰 |
EMDASH_PREVIEW_SECRET | 預覽權杖產生的密鑰 |
EMDASH_URL | 用於結構描述同步的遠端 EmDash URL |
使用以下命令產生驗證密鑰:
npx emdash auth secret
package.json 設定
package.json 中的選用設定:
{
"emdash": {
"label": "My Blog Template",
"description": "A clean, minimal blog template",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev",
"preview": "https://emdash-blog.pages.dev"
}
}
| 選項 | 說明 |
|---|---|
label | 範本的顯示名稱 |
description | 範本說明 |
seed | 種子 JSON 檔案的路徑 |
url | 用於結構描述同步的遠端 URL |
preview | 範本預覽的示範網站 URL |
TypeScript 設定
EmDash 在 .emdash/types.ts 中產生型別。加入到你的 tsconfig.json:
{
"compilerOptions": {
"paths": {
"@emdash-cms/types": ["./.emdash/types.ts"]
}
}
}
產生型別:
npx emdash types