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 兼容(任意平台)
storage: s3()
详见存储选项。
objectCache
可选。 将内容和配置查询结果缓存在键/值存储中,使读取无需每次请求都查询数据库。省略时禁用:
// Cloudflare KV
import { kvCache } from "@emdash-cms/cloudflare";
objectCache: kvCache({ binding: "CACHE" });
// 内存(Node.js / 开发用)
import { memoryCache } from "emdash/astro";
objectCache: memoryCache();
plugins
可选。 EmDash 插件数组:
import seoPlugin from "@emdash-cms/plugin-seo";
plugins: [seoPlugin()];
fonts
可选。 管理界面字体配置。
默认情况下,EmDash 通过 Astro Font API 加载 Noto Sans。字体在构建时从 Google 下载并自托管。基础字体涵盖拉丁、西里尔、希腊、天城体和越南文字。
要添加额外的书写系统支持,传递脚本名称:
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。
设为 false 以完全禁用字体注入并使用系统字体:
emdash({ fonts: false })
auth
可选。 认证适配器。EmDash 内置登录使用通行密钥;设置 auth 会将其替换为外部提供者:
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) 标签 |
audienceEnvVar | string | "CF_ACCESS_AUDIENCE" | 运行时读取 audience 标签的环境变量 |
autoProvision | boolean | true | 首次登录时创建 EmDash 用户 |
defaultRole | number | 30 | 未被 roleMapping 匹配的用户的角色级别 |
syncRoles | boolean | false | 每次登录时重新应用 roleMapping 而非仅在配置时 |
roleMapping | object | — | 将 IdP 组名映射到 EmDash 角色级别 |
authProviders
可选。 可插拔登录提供者数组:
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 协议网络)。无需环境变量。
siteUrl
可选。 网站的公开浏览器端源(方案 + 主机 + 可选端口,无路径)。
在 TLS 终端反向代理 后面,Astro.url 返回内部地址而非公开地址。设置 siteUrl 一次性修复通行密钥、CSRF、OAuth 重定向等所有问题。
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。
多源通行密钥验证
通过 allowedOrigins 或 EMDASH_ALLOWED_ORIGINS 环境变量声明额外接受的源:
emdash({
siteUrl: "https://example.com",
allowedOrigins: ["https://preview.example.com"],
})
反向代理设置
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 解析的信任头:
emdash({
trustedProxyHeaders: ["x-real-ip"],
});
maxUploadSize
可选。 媒体文件上传的最大允许大小(字节)。默认 52_428_800(50 MB):
emdash({
maxUploadSize: 100 * 1024 * 1024, // 100 MB
});
toolbar
可选。 控制编辑器工具栏的交付方式。默认 "server"。
| 值 | 行为 |
|---|---|
"server"(默认) | 工具栏被服务端注入到每个为认证编辑者渲染的 HTML 响应中。 |
"client" | 公开 HTML 对所有访问者相同。小的引导脚本显示 “Edit” 按钮。 |
false | 从不渲染工具栏或引导脚本。 |
experimental
可选。 行为可能在次要版本中更改的选择性功能。
experimental.registry
可选。 将管理仪表盘的插件浏览和安装流程指向联邦插件注册表。
emdash({
sandboxRunner: "@emdash-cms/sandbox-cloudflare",
experimental: {
registry: {
aggregatorUrl: "https://registry.emdashcms.com",
acceptLabelers: "did:plc:emdashverification",
policy: {
minimumReleaseAge: "48h",
minimumReleaseAgeExclude: ["did:plc:yourfirstpartydid"],
},
},
},
});
数据库适配器
import { sqlite, libsql, postgres } from "emdash/db";
sqlite(config)
| 选项 | 类型 | 描述 |
|---|---|---|
url | string | 带 file: 前缀的文件路径 |
libsql(config)
| 选项 | 类型 | 描述 |
|---|---|---|
url | string | 数据库 URL |
authToken | string | 认证令牌(本地文件可选) |
postgres(config)
| 选项 | 类型 | 描述 |
|---|---|---|
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) |
d1(config)
Cloudflare D1。从 @emdash-cms/cloudflare 导入。
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
binding | string | — | wrangler.jsonc 中的 D1 绑定名称 |
session | string | "disabled" | 读取复制模式 |
bookmarkCookie | string | "__em_d1_bookmark" | 会话书签的 Cookie 名称 |
存储适配器
import emdash, { local, s3 } from "emdash/astro";
import { r2 } from "@emdash-cms/cloudflare";
local(config)
| 选项 | 类型 | 描述 |
|---|---|---|
directory | string | 目录路径 |
baseUrl | string | 文件服务的基础 URL |
r2(config)
| 选项 | 类型 | 描述 |
|---|---|---|
binding | string | R2 绑定名称 |
publicUrl | string | 可选的公开 URL |
s3(config?)
S3 兼容存储。所有字段可选。
前提: 安装 @aws-sdk/client-s3 和 @aws-sdk/s3-request-presigner。
| 选项 | 类型 | 描述 |
|---|---|---|
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) |
对象缓存适配器
kvCache(config)
Cloudflare KV 后端。
kvCache({ binding: "CACHE", defaultTtl: 3600, revalidate: 1000, timeout: 2000, keyPrefix: "em" })
memoryCache(config?)
Node.js 进程内后端。
memoryCache({ defaultTtl: 3600, revalidate: 1000, maxEntries: 1000, keyPrefix: "em" })
实时集合
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({
loader: emdashLoader(),
}),
};
环境变量
| 变量 | 描述 |
|---|---|
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 盐源。 |
EMDASH_TURNSTILE_SECRET_KEY | Cloudflare Turnstile 密钥 |
EMDASH_URL | 模式同步用的远程 EmDash URL |
npx emdash secrets generate
package.json 配置
{
"emdash": {
"label": "My Blog Template",
"seed": ".emdash/seed.json",
"url": "https://my-site.pages.dev"
}
}
TypeScript 配置
{
"compilerOptions": {
"paths": {
"@emdash-cms/types": ["./.emdash/types.ts"]
}
}
}
npx emdash types