JavaScript API リファレンス

このページ

このページでは、Astro のページ、レイアウト、コンポーネントが EmDash サイトを読み取り、表示するために使用する公開 API を扱います。emdash パッケージのルートからエクスポートされるすべてを網羅するものではありません。データベースのリポジトリ、API ハンドラー、マイグレーションユーティリティ、プラグイン作成用 API、その他のサーバー内部の実装には、それぞれ別のリファレンスがあるか、フレームワーク統合コード向けのものです。

このリファレンスのサイトテンプレート API 契約には、EmDash が保守している公式サイトテンプレートが emdash からインポートするすべての関数が載っています。MediaValue のような型のみのインポートは、該当するデータモデルのドキュメントで扱います。サイト作成者の役に立つ関連関数は同じセクションで説明しますが、無関係なルートエクスポートは対象外です。

サイトテンプレート API 契約

保守されているテンプレートは、次のランタイムヘルパーを呼び出します。

関数用途
decodeSlug検索の前に動的ルートパラメータをデコードする
getEmDashCollectionコレクション内のエントリを読み取り、絞り込む
getEmDashEntryID またはスラッグで 1 件のエントリを読み取る
getMenuWithCacheHintキャッシュ無効化用のヒント付きでナビゲーションメニューをレンダリングする
getSeoMetaエントリの SEO パネルの値とテンプレートのフォールバックを解決する
getSiteSettings公開されているサイトの基本情報とその他のグローバル設定を読み取る
getSiteSettingsWithCacheHintキャッシュ無効化用のヒント付きでグローバル設定を読み取る
getTaxonomyTermsWithCacheHintキャッシュ無効化用のヒント付きでタクソノミーのフィルターをレンダリングする
getTermsForEntriesエントリの一覧に対して 1 つのタクソノミーをまとめて読み込む
sanitizeHref保存済みのリンクをレンダリングする前に、安全でない URL スキームを拒否する
searchコレクションをまたいで公開済みコンテンツを検索する

コンテンツクエリ

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);
}

パラメータ

パラメータ型説明
collectionstringコレクションのスラッグ
optionsCollectionFilter任意のフィルターオプション

オプション

options パラメータは次のフィルターを受け付けます。

interface WhereRange {
	gt?: string;
	gte?: string;
	lt?: string;
	lte?: string;
}

interface CollectionFilter {
	status?: "draft" | "published" | "archived";
	limit?: number;
	cursor?: string; // Keyset pagination — pass a previous `nextCursor`
	offset?: number; // Offset pagination — skip N entries (use with `limit`)
	where?: Record<string, string | string[] | WhereRange>;
	orderBy?: Record<string, "asc" | "desc">;
	locale?: string;
}

cursor と offset は同時に指定できません。where のキーには、コンテンツフィールド、タクソノミー、byline を指定できます。順序付きの比較には範囲オブジェクトを使えます。

戻り値

この関数は CollectionResult に解決されます。

interface CollectionResult<T> {
	entries: ContentEntry<T>[]; // Empty array if error or none found
	error?: Error; // Set if query failed
	cacheHint: CacheHint; // Tags and last-modified time for Astro route caching
	nextCursor?: string; // Cursor for the next keyset page, if any
	hasMore?: boolean; // Whether more entries exist beyond this page (when `limit` is set)
}

例

次の例では、ステータスとタクソノミーで絞り込み、結果を制限し、エラーを処理します。

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

// Numbered archive page (e.g. /page/3) with offset pagination
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" },
});

// Handle errors
const { entries, error } = await getEmDashCollection("posts");
if (error) {
	return new Response("Server error", { status: 500 });
}

getEmDashEntry()

スラッグまたは ID で 1 件のエントリを取得します。次の例では、投稿を読み込み、存在しない場合はサイトの 404 ページをレンダリングします。

import { getEmDashEntry } from "emdash";

const { entry: post, error } = await getEmDashEntry("posts", "my-post-slug");

if (!post) {
	return Astro.rewrite("/404");
}

パラメータ

