JavaScript-API-Referenz

Auf dieser Seite

Diese Seite behandelt die öffentliche API, die Astro-Seiten, Layouts und Komponenten verwenden, um eine EmDash-Site zu lesen und darzustellen. Sie verzeichnet nicht jeden Export des emdash-Paket-Roots: Datenbank-Repositories, API-Handler, Migrationswerkzeuge, APIs zum Entwickeln von Plugins und andere Server-Interna haben eigene Referenzen oder sind für Framework-Integrationscode gedacht.

Der Site-Template-API-Vertrag in dieser Referenz listet jede Funktion auf, die die gepflegten Site-Templates von EmDash aus emdash importieren. Reine Typ-Importe wie MediaValue gehören zur jeweiligen Dokumentation des Datenmodells. Verwandte Funktionen werden in denselben Abschnitten beschrieben, wenn sie Site-Autoren helfen, die Seite behandelt aber keine unzusammenhängenden Root-Exporte.

Site-Template-API-Vertrag

Die gepflegten Templates rufen diese Laufzeit-Helfer auf:

FunktionVerwendet für
decodeSlugDekodieren eines dynamischen Route-Parameters vor dem Nachschlagen
getEmDashCollectionLesen und Filtern von Einträgen in einer Collection
getEmDashEntryLesen eines Eintrags per ID oder Slug
getMenuWithCacheHintRendern eines Navigationsmenüs mit Cache-Invalidierung
getSeoMetaAuflösen der SEO-Panel-Werte eines Eintrags und der Template-Fallbacks
getSiteSettingsLesen der öffentlichen Site-Identität und weiterer globaler Einstellungen
getSiteSettingsWithCacheHintLesen globaler Einstellungen mit Cache-Invalidierung
getTaxonomyTermsWithCacheHintRendern von Taxonomie-Filtern mit Cache-Invalidierung
getTermsForEntriesStapelweises Laden einer Taxonomie für eine Liste von Einträgen
sanitizeHrefAblehnen unsicherer URL-Schemata, bevor gespeicherte Links gerendert werden
searchDurchsuchen veröffentlichter Inhalte über Collections hinweg

Inhaltsabfragen

Die Abfragefunktionen von EmDash folgen dem Muster der Live Content Collections von Astro und liefern { entries, error } bzw. { entry, error }, damit Fehler sauber behandelt werden können.

getEmDashCollection()

Ruft alle Einträge einer Collection ab. Das folgende Beispiel lädt alle Beiträge und prüft auf einen Fehler:

import { getEmDashCollection } from "emdash";

const { entries: posts, error } = await getEmDashCollection("posts");

if (error) {
	console.error("Failed to load posts:", error);
}

Parameter

ParameterTypBeschreibung
collectionstringCollection-Slug
optionsCollectionFilterOptionale Filteroptionen

Optionen

Der Parameter options akzeptiert den folgenden Filter:

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 und offset schließen sich gegenseitig aus. Die Schlüssel von where können Inhaltsfelder, Taxonomien oder byline benennen; für geordnete Vergleiche stehen Bereichsobjekte zur Verfügung.

Rückgabewert

Die Funktion wird zu einem CollectionResult aufgelöst:

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

Beispiele

Die folgenden Beispiele filtern nach Status und Taxonomie, begrenzen die Ergebnisse und behandeln Fehler:

// 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()

Ruft einen einzelnen Eintrag per Slug oder ID ab. Das folgende Beispiel lädt einen Beitrag und rendert die 404-Seite der Site, wenn er fehlt:

import { getEmDashEntry } from "emdash";

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

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

Parameter

ParameterTypBeschreibung
collectionstringCollection-Slug
slugOrIdstringSlug oder ID des Eintrags
options{ locale?: string; references?: ReferenceSelection }Optional. Locale für die Slug-Auflösung sowie die zu ladenden Referenzfelder

Der Vorschaumodus wird automatisch behandelt: Hat die Anfrage ein gültiges _preview-Token, liefert die Abfrage Entwurfsinhalte. Für den Vorschaustatus ist kein Parameter nötig.

references benennt die zu ladenden Referenzfelder, geordnet nach Feld-Slug. true fordert die erste Seite mit dem Standardlimit von 50 Einträgen an; die Objektform akzeptiert ein limit (höchstens 100) und den cursor einer vorherigen Seite. Nicht aufgeführte Felder werden nicht gelesen, und ein Aufruf ohne diese Option führt keine Referenzabfragen aus.

Rückgabewert

Die Funktion wird zu einem EntryResult aufgelöst:

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
}

Beispiele

