Référence de l’API JavaScript

Sur cette page

EmDash exporte des fonctions pour interroger le contenu, gérer les médias et travailler avec la base de données.

Content Queries

Les fonctions de requête d’EmDash suivent le modèle des live content collections d’Astro et renvoient { entries, error } ou { entry, error } pour une gestion d’erreurs propre.

getEmDashCollection()

Récupérer toutes les entrées d’une collection.

import { getEmDashCollection } from "emdash";

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

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

Parameters

ParameterTypeDescription
collectionstringSlug de la collection
optionsCollectionFilterOptions de filtre facultatives

Options

interface CollectionFilter {
	status?: "draft" | "published" | "archived";
	limit?: number;
	where?: Record<string, string | string[]>; // Filter by field or taxonomy
}

Returns

interface CollectionResult<T> {
	entries: ContentEntry<T>[]; // Empty array if error or none found
	error?: Error; // Set if query failed
}

Examples

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

Récupérer une entrée par slug ou ID.

import { getEmDashEntry } from "emdash";

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

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

Parameters

ParameterTypeDescription
collectionstringSlug de la collection
slugOrIdstringSlug ou ID de l’entrée

Le mode aperçu est géré automatiquement — le middleware détecte les jetons _preview et sert les brouillons via AsyncLocalStorage. Aucun paramètre options n’est nécessaire.

Returns

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
}

Examples

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

Content Types

ContentEntry

L’entrée renvoyée par les fonctions de requête :

interface ContentEntry<T = Record<string, unknown>> {
	id: string;
	data: T;
	edit: EditProxy; // Visual editing annotations
}

Le proxy edit fournit des annotations pour l’édition visuelle. Étalez-le sur les éléments pour l’édition en ligne : {...entry.edit.title}. En production, il ne produit aucune sortie.

L’objet data contient tous les champs de contenu plus les champs système :

  • id — Identifiant unique
  • slug — Identifiant adapté aux URL
  • status"draft" | "published" | "archived"
  • createdAt — Horodatage ISO
  • updatedAt — Horodatage ISO
  • publishedAt — Horodatage ISO ou null
  • Plus tous les champs personnalisés définis dans le schéma de la collection

Database Functions

createDatabase()

Créer une connexion à la base de données.

import { createDatabase } from "emdash";

const db = createDatabase({ url: "file:./data.db" });

runMigrations()

Exécuter les migrations en attente.

import { createDatabase, runMigrations } from "emdash";

const db = createDatabase({ url: "file:./data.db" });
const { applied } = await runMigrations(db);
console.log(`Applied ${applied.length} migrations`);

getMigrationStatus()

Vérifier l’état des migrations.

import { createDatabase, getMigrationStatus } from "emdash";

const db = createDatabase({ url: "file:./data.db" });
const status = await getMigrationStatus(db);
// { applied: ["0001_core", ...], pending: [] }

Repositories

Accès bas niveau aux données via des dépôts.

ContentRepository

import { ContentRepository, createDatabase } from "emdash";

const db = createDatabase({ url: "file:./data.db" });
const repo = new ContentRepository(db);

// Find many
const { items, nextCursor } = await repo.findMany("posts", {
	limit: 10,
	where: { status: "published" },
});

// Find by ID
const post = await repo.findById("posts", "01HXK5MZSN...");

// Create
const newPost = await repo.create({
	type: "posts",
	slug: "new-post",
	data: { title: "New Post", content: [] },
	status: "draft",
});

// Update
const updated = await repo.update("posts", "01HXK5MZSN...", {
	data: { title: "Updated Title" },
});

// Delete
await repo.delete("posts", "01HXK5MZSN...");

MediaRepository

import { MediaRepository, createDatabase } from "emdash";

const db = createDatabase({ url: "file:./data.db" });
const repo = new MediaRepository(db);

// List media
const { items } = await repo.findMany({ limit: 20 });

// Get by ID
const media = await repo.findById("01HXK5MZSN...");

// Create (after upload)
const newMedia = await repo.create({
	filename: "photo.jpg",
	mimeType: "image/jpeg",
	size: 12345,
	storageKey: "uploads/photo.jpg",
});

Schema Registry

Gestion programmatique du schéma.

import { SchemaRegistry, createDatabase } from "emdash";

const db = createDatabase({ url: "file:./data.db" });
const registry = new SchemaRegistry(db);

// List collections
const collections = await registry.listCollections();

// Get collection with fields
const postsSchema = await registry.getCollectionWithFields("posts");

// Create collection
await registry.createCollection({
	slug: "products",
	label: "Products",
	labelSingular: "Product",
	supports: ["drafts", "revisions"],
});

// Add field
await registry.createField("products", {
	slug: "price",
	label: "Price",
	type: "number",
	required: true,
});

Preview System

generatePreviewToken()

Générer un jeton d’aperçu pour le contenu brouillon.

import { generatePreviewToken } from "emdash";

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

verifyPreviewToken()

Vérifier un jeton d’aperçu.

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

Vérifier si la requête inclut un jeton d’aperçu.

import { isPreviewRequest, getPreviewToken } from "emdash";

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

Content Converters

Convertir entre Portable Text et 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 Settings

import { getSiteSettings, getSiteSetting } from "emdash";

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

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

Les réglages sont en lecture seule via l’API runtime. Utilisez l’API d’administration pour les mettre à jour.

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

Taxonomies

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

Widget Areas

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

Sections

import { getSection, getSections, getSectionCategories } from "emdash";

// Get all sections
const sections = await getSections();

// Filter sections
const heroes = await getSections({ category: "hero" });
const themeSections = await getSections({ source: "theme" });
const results = await getSections({ search: "newsletter" });

// Get single section
const cta = await getSection("newsletter-cta");

// Get categories
const categories = await getSectionCategories();
import { search, searchCollection } from "emdash";

// Global search across collections
const results = await search("hello world", {
	collections: ["posts", "pages"],
	status: "published",
	limit: 20,
});

// Results include snippets with highlights
results.forEach(result => {
	console.log(result.title);
	console.log(result.snippet); // Contains <mark> tags
	console.log(result.score);
});

// Collection-specific search
const posts = await searchCollection("posts", "typescript", {
	limit: 10,
});

Error Handling

EmDash exporte des classes d’erreur pour des échecs spécifiques :

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