パラメータ型説明
collectionstringコレクションのスラッグ
slugOrIdstringエントリのスラッグまたは ID
options{ locale?: string; references?: ReferenceSelection }任意。スラッグの解決に使うロケールと、読み込む参照フィールド

プレビューモードは自動的に処理されます。リクエストに有効な _preview トークンが含まれている場合、クエリは下書きコンテンツを返します。プレビューの状態にパラメータは不要です。

references は、読み込む参照フィールドをフィールドのスラッグをキーにして指定します。true は既定の上限である 50 件で最初のページを要求します。オブジェクト形式では limit(最大 100)と、前のページから得た cursor を指定できます。省略したフィールドは読み込まれず、このオプションを省略した呼び出しでは参照クエリが一切実行されません。

戻り値

この関数は EntryResult に解決されます。

interface EntryResult<T, R> {
	entry: ContentEntry<T, R> | null; // null if not found
	error?: Error; // Set only for actual errors, not "not found"
	isPreview: boolean; // true if draft content is being served
	fallbackLocale?: string; // Set when locale fallback returned another locale
	cacheHint: CacheHint; // Tags and last-modified time for Astro route caching
}

例

次の例では、スラッグと 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.rewrite("/404");
}

getTranslations()

コレクションのスラッグとデータベース ID を指定して、1 件のエントリで利用可能な翻訳を取得します。

import { getTranslations } from "emdash";

const { translations, error } = await getTranslations("posts", post.data.id);

結果には、共有される translationGroup、translations 配列、任意の error が含まれます。各翻訳の概要には id、locale、slug、status が含まれます。

resolveEmDashPath()

ルーティング可能なコレクションに設定された URL パターンに対して、公開パス名を解決します。

import { resolveEmDashPath } from "emdash";

const result = await resolveEmDashPath("/blog/hello-world");

if (result) {
	console.log(result.collection, result.entry.data.title);
}

結果には、一致した collection、entry、ルートの params が含まれます。設定済みの URL パターンのどれにも一致しない場合、この関数は null を返します。

getEditMeta()

Portable Text の値に付与された、列挙不可のビジュアル編集用メタデータを読み取ります。

import { getEditMeta } from "emdash";

const meta = getEditMeta(post.data.content);

注釈の付いた値では { collection, id, field } を返し、注釈のない値では undefined を返します。

コンテンツ型

ContentEntry

クエリ関数は、次の形のエントリを返します。

interface ContentEntry<T = Record<string, unknown>, R = ReferencePages> {
	id: string;
	data: T;
	references?: R; // One page per reference field requested; absent otherwise
	edit: EditProxy; // Visual editing annotations
}

edit プロキシはビジュアル編集用の注釈を提供します。要素にスプレッドすると、インライン編集が有効になります: {...entry.edit.title}。編集モード以外では何も出力しません。

data オブジェクトには、すべてのコンテンツフィールドとシステムフィールドが含まれます。

  • id - 一意の識別子
  • slug - URL に使いやすい識別子
  • status - “draft” | “published” | “archived”
  • createdAt - 作成日時(Date)
  • updatedAt - 最終更新日時(Date)
  • publishedAt - 公開日時(Date または null)。コンテンツを非公開にしても保持されます
  • さらに、コレクションのスキーマで定義したすべてのカスタムフィールド

ReferencePage

entry.references には、getEmDashEntry に要求された参照フィールドごとに 1 ページ分が、フィールドのスラッグをキーとして格納されます。

interface ReferencePage<T = Record<string, unknown>> {
	entries: ContentEntry<T>[];
	nextCursor?: string; // Set when the field holds more entries than the limit
}

各エントリは、直接読み込んだエントリと同じ方法でマッピングされますが、1 つだけ例外があります。バイラインとタクソノミーのタームは展開されないため、data.bylines と data.terms は存在しません。

getEmDashReferences()

そのフィールドを持つエントリを読み直さずに、1 つの参照フィールドの 1 ページ分を取得します。最初のページより先へ進むには、そのページが返した nextCursor を使います。