Die folgenden Beispiele rufen Einträge per Slug und ID ab, lesen den Vorschaustatus und unterscheiden Fehler von „nicht gefunden“:

// 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()

Ruft die verfügbaren Übersetzungen eines Eintrags anhand von Collection-Slug und Datenbank-ID ab:

import { getTranslations } from "emdash";

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

Das Ergebnis enthält die gemeinsame translationGroup, ein translations-Array und ein optionales error. Jede Übersetzungszusammenfassung enthält id, locale, slug und status.

resolveEmDashPath()

Löst einen öffentlichen Pfadnamen anhand der URL-Muster auf, die für routbare Collections konfiguriert sind:

import { resolveEmDashPath } from "emdash";

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

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

Das Ergebnis enthält die passende collection, den entry und die Route-params. Passt kein konfiguriertes URL-Muster, gibt die Funktion null zurück.

getEditMeta()

Liest die nicht aufzählbaren Metadaten für die visuelle Bearbeitung, die an einen Portable-Text-Wert angehängt sind:

import { getEditMeta } from "emdash";

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

Für einen annotierten Wert liefert sie { collection, id, field }, und undefined, wenn der Wert keine Annotation hat.

Inhaltstypen

ContentEntry

Abfragefunktionen liefern Einträge in der folgenden Form:

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
}

Der edit-Proxy liefert Annotationen für die visuelle Bearbeitung. Verteilen Sie ihn auf Elemente, um die Inline-Bearbeitung zu aktivieren: {...entry.edit.title}. Außerhalb des Bearbeitungsmodus erzeugt er keine Ausgabe.

Das data-Objekt enthält alle Inhaltsfelder sowie Systemfelder:

  • id - Eindeutige Kennung
  • slug - URL-freundliche Kennung
  • status - “draft” | “published” | “archived”
  • createdAt - Erstellungszeitpunkt als Date
  • updatedAt - Zeitpunkt der letzten Aktualisierung als Date
  • publishedAt - Veröffentlichungszeitpunkt als Date oder null; bleibt erhalten, wenn Inhalte depubliziert werden
  • Dazu alle benutzerdefinierten Felder, die in Ihrem Collection-Schema definiert sind

ReferencePage

entry.references enthält eine Seite für jedes Referenzfeld, das bei getEmDashEntry angefordert wurde, geordnet nach Feld-Slug:

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

Jeder Eintrag wird so abgebildet wie ein direkt geladener Eintrag, mit einer Ausnahme: Bylines und Taxonomie-Terms werden nicht hydriert, daher fehlen data.bylines und data.terms.

getEmDashReferences()

Ruft eine Seite eines einzelnen Referenzfelds ab, ohne den Eintrag, an dem es hängt, erneut zu lesen. Nutzen Sie dies, um mit dem nextCursor der vorherigen Seite über die erste Seite hinauszugehen.

ParameterTypBeschreibung
collectionstringCollection-Slug des Eintrags, der das Feld enthält
slugOrIdstringSlug oder ID des Eintrags
fieldstringSlug des Referenzfelds
options{ limit?: number; cursor?: string; locale?: string }Optional. Standardmäßig 50 Einträge, höchstens 100

Das folgende Beispiel lädt die nächsten 20 verknüpften Einträge:

import { getEmDashReferences } from "emdash";

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

error wird nur bei tatsächlichen Fehlern gesetzt. Ein unbekanntes Feld, ein fehlender Eintrag oder ein Eintrag, den die Anfrage nicht sehen darf, werden alle zu einem leeren entries-Array aufgelöst.

Das Ergebnis enthält außerdem einen cacheHint, der die von der Seite gelesenen Zeilen benennt. Eine Route, die ihre Ausgabe cacht, sollte ihn in ihren eigenen Hint einmischen, so wie getEmDashEntry({ references }) den Hint der ersten Seite einbezieht, damit das Schreiben in einen dieser Einträge die Seite ablaufen lässt.

URL-Helfer

decodeSlug() und slugify()

Verwenden Sie decodeSlug() für einen dynamischen Route-Parameter, bevor Sie ihn an eine Inhaltsabfrage übergeben. Für einen fehlenden Parameter liefert es undefined, andernfalls wendet es decodeURIComponent() an, das bei fehlerhafter Prozent-Kodierung eine Exception auslöst:

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) wandelt Text in einen kleingeschriebenen, durch Bindestriche getrennten Slug um. Verwenden Sie es, wenn ein Template aus einem Label einen Slug bilden muss; gespeicherte Eintrags-Slugs stammen bereits von EmDash.

sanitizeHref() und isSafeHref()

