設定參考

本頁內容

EmDash 透過兩個檔案進行設定:整合設定檔 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

必需。 資料庫配接器設定。選擇一個配接器:

// 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", // 可選
});

// 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 外掛陣列。以下範例註冊了一個外掛:

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

plugins: [seoPlugin()];

fonts

可選。 管理介面字型設定。

預設情況下,EmDash 透過 Astro 字型 API 載入 Noto Sans。字型在建置時從 Google 下載並自主託管,因此沒有執行時 CDN 請求。基礎字型涵蓋拉丁文、西里爾文、希臘文、梵文和越南文字。

要新增對其他書寫系統的支援,請傳遞指令碼名稱。以下範例新增了阿拉伯語和日語:

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

可用的指令碼有 arabicarmenianbengalichinese-simplifiedchinese-traditionalchinese-hongkongdevanagariethiopicfarsigeorgiangujaratigurmukhihebrewjapanesekannadakhmerkoreanlaomalayalammyanmaroriyasinhalatamilteluguthaitibetan

每個指令碼對應到 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() 的選項:

選項類型預設值描述
teamDomainstring必需您的 Cloudflare Access 團隊網域名稱
audiencestring應用程式受眾(AUD)標籤。在 Workers 上,優先使用 audienceEnvVar
audienceEnvVarstring"CF_ACCESS_AUDIENCE"執行時讀取受眾標籤的環境變數
autoProvisionbooleantrue首次登入時建立 EmDash 使用者
defaultRolenumber30未被 roleMapping 比對的使用者的角色層級(參見使用者角色
syncRolesbooleanfalse每次登入時重新套用 roleMapping,而不是僅在設定時
roleMappingobject將 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 傳回內部位址(http://localhost:4321)而不是公開位址(https://cms.example.com)。這會破壞密鑰、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.comhttps://preview.example.com)下存取時,密鑰驗證會拒絕來源與 siteUrl 不完全相符的斷言 — 儘管 WebAuthn 允許密鑰在相同 rpId 下的子網域之間有效。

透過 astro.config.mjs 中的 allowedOriginsEMDASH_ALLOWED_ORIGINS 環境變數宣告其他接受的來源。規範的 siteUrl 仍然是 rpId 的來源;此處列出的條目在驗證時被接受。兩個來源在執行時合併,因此設定可以宣告穩定來源(版本控制、程式碼審查),而環境新增特定於環境的額外內容(例如臨時 PR 預覽)。

以下範例在設定中宣告一個額外的來源:

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.allowedOriginsconfig.siteUrl 都來自 astro.config.mjs 時 — 程式碼中的拼寫錯誤導致建置失敗。
  • 在首次密鑰驗證時,當任一值來自 EMDASH_ALLOWED_ORIGINSEMDASH_SITE_URL 時 — 環境不相符在首次驗證嘗試時顯示為 500。

反向代理設定

Astro 僅在允許公開主機時才反映 X-Forwarded-*。為使用者存取的主機名稱(和配置)設定 security.allowedDomains。在 astro dev 中,新增相符的 vite.server.allowedHosts,以便 Vite 接受代理的 Host 標頭。

優先修復 allowedDomains(和轉送的標頭);當重建的 URL 仍然與瀏覽器來源不同時(典型情況是 TLS 在前端終止,上游請求保持 http://)使用 siteUrl

在前端有 TLS 的情況下,將開發伺服器繫結到迴路(astro dev --host 127.0.0.1)通常就足夠了:代理本機連線,而 siteUrl 與公開 HTTPS 來源相符。

如果您的代理寫入用戶端 IP 標頭,請設定 trustedProxyHeaders,以便 EmDash 的速率限制可以使用真實的用戶端 IP,而不是將每個請求歸類到共享的「unknown」金鑰下。

以下設定為反向代理部署一起設定 allowedDomainsvite.server.allowedHostssiteUrl

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 或類似服務後面的自主託管部署中,將其設定為代理寫入的標頭,以便速率限制可以按真實用戶端 IP 分組,而不是將每個請求視為「unknown」。

以下範例信任由 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 資料庫。以下範例連線到本機檔案:

選項類型描述
urlstringfile: 前綴的檔案路徑
sqlite({ url: "file:./data.db" });

libsql(config)

libSQL 資料庫。以下範例連線到遠端 libSQL 資料庫:

選項類型描述
urlstring資料庫 URL
authTokenstring認證權杖(本機檔案可選)
libsql({
	url: process.env.LIBSQL_DATABASE_URL,
	authToken: process.env.LIBSQL_AUTH_TOKEN,
});

postgres(config)

帶連線集區的 PostgreSQL 資料庫。

選項類型描述
connectionStringstringPostgreSQL 連線 URL
hoststring資料庫主機
portnumber資料庫連接埠
databasestring資料庫名稱
userstring資料庫使用者
passwordstring資料庫密碼
sslboolean啟用 SSL
pool.minnumber最小集區大小(預設:0)
pool.maxnumber最大集區大小(預設:10)

以下範例使用連線字串連線:

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

d1(config)

Cloudflare D1 資料庫。從 @emdash-cms/cloudflare 匯入。

選項類型預設值描述
bindingstring來自 wrangler.jsonc 的 D1 繫結名稱
sessionstring"disabled"讀取複製模式:"disabled""auto""primary-first"
bookmarkCookiestring"__em_d1_bookmark"工作階段書籤的 cookie 名稱

以下範例顯示基本繫結和啟用讀取副本的繫結:

// 基本
d1({ binding: "DB" });

// 使用讀取副本
d1({ binding: "DB", session: "auto" });

session"auto""primary-first" 時,EmDash 使用 D1 Sessions API 將讀取查詢路由到附近的副本。經過身分驗證的使用者獲得基於書籤的讀後寫一致性。詳情請參閱資料庫選項 — 讀取副本

儲存配接器

emdash/astro 匯入 locals3r2 配接器從 @emdash-cms/cloudflare 匯入:

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

local(config)

本機檔案系統儲存。以下範例從本機目錄提供上傳:

選項類型描述
directorystring目錄路徑
baseUrlstring用於提供檔案的基本 URL
local({
	directory: "./uploads",
	baseUrl: "/_emdash/api/media/file",
});

r2(config)

Cloudflare R2 繫結。以下範例使用帶有公開 URL 的 R2 繫結:

選項類型描述
bindingstringR2 繫結名稱
publicUrlstring可選公開 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 相容儲存

選項類型描述
endpointstringS3 端點 URL(S3_ENDPOINT
bucketstring儲存桶名稱(S3_BUCKET
accessKeyIdstring存取金鑰(S3_ACCESS_KEY_ID
secretAccessKeystring密鑰(S3_SECRET_ACCESS_KEY
regionstring區域,預設 "auto"S3_REGION
publicUrlstring可選 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.jsonemdash 金鑰下宣告可選中繼資料:

{
	"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