パラメータ型説明
collectionstringフィールドを持つエントリのコレクションのスラッグ
slugOrIdstringエントリのスラッグまたは ID
fieldstring参照フィールドのスラッグ
options{ limit?: number; cursor?: string; locale?: string }任意。既定は 50 件、最大 100 件

次の例では、リンクされたエントリを次の 20 件読み込みます。

import { getEmDashReferences } from "emdash";

const { entries, nextCursor, error } = await getEmDashReferences(
	"posts",
	post.id,
	"related_posts",
	{ cursor, limit: 20 },
);

error は実際のエラーの場合にのみ設定されます。不明なフィールド、存在しないエントリ、リクエストから見えないエントリは、いずれも空の entries 配列に解決されます。

結果には、そのページが読み取った行を示す cacheHint も含まれます。レンダリング結果をキャッシュするルートは、getEmDashEntry({ references }) が最初のページのヒントを取り込むのと同じ方法でこれを自身のヒントにマージしてください。そうすれば、これらのエントリのいずれかに書き込みがあったときにページが失効します。

URL ヘルパー

decodeSlug() と slugify()

動的ルートのパラメータをコンテンツクエリに渡す前に、decodeSlug() を使います。パラメータがない場合、またはパーセントエンコーディングが不正な文字列の場合は undefined を返し、それ以外はデコードしたスラッグを返します。

function decodeSlug(raw: string | undefined): string | undefined;
import { decodeSlug, getEmDashEntry } from "emdash";

const slug = decodeSlug(Astro.params.slug);
const { entry } = slug ? await getEmDashEntry("posts", slug) : { entry: null };

slugify(value) は、テキストを小文字でハイフン区切りのスラッグに変換します。テンプレートでラベルからスラッグを組み立てる必要があるときに使います。保存済みのエントリのスラッグは、すでに EmDash によって生成されています。

sanitizeHref() と isSafeHref()

これらのヘルパーは、http:、https:、mailto:、tel:、サイト相対パス、フラグメントを受け付けます。スクリプトを実行できるスキーム、プロトコル相対 URL、ブラウザーが別のサイトとして解決するバックスラッシュで始まる形式、制御文字は拒否します。isSafeHref(value) は真偽値を返します。sanitizeHref(value) は、元の安全な URL を返し、値が空または安全でない場合は "#" を返します。

import { sanitizeHref } from "emdash";

const href = sanitizeHref(menuItem.url);

プレビューシステム

generatePreviewToken()

下書きコンテンツ用のプレビュートークンを生成します。次の例では、1 時間後に期限切れになるトークンを作成します。

import { generatePreviewToken } from "emdash";

const token = await generatePreviewToken({
	contentId: "posts:01HXK5MZSN...",
	secret: process.env.EMDASH_PREVIEW_SECRET!,
	expiresIn: 3600, // 1 hour
});

contentId は collection:id 形式にする必要があります。expiresIn には秒数、または s、m、h、d、w で終わる期間を指定でき、既定値は "1h" です。署名用のシークレットはサーバー側にだけ置いてください。

verifyPreviewToken()

プレビュートークンを検証し、そのペイロードを読み取ります。

import { verifyPreviewToken } from "emdash";

const result = await verifyPreviewToken({
	token,
	secret: process.env.EMDASH_PREVIEW_SECRET!,
});

if (result.valid) {
	const { cid, exp, iat } = result.payload;
	// cid is "collection:id" format, e.g. "posts:my-draft-post"
}

署名用の secret とともに、token または url のいずれかを渡します。無効なトークンは { valid: false, error } を返し、error は "none"、"malformed"、"invalid"、"expired" のいずれかです。

parseContentId()

プレビューのペイロードにある collection:id の値を、2 つの部分に分割します。

import { parseContentId } from "emdash";

const parsed = parseContentId(result.payload.cid);

{ collection, id } を返し、値にコロンの区切りがない場合は例外をスローします。

getPreviewUrl() と buildPreviewUrl()

getPreviewUrl() は、プレビュー URL を作成して署名します。collection、id、secret を受け取り、任意で expiresIn、baseUrl、pathPattern、locale も指定できます。

import { getPreviewUrl } from "emdash";