Diese Helfer akzeptieren http:, https:, mailto:, tel:, Site-relative Pfade und Fragmente. Sie lehnen skriptfähige Schemata, protokollrelative URLs, mit Backslash beginnende Formen, die Browser auf eine andere Site auflösen, und Steuerzeichen ab. isSafeHref(value) gibt einen Boolean zurück. sanitizeHref(value) gibt die ursprüngliche sichere URL zurück oder "#", wenn der Wert leer oder unsicher ist.

import { sanitizeHref } from "emdash";

const href = sanitizeHref(menuItem.url);

Vorschausystem

generatePreviewToken()

Erzeugt ein Vorschau-Token für Entwurfsinhalte. Das folgende Beispiel erstellt ein Token, das nach einer Stunde abläuft:

import { generatePreviewToken } from "emdash";

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

contentId muss das Format collection:id haben. expiresIn akzeptiert Sekunden oder eine Dauer, die auf s, m, h, d oder w endet, und ist standardmäßig "1h". Halten Sie das Signaturgeheimnis auf dem Server.

verifyPreviewToken()

Prüft ein Vorschau-Token und liest seine Nutzdaten:

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

Übergeben Sie entweder token oder url zusammen mit dem Signatur-secret. Ein ungültiges Token liefert { valid: false, error }, wobei error "none", "malformed", "invalid" oder "expired" ist.

parseContentId()

Teilt den Wert collection:id aus den Nutzdaten einer Vorschau in seine beiden Teile:

import { parseContentId } from "emdash";

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

Sie liefert { collection, id } und löst eine Exception aus, wenn der Wert keinen Doppelpunkt als Trennzeichen enthält.

getPreviewUrl() und buildPreviewUrl()

getPreviewUrl() erstellt und signiert eine Vorschau-URL. Sie akzeptiert collection, id und secret sowie optionale Werte für expiresIn, baseUrl, pathPattern und locale:

import { getPreviewUrl } from "emdash";

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

Ohne baseUrl liefert sie eine Site-relative URL. Verwenden Sie buildPreviewUrl({ path, token, baseUrl? }), wenn bereits ein Token existiert.

isPreviewRequest()

Prüft, ob eine Anfrage ein Vorschau-Token enthält, und liest es anschließend aus:

import { isPreviewRequest, getPreviewToken } from "emdash";

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

getPreviewToken() liefert den Query-Parameter _preview oder null, wenn er fehlt. Die EmDash-Middleware prüft normale Vorschau-Anfragen und stellt getEmDashEntry() den Vorschaustatus automatisch bereit; diese Helfer sind für benutzerdefinierte Vorschau-Routen und Werkzeuge gedacht.

Inhaltskonverter

Konvertieren zwischen den Formaten Portable Text und 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);

Site-Einstellungen

Lesen Sie site-weite Einstellungen mit getSiteSettings und 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");

Einstellungen sind über die Laufzeit-API schreibgeschützt. Verwenden Sie zum Aktualisieren die Admin-API.

getSiteSettings() liefert ein partielles Objekt, weil nicht gesetzte Schlüssel weggelassen werden. Medieneinstellungen wie Site-Logo und Favicon werden zu Medienreferenz-Objekten aufgelöst, bevor die Funktion zurückkehrt.

getSiteSettingsWithCacheHint() liefert { data, cacheHint }. Übergeben Sie den Hint an Astro.cache.set(), wenn ein Astro-Route-Cache nach einer Änderung der Site-Einstellungen invalidiert werden soll.

SEO

Lösen Sie die Werte des SEO-Panels und die Inhalts-Fallbacks für eine Seite mit getSeoMeta() auf:

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

Sie liefert den aufgelösten Titel, die Beschreibung, die Open-Graph-Werte, die kanonische URL und den robots-Wert. getContentSeo(content) liefert das rohe SEO-Objekt, ohne Template-Fallbacks anzuwenden.

Für übersetzte Inhalte liefert getHreflangAlternates(collection, entryId, { siteUrl? }) veröffentlichte, routbare Locale-Varianten als { hreflang, href }-Objekte und fügt einen x-default-Eintrag hinzu. Sie liefert ein leeres Array, wenn Internationalisierung deaktiviert ist, der aktuelle Eintrag als noindex markiert ist oder keine absolute Site-URL verfügbar ist.

Kommentare

Rufen Sie freigegebene Kommentare und deren Anzahl für einen Eintrag ab:

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 verschachtelt Antworten unter ihrem übergeordneten Kommentar. Die Standardeinstellung für sort ist "oldest"; "best" ordnet Kommentare der obersten Ebene nach Reaktionen und aktiviert Reaktionszähler automatisch. Serverseitig gerenderte Kommentarabfragen liefern höchstens 500 freigegebene Kommentare; verwenden Sie die REST-API, wenn ein Client Paginierung braucht.

Menüs

Rufen Sie Navigationsmenüs ab und durchlaufen Sie deren Einträge, einschließlich verschachtelter Kinder:

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? }) folgt der konfigurierten Locale-Fallback-Kette. getMenus({ locale? }) listet Menüzusammenfassungen für die aufgelöste Anfrage-Locale oder die konfigurierte Locale auf; ohne Internationalisierung werden alle Locales aufgelistet. getMenuWithCacheHint() liefert { data, cacheHint } für Routen, die den Astro-Cache verwenden.

Bylines

Rufen Sie ein Autorenprofil per ID oder Slug ab oder listen Sie Einträge auf, die einer Byline zugeordnet sind:

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) liefert ein Profil oder null. Die Slug-Suche akzeptiert eine optionale Locale und folgt der Locale-Fallback-Kette. Inhaltsabfragen hydrieren die geordneten Urheberangaben eines Eintrags bereits in entry.data.bylines; verwenden Sie diese eigenständigen Helfer für Autorenseiten und Byline-Archive.

Taxonomien

Rufen Sie Taxonomie-Terms, einen einzelnen Term, die Terms eines Eintrags oder Einträge nach Term ab:

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? }) listet pro Taxonomie eine Definition auf, und getTaxonomyDef(name, { locale? }) liefert eine Definition oder null, wenn keine Locale die Taxonomie definiert. Beide lösen eine Taxonomie in jeder Locale auf; Taxonomien und Terms übersetzen erklärt, welches Locale-Label sie verwenden. Term-Abfragen folgen der konfigurierten Fallback-Kette.

getTaxonomyTerms(name, { locale?, includeCounts? }) liefert für hierarchische Taxonomien einen Baum und enthält standardmäßig die Anzahl sichtbarer Einträge. Übergeben Sie includeCounts: false, wenn das Template keine Zähler rendert. Inhaltsabfragen hydrieren zugewiesene Terms ebenfalls in das data.terms jedes Eintrags; verwenden Sie getEntryTerms(), wenn Sie nur einen Collection-Namen und eine Eintrags-ID haben.

Bei Archivseiten, die Terms neben vielen Einträgen rendern, fassen Sie die Abfrage zu einem Stapel zusammen, statt getEntryTerms() in einer Schleife aufzurufen:

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() liefert eine Map von Eintrags-ID auf die Terms der angeforderten Taxonomie. getAllTermsForEntries() liefert eine Map von Eintrags-ID auf Terms, gruppiert nach Taxonomiename. getTaxonomyTermsWithCacheHint() liefert { data, cacheHint } für eine Astro-gecachte Route.

Widget-Bereiche

Rufen Sie Widget-Bereiche und die darin enthaltenen Widgets ab:

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) liefert { data, cacheHint } für Routen, die den Astro-Cache verwenden. Widget-Bereiche und ihre Widgets sind nach ihrer konfigurierten Sortierreihenfolge geordnet.

Sections

Rufen Sie Sections ab und filtern Sie sie:

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?) liefert { items: Section[]; nextCursor?: string }. Die Optionen sind source ("theme" | "user" | "import"), search, limit (Standard 50, maximal 100) und cursor.

Suche

Führen Sie eine globale Suche über Collections hinweg aus. Die Ergebnisse enthalten hervorgehobene Snippets:

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

Mit scope: "title" trifft die Abfrage nur das Titelfeld jeder Collection statt des gesamten indizierten Texts – nützlich für Auswahlfelder und Autovervollständigung, bei denen Treffer im Fließtext überraschen würden. Collections, deren Titelfeld nicht für die Suche indiziert ist, liefern in diesem Scope keine Ergebnisse.

Fehlerbehandlung

Inhaltsabfragen liefern betriebliche Fehler in ihrem Ergebnis, statt sie auszulösen. Ein fehlender Eintrag ist kein betrieblicher Fehler: entry ist null, und error bleibt undefiniert.

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

Helfer ohne Ergebnis-Hülle können Exceptions auslösen, wenn ihre Eingabe ungültig ist oder eine Datenbankoperation fehlschlägt. Behandeln Sie diese Fehler an der Route-Grenze, wenn die Seite einen sinnvollen Fallback bieten kann. Die Fehlerklassen für Repositories und Handler, die von serverseitigen Integrationen auf niedrigerer Ebene verwendet werden, liegen außerhalb dieser Site-Template-API.