EmDash は、コンテンツのクエリやプレビュー、設定、メニュー、タクソノミー、ウィジェットエリア、セクション、検索を扱うための関数をエクスポートします。
コンテンツクエリ
EmDash のクエリ関数は、Astro の ライブコンテンツコレクション パターンに従い、エレガントなエラーハンドリングのために { entries, error } または { entry, error } を返します。
getEmDashCollection()
コレクションからすべてのエントリを取得します。次の例は、すべての投稿を読み込み、エラーをチェックします:
import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) {
console.error("Failed to load posts:", error);
}
パラメータ
| パラメータ | 型 | 説明 |
|---|---|---|
collection | string | コレクションスラッグ |
options | CollectionFilter | オプションのフィルターオプション |
オプション
options パラメータは次のフィルターを受け入れます:
interface CollectionFilter {
status?: "draft" | "published" | "archived";
limit?: number;
where?: Record<string, string | string[]>; // Filter by field or taxonomy
}
戻り値
関数は CollectionResult に解決されます:
interface CollectionResult<T> {
entries: ContentEntry<T>[]; // Empty array if error or none found
error?: Error; // Set if query failed
}
例
次の例は、ステータスとタクソノミーでフィルタリングし、結果を制限し、エラーを処理します:
// Get all published posts
const { entries: posts } = await getEmDashCollection("posts", {
status: "published",
});
// Get latest 5 posts
const { entries: latest } = await getEmDashCollection("posts", {
limit: 5,
status: "published",
});
// Filter by taxonomy
const { entries: newsPosts } = await getEmDashCollection("posts", {
status: "published",
where: { category: "news" },
});
// Handle errors
const { entries, error } = await getEmDashCollection("posts");
if (error) {
return new Response("Server error", { 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 if not found
error?: Error; // Set only for actual errors, not "not found"
isPreview: boolean; // true if draft content is being served
}
例
次の例は、スラッグと ID で取得し、プレビュー状態を読み取り、エラーと「見つからない」を区別します:
// Get by slug
const { entry: post } = await getEmDashEntry("posts", "hello-world");
// Get by ID
const { entry: post } = await getEmDashEntry("posts", "01HXK5MZSN0FVXT2Q3KPRT9M7D");
// Preview is automatic — isPreview is true when a valid _preview token is present
const { entry, isPreview, error } = await getEmDashEntry("posts", slug);
// Handle errors vs not-found
if (error) {
return new Response("Server error", { status: 500 });
}
if (!entry) {
return Astro.redirect("/404");
}
コンテンツタイプ
ContentEntry
クエリ関数は次の形式でエントリを返します:
interface ContentEntry<T = Record<string, unknown>> {
id: string;
data: T;
edit: EditProxy; // Visual editing annotations
}
edit プロキシはビジュアル編集アノテーションを提供します。インライン編集を有効にするために、要素に展開します: {...entry.edit.title}。本番環境では、これは出力を生成しません。
data オブジェクトには、すべてのコンテンツフィールドとシステムフィールドが含まれています:
id- 一意の識別子slug- URL フレンドリーな識別子status- “draft” | “published” | “archived”createdAt- ISO タイムスタンプupdatedAt- ISO タイムスタンプpublishedAt- ISO タイムスタンプまたは null- コレクションスキーマで定義されたすべてのカスタムフィールド
プレビューシステム
generatePreviewToken()
ドラフトコンテンツのプレビュートークンを生成します。次の例は、1 時間で期限切れになるトークンを作成します:
import { generatePreviewToken } from "emdash";
const token = await generatePreviewToken({
contentId: "posts:01HXK5MZSN...",
secret: process.env.EMDASH_ADMIN_SECRET,
expiresIn: 3600, // 1 hour
});
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 is "collection:id" format, e.g. "posts:my-draft-post"
}
isPreviewRequest()
リクエストにプレビュートークンが含まれているかどうかを確認し、それを読み取ります:
import { isPreviewRequest, getPreviewToken } from "emdash";
if (isPreviewRequest(Astro.url)) {
const token = getPreviewToken(Astro.url);
// Verify and show preview content
}
コンテンツコンバーター
Portable Text と ProseMirror 形式の間で変換します:
import { prosemirrorToPortableText, portableTextToProsemirror } from "emdash";
// From ProseMirror (editor) to Portable Text (storage)
const portableText = prosemirrorToPortableText(prosemirrorDoc);
// From Portable Text to ProseMirror
const prosemirrorDoc = portableTextToProsemirror(portableText);
サイト設定
getSiteSettings と getSiteSetting でサイト全体の設定を読み取ります:
import { getSiteSettings, getSiteSetting } from "emdash";
// Get all settings
const settings = await getSiteSettings();
// Get single setting
const title = await getSiteSetting("title");
設定はランタイム API から読み取り専用です。更新するには管理 API を使用してください。
メニュー
ナビゲーションメニューを取得し、ネストされた子を含むアイテムを反復処理します:
import { getMenu, getMenus } from "emdash";
// Get all menus
const menus = await getMenus();
// Get specific menu with items
const primaryMenu = await getMenu("primary");
if (primaryMenu) {
primaryMenu.items.forEach(item => {
console.log(item.label, item.url);
// Nested items for dropdowns
item.children.forEach(child => console.log(" -", child.label));
});
}
タクソノミー
タクソノミーの用語、単一の用語、エントリの用語、または用語によるエントリを取得します:
import { getTaxonomyTerms, getTerm, getEntryTerms, getEntriesByTerm } from "emdash";
// Get all terms for a taxonomy (tree structure for hierarchical)
const categories = await getTaxonomyTerms("category");
// Get single term
const news = await getTerm("category", "news");
// Get terms assigned to a content entry
const postCategories = await getEntryTerms("posts", "post-123", "category");
// Get entries with a specific term
const newsPosts = await getEntriesByTerm("posts", "category", "news");
ウィジェットエリア
ウィジェットエリアとそれに含まれるウィジェットを取得します:
import { getWidgetArea, getWidgetAreas } from "emdash";
// Get all widget areas
const areas = await getWidgetAreas();
// Get specific widget area with widgets
const sidebar = await getWidgetArea("sidebar");
if (sidebar) {
sidebar.widgets.forEach(widget => {
console.log(widget.type, widget.title);
});
}
セクション
セクションを取得してフィルタリングします:
import { getSection, getSections } from "emdash";
// Get all sections (paginated)
const { items, nextCursor } = await getSections();
// Filter sections
const { items: themeSections } = await getSections({ source: "theme" });
const { items: results } = await getSections({ search: "newsletter" });
// Get a single section by slug
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() resolves to { items, nextCursor? }
results.items.forEach(result => {
console.log(result.title);
console.log(result.snippet); // Contains <mark> tags
console.log(result.score);
});
エラーハンドリング
EmDash は特定の失敗を処理するためのエラークラスをエクスポートします。次の例は、検証とスキーマのエラーをキャッチします:
import {
EmDashDatabaseError,
EmDashValidationError,
EmDashStorageError,
SchemaError,
} from "emdash";
try {
await repo.create({ ... });
} catch (error) {
if (error instanceof EmDashValidationError) {
console.error("Validation failed:", error.message);
}
if (error instanceof SchemaError) {
console.error("Schema error:", error.code, error.details);
}
}