const previewUrl = await getPreviewUrl({
	collection: "posts",
	id: post.id,
	secret: process.env.EMDASH_PREVIEW_SECRET!,
	pathPattern: "/blog/{id}",
});

baseUrl を指定しない場合は、サイト相対 URL を返します。すでにトークンがある場合は、buildPreviewUrl({ path, token, baseUrl? }) を使います。

isPreviewRequest()

リクエストにプレビュートークンが含まれているかを確認し、含まれていれば読み取ります。

import { isPreviewRequest, getPreviewToken } from "emdash";

if (isPreviewRequest(Astro.url)) {
	const token = getPreviewToken(Astro.url);
	// Verify and show preview content
}

getPreviewToken() は _preview クエリパラメータを返し、ない場合は null を返します。EmDash のミドルウェアは通常のプレビューリクエストを検証し、プレビューの状態を getEmDashEntry() に自動的に渡します。これらのヘルパーは、カスタムのプレビュールートやツール向けです。

コンテンツコンバータ

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);

ProseMirror ドキュメントでは、image、table、iframeBlock、videoBlock など、組み込みブロックに EmDash 独自のノードが使われます。これを読み込む TipTap エディターは、スキーマにそれらのノードが必要です。ないと、それらを使うドキュメントを読み込めません。videoBlock ノードには、src、mediaId、provider、caption、width、height の属性があります。

サイト設定

getSiteSettings と getSiteSetting で、サイト全体の設定を読み取ります。

function getSiteSettings(): Promise<Partial<SiteSettings>>;
function getSiteSetting<K extends SiteSettingKey>(key: K): Promise<SiteSettings[K] | undefined>;
import { getSiteSettings, getSiteSetting } from "emdash";

// Get all settings
const settings = await getSiteSettings();

// Get single setting
const title = await getSiteSetting("title");

設定はランタイム API からは読み取り専用です。更新するには管理 API を使います。

getSiteSettings() は、未設定のキーが省略されるため、部分的なオブジェクトを返します。サイトのロゴやファビコンなどのメディア設定は、関数が返る前にメディア参照オブジェクトへ解決されます。

getSiteSettingsWithCacheHint() は { data, cacheHint } を返します。サイト設定の変更後に Astro のルートキャッシュを無効化したい場合は、このヒントを Astro.cache.set() に渡します。

SEO

getSeoMeta() で、ページの SEO パネルの値とコンテンツのフォールバックを解決します。

function getSeoMeta<T>(content: SeoContentInput<T>, options?: SeoMetaOptions): SeoMeta;

interface SeoMetaOptions {
	siteTitle?: string;
	siteUrl?: string;
	titleSeparator?: string; // Default: " | "
	path?: string;
	defaultOgImage?: string;
	defaultTitle?: string;
	defaultDescription?: string;
}

interface SeoMeta {
	title: string;
	description: string | null;
	ogTitle: string;
	ogDescription: string | null;
	ogImage: string | null;
	canonical: string | null;
	robots: string | null;
}
import { getSeoMeta } from "emdash";

const meta = getSeoMeta(post, {
	siteTitle: "Example Blog",
	siteUrl: "https://example.com",
	path: `/blog/${post.data.slug}`,
});

解決済みのタイトル、説明、Open Graph の値、正規 URL、robots の値を返します。getContentSeo(content) は、テンプレートのフォールバックを適用せずに、元の SEO オブジェクトを返します。

翻訳されたコンテンツについては、getHreflangAlternates(collection, entryId, { siteUrl? }) が、公開済みでルーティング可能なロケール別のバリアントを { hreflang, href } オブジェクトとして返し、x-default のエントリを追加します。国際化が無効な場合、現在のエントリが noindex に設定されている場合、または絶対サイト URL がない場合は、空の配列を返します。

コメント

エントリの承認済みコメントとその件数を取得します。

import { getCommentCount, getComments } from "emdash";

const { items: comments, total } = await getComments({
	collection: "posts",
	contentId: post.data.id,
	threaded: true,
	reactions: true,
	sort: "best",
});

const count = await getCommentCount("posts", post.data.id);

threaded は、返信を親コメントの下にネストします。既定の sort は "oldest" です。"best" はトップレベルのコメントをリアクション数で順位付けし、リアクション数の集計を自動的に有効にします。サーバーサイドレンダリングでのコメントクエリが返す承認済みコメントは最大 500 件です。クライアントでページネーションが必要な場合は、REST API を使ってください。

コメントコンポーネントを翻訳する

emdash/ui/comments の Comments コンポーネントと CommentForm コンポーネントは、既定では英語のテキストを表示します。labels オブジェクトを渡すと、その一部を置き換えられます。省略したキーや undefined を設定したキーは、英語の既定値のままになります。

<Comments
	collection="posts"
	contentId={post.data.id}
	threaded
	labels={{
		heading: (count) => (count === 1 ? "1 Kommentar" : `${count} Kommentare`),
		member: "Mitglied",
		like: "Gefällt mir",
	}}
/>
<CommentForm
	collection="posts"
	contentId={post.data.id}
	labels={{
		name: "Name",
		email: "E-Mail",
		comment: "Kommentar",
		submit: "Kommentar senden",
		submitting: "Wird gesendet …",
		published: "Kommentar veröffentlicht",
		pending: "Kommentar wird vor der Veröffentlichung geprüft",
		error: "Der Kommentar konnte nicht gesendet werden.",
		networkError: "Netzwerkfehler. Bitte versuche es erneut.",
	}}
/>

Comments は heading、member、like を受け付けます。heading には承認済みコメントの件数が渡されるため、コメントが 0 件の場合に別のテキストを返せます。

CommentForm は name、email、comment、submit、submitting、published、pending、error、networkError を受け付けます。フォームは、コメントがすぐに承認された場合は published を、モデレーションを待つ場合は pending を表示します。error がない場合、フォームはサーバーの英語のエラーメッセージを表示します。

Comments は、コメントの日付をページのロケール(Astro.currentLocale)で書式設定し、ない場合は en-US にフォールバックします。Astro が Astro.currentLocale を設定するのは、i18n 設定が有効な場合だけです。有効でない場合や別の書式を使いたい場合は、locale="de-CH" のように BCP 47 ロケールタグを渡してください。

メニュー

ナビゲーションメニューを取得し、ネストされた子を含む項目を順に処理します。

function getMenu(name: string, options?: { locale?: string }): Promise<Menu | null>;
function getMenus(options?: { locale?: string }): Promise<MenuSummary[]>;
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));
	});
}

getMenu(name, { locale? }) は、設定されたロケールのフォールバックチェーンに従います。getMenus({ locale? }) は、解決されたリクエストのロケールまたは設定済みのロケールのメニュー概要を一覧にします。国際化を使っていない場合は、すべてのロケールを一覧にします。getMenuWithCacheHint() は、Astro のキャッシュを使うルート向けに { data, cacheHint } を返します。

バイライン

ID またはスラッグで著者プロフィールを取得するか、バイラインにクレジットされたエントリを一覧にします。

import { getByline, getBylineBySlug, getEntriesByByline } from "emdash";

const profile = await getBylineBySlug("jane-doe", { locale: "en" });
const posts = profile
	? await getEntriesByByline("posts", profile.translationGroup ?? profile.id)
	: [];

getByline(id) は 1 件のプロフィールまたは null を返します。スラッグでの検索は任意のロケールを受け付け、ロケールのフォールバックチェーンに従います。コンテンツクエリはすでに、エントリの順序付きクレジットを entry.data.bylines に展開しています。著者ページやバイラインのアーカイブには、これらの単独のヘルパーを使います。

タクソノミー

タクソノミーのターム、単一のターム、エントリのターム、またはタームによるエントリを取得します。

function getTaxonomyTerms(
	taxonomyName: string,
	options?: { locale?: string; includeCounts?: boolean },
): Promise<TaxonomyTerm[]>;

function getTerm(
	taxonomyName: string,
	slug: string,
	options?: { locale?: string; includeCounts?: boolean },
): Promise<TaxonomyTerm | null>;

function getTermsForEntries(
	collection: string,
	entryIds: string[],
	taxonomyName: string,
	options?: { locale?: string },
): Promise<Map<string, TaxonomyTerm[]>>;
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");

getTaxonomyDefs({ locale? }) はタクソノミーごとに 1 つの定義を一覧にし、getTaxonomyDef(name, { locale? }) は 1 つの定義を返します。どのロケールもそのタクソノミーを定義していない場合は null を返します。どちらもすべてのロケールにわたってタクソノミーを解決します。どのロケールのラベルが使われるかは、タクソノミーとタームを翻訳するを参照してください。ターム検索は、設定されたフォールバックチェーンに従います。

getTaxonomyTerms(name, { locale?, includeCounts? }) は、階層型のタクソノミーではツリーを返し、既定で表示可能なエントリの件数を含めます。テンプレートが件数を表示しない場合は、includeCounts: false を渡します。コンテンツクエリも、割り当て済みのタームを各エントリの data.terms に展開します。コレクション名とエントリ ID しかない場合は、getEntryTerms() を使います。

多数のエントリの横にタームを表示するアーカイブページでは、ループ内で getEntryTerms() を呼ぶ代わりに、検索をまとめて行います。

import { getAllTermsForEntries, getTermsForEntries } from "emdash";

const termsByPost = await getTermsForEntries(
	"posts",
	posts.map(post => post.data.id),
	"category",
);

const allTermsByPost = await getAllTermsForEntries(
	"posts",
	posts.map(post => post.data.id),
);

getTermsForEntries() は、エントリ ID から、指定したタクソノミーのタームへのマップを返します。getAllTermsForEntries() は、エントリ ID から、タクソノミー名ごとにグループ化されたタームへのマップを返します。getTaxonomyTermsWithCacheHint() は、Astro でキャッシュされるルート向けに { data, cacheHint } を返します。

ウィジェットエリア

ウィジェットエリアと、そこに含まれるウィジェットを取得します。

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);
	});
}

getWidgetAreaWithCacheHint(name) は、Astro のキャッシュを使うルート向けに { data, cacheHint } を返します。ウィジェットエリアとそのウィジェットは、設定された並び順で並びます。

セクション

セクションを取得して絞り込みます。

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 です。

検索

コレクション全体にわたるグローバル検索を実行します。結果にはハイライトされたスニペットが含まれます。

function search(query: string, options?: SearchOptions): Promise<SearchResponse>;

interface SearchOptions {
	collections?: string[]; // Default: every searchable collection
	status?: string; // Default: "published"
	locale?: string; // Default: all locales
	limit?: number; // Default: 20
	cursor?: string;
	scope?: "all" | "title"; // Default: "all"
}

interface SearchResponse {
	items: SearchResult[];
	nextCursor?: string;
}
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);
});

// Paginate: pass the previous nextCursor back as `cursor` to get the next page.
// nextCursor is undefined once there are no more results.
if (results.nextCursor) {
	const next = await search("hello world", {
		collections: ["posts", "pages"],
		limit: 20,
		cursor: results.nextCursor,
	});
}

scope: "title" を指定すると、クエリはインデックス化された全文ではなく各コレクションのタイトルフィールドにのみ一致します。本文の一致が意外に感じられるピッカーやオートコンプリートで便利です。タイトルフィールドが検索用にインデックス化されていないコレクションは、このスコープでは結果を返しません。

エラー処理

コンテンツクエリは、運用上のエラーをスローせず、結果の中で返します。エントリが存在しないことは運用上のエラーではありません。この場合 entry は null になり、error は未定義のままです。

const { entry, error } = await getEmDashEntry("posts", slug);

if (error) {
	return new Response("Content could not be loaded", { status: 500 });
}

if (!entry) {
	return Astro.rewrite("/404");
}

結果のエンベロープを持たないヘルパーは、入力が無効な場合やデータベース操作が失敗した場合にスローすることがあります。ページが有用なフォールバックを提供できる場合は、ルートの境界でそれらのエラーを処理してください。より低レベルのサーバー統合で使われるリポジトリやハンドラーのエラークラスは、このサイトテンプレート API の対象外です。