EmDash 匯出用於查詢內容以及處理預覽、設定、選單、分類法、小工具區域、區塊和搜尋的函式。
內容查詢
EmDash 的查詢函式遵循 Astro 的即時內容集合模式,回傳 { entries, error } 或 { entry, error } 以實現優雅的錯誤處理。
getEmDashCollection()
取得集合中的所有條目。以下範例載入所有文章並檢查錯誤:
import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("載入文章失敗:", error);
}
參數
| 參數 | 型別 | 描述 |
|---|---|---|
collection | string | 集合識別符 |
options | CollectionFilter | 可選的篩選選項 |
選項
options 參數接受以下篩選器:
interface CollectionFilter {
status?: "draft" | "published" | "archived";
limit?: number;
cursor?: string; // 鍵集分頁 — 傳遞前一個 `nextCursor`
offset?: number; // 偏移分頁 — 跳過 N 個條目(與 `limit` 配合使用)
where?: Record<string, string | string[]>; // 按欄位或分類法篩選
}
回傳值
函式解析為 CollectionResult:
interface CollectionResult<T> {
entries: ContentEntry<T>[]; // 出錯或無結果時為空陣列
error?: Error; // 查詢失敗時設定
nextCursor?: string; // 下一個鍵集頁面的游標(如果有)
hasMore?: boolean; // 此頁面之後是否還有更多條目(當設定了 `limit` 時)
}
範例
以下範例按狀態和分類法篩選、限制結果並處理錯誤:
// 取得所有已發布的文章
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
// 取得最新的 5 篇文章
const { entries: latest } = await getEmDashCollection("posts", {
limit: 5,
status: "published",
});
// 按分類法篩選
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
// 帶編號的歸檔頁面(例如 /page/3)使用偏移分頁
const perPage = 20;
const page = Number(Astro.params.page ?? 1);
const { entries: pagePosts, hasMore } = await getEmDashCollection("posts", {
status: "published",
limit: perPage,
offset: (page - 1) * perPage,
orderBy: { published_at: "desc" },
});
// 處理錯誤
const { entries, error } = await getEmDashCollection("posts");
if (error) {
return new Response("伺服器錯誤", { status: 500 });
}
getEmDashEntry()
透過識別符或 ID 取得單一條目。以下範例載入一篇文章,如果不存在則重新導向:
import { getEmDashEntry } from "emdash";
const { entry: post, error } = await getEmDashEntry("posts", "my-post-slug");
if (!post) {
return Astro.redirect("/404");
}
參數
| 參數 | 型別 | 描述 |
|---|---|---|
collection | string | 集合識別符 |
slugOrId | string | 條目識別符或 ID |
options | { locale?: string } | 可選。用於識別符解析的語言環境 |
預覽模式自動處理 — 中介軟體偵測 _preview 權杖並透過 AsyncLocalStorage 提供草稿內容。可選的 options 參數僅接受用於識別符解析的 locale;預覽狀態不需要參數。
回傳值
函式解析為 EntryResult:
interface EntryResult<T> {
entry: ContentEntry<T> | null; // 未找到時為 null
error?: Error; // 僅在實際錯誤時設定,「未找到」不設定
isPreview: boolean; // 提供草稿內容時為 true
}
範例
以下範例透過識別符和 ID 取得、讀取預覽狀態,並區分錯誤和未找到:
// 透過識別符取得
const { entry: post } = await getEmDashEntry("posts", "hello-world");
// 透過 ID 取得
const { entry: post } = await getEmDashEntry("posts", "01HXK5MZSN0FVXT2Q3KPRT9M7D");
// 預覽是自動的 — 存在有效的 _preview 權杖時 isPreview 為 true
const { entry, isPreview, error } = await getEmDashEntry("posts", slug);
// 處理錯誤 vs 未找到
if (error) {
return new Response("伺服器錯誤", { status: 500 });
}
if (!entry) {
return Astro.redirect("/404");
}
內容型別
ContentEntry
查詢函式以以下形式回傳條目:
interface ContentEntry<T = Record<string, unknown>> {
id: string;
data: T;
edit: EditProxy; // 視覺化編輯註解
}
edit 代理提供視覺化編輯註解。將其展開到元素上以啟用內嵌編輯:{...entry.edit.title}。在生產環境中,這不會產生輸出。
data 物件包含所有內容欄位和系統欄位:
id- 唯一識別符slug- URL 友善的識別符status- “draft” | “published” | “archived”createdAt- ISO 時間戳記updatedAt- ISO 時間戳記publishedAt- ISO 時間戳記或 null- 加上集合結構描述中定義的所有自訂欄位
預覽系統
generatePreviewToken()
為草稿內容產生預覽權杖。以下範例建立一個一小時後過期的權杖:
import { generatePreviewToken } from "emdash";
const token = await generatePreviewToken({
contentId: "posts:01HXK5MZSN...",
secret: process.env.EMDASH_ADMIN_SECRET,
expiresIn: 3600, // 1 小時
});
verifyPreviewToken()
驗證預覽權杖並讀取其有效載荷:
import { verifyPreviewToken } from "emdash";
const result = await verifyPreviewToken({
token,
secret: process.env.EMDASH_ADMIN_SECRET,
});
if (result.valid) {
const { cid, exp, iat } = result.payload;
// cid 格式為 "collection:id",例如 "posts:my-draft-post"
}
isPreviewRequest()
檢查請求是否包含預覽權杖,然後讀取:
import { isPreviewRequest, getPreviewToken } from "emdash";
if (isPreviewRequest(Astro.url)) {
const token = getPreviewToken(Astro.url);
// 驗證並顯示預覽內容
}
內容轉換器
在 Portable Text 和 ProseMirror 格式之間轉換:
import { prosemirrorToPortableText, portableTextToProsemirror } from "emdash";
// 從 ProseMirror(編輯器)到 Portable Text(儲存)
const portableText = prosemirrorToPortableText(prosemirrorDoc);
// 從 Portable Text 到 ProseMirror
const prosemirrorDoc = portableTextToProsemirror(portableText);
站點設定
使用 getSiteSettings 和 getSiteSetting 讀取站點全域設定:
import { getSiteSettings, getSiteSetting } from "emdash";
// 取得所有設定
const settings = await getSiteSettings();
// 取得單一設定
const title = await getSiteSetting("title");
設定從執行時 API 是唯讀的。使用管理 API 來更新它們。
選單
取得導覽選單並迭代其項目,包括巢狀子項:
import { getMenu, getMenus } from "emdash";
// 取得所有選單
const menus = await getMenus();
// 取得特定選單及其項目
const primaryMenu = await getMenu("primary");
if (primaryMenu) {
primaryMenu.items.forEach(item => {
console.log(item.label, item.url);
// 下拉選單的巢狀項目
item.children.forEach(child => console.log(" -", child.label));
});
}
分類法
取得分類法術語、單一術語、條目的術語或按術語取得條目:
import { getTaxonomyTerms, getTerm, getEntryTerms, getEntriesByTerm } from "emdash";
// 取得分類法的所有術語(階層式為樹狀結構)
const categories = await getTaxonomyTerms("category");
// 取得單一術語
const news = await getTerm("category", "news");
// 取得分配給內容條目的術語
const postCategories = await getEntryTerms("posts", "post-123", "category");
// 取得具有特定術語的條目
const newsPosts = await getEntriesByTerm("posts", "category", "news");
小工具區域
取得小工具區域及其包含的小工具:
import { getWidgetArea, getWidgetAreas } from "emdash";
// 取得所有小工具區域
const areas = await getWidgetAreas();
// 取得特定小工具區域及其小工具
const sidebar = await getWidgetArea("sidebar");
if (sidebar) {
sidebar.widgets.forEach(widget => {
console.log(widget.type, widget.title);
});
}
區塊
取得區塊並篩選:
import { getSection, getSections } from "emdash";
// 取得所有區塊(分頁)
const { items, nextCursor } = await getSections();
// 篩選區塊
const { items: themeSections } = await getSections({ source: "theme" });
const { items: results } = await getSections({ search: "newsletter" });
// 透過識別符取得單一區塊
const cta = await getSection("newsletter-cta");
getSections(options?) 回傳 { items: Section[]; nextCursor?: string }。選項為 source("theme" | "user" | "import")、search、limit(預設 50,最大 100)和 cursor。
搜尋
跨集合執行全域搜尋。結果包含醒目標示的摘要片段:
import { search } from "emdash";
const results = await search("hello world", {
collections: ["posts", "pages"],
status: "published",
limit: 20,
});
// search() 解析為 { items, nextCursor? }
results.items.forEach(result => {
console.log(result.title);
console.log(result.snippet); // 包含 <mark> 標籤
console.log(result.score);
});
// 分頁:將前一個 nextCursor 作為 `cursor` 傳遞以取得下一頁。
// 沒有更多結果時 nextCursor 為 undefined。
if (results.nextCursor) {
const next = await search("hello world", {
collections: ["posts", "pages"],
limit: 20,
cursor: results.nextCursor,
});
}
錯誤處理
EmDash 匯出錯誤類別用於處理特定故障。以下範例捕獲驗證和結構描述錯誤:
import {
EmDashDatabaseError,
EmDashValidationError,
EmDashStorageError,
SchemaError,
} from "emdash";
try {
await repo.create({ ... });
} catch (error) {
if (error instanceof EmDashValidationError) {
console.error("驗證失敗:", error.message);
}
if (error instanceof SchemaError) {
console.error("結構描述錯誤:", error.code, error.details);
}
}