Referencia de API JavaScript

En esta página

EmDash exporta funciones para consultar contenido y trabajar con vista previa, configuraciones, menús, taxonomías, áreas de widgets, secciones y búsqueda.

Consultas de contenido

Las funciones de consulta de EmDash siguen el patrón de colecciones de contenido en vivo de Astro, devolviendo { entries, error } o { entry, error } para un manejo elegante de errores.

getEmDashCollection()

Obtener todas las entradas de una colección. El siguiente ejemplo carga todos los posts y verifica errores:

import { getEmDashCollection } from "emdash";

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

if (error) {
	console.error("Error al cargar posts:", error);
}

Parámetros

ParámetroTipoDescripción
collectionstringSlug de la colección
optionsCollectionFilterOpciones de filtro opcionales

Opciones

El parámetro options acepta el siguiente filtro:

interface CollectionFilter {
	status?: "draft" | "published" | "archived";
	limit?: number;
	cursor?: string; // Paginación por keyset — pasa un `nextCursor` anterior
	offset?: number; // Paginación por offset — saltar N entradas (usar con `limit`)
	where?: Record<string, string | string[]>; // Filtrar por campo o taxonomía
}

Retorna

La función resuelve a un CollectionResult:

interface CollectionResult<T> {
	entries: ContentEntry<T>[]; // Array vacío si hay error o no se encontraron
	error?: Error; // Establecido si la consulta falló
	nextCursor?: string; // Cursor para la siguiente página keyset, si existe
	hasMore?: boolean; // Si existen más entradas más allá de esta página (cuando `limit` está establecido)
}

Ejemplos

Los siguientes ejemplos filtran por estado y taxonomía, limitan resultados y manejan errores:

// Obtener todos los posts publicados
const { entries: posts } = await getEmDashCollection("posts", {
	status: "published",
});

// Obtener los últimos 5 posts
const { entries: latest } = await getEmDashCollection("posts", {
	limit: 5,
	status: "published",
});

// Filtrar por taxonomía
const { entries: newsPosts } = await getEmDashCollection("posts", {
	status: "published",
	where: { category: "news" },
});

// Página de archivo numerada (ej. /page/3) con paginación por offset
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" },
});

// Manejar errores
const { entries, error } = await getEmDashCollection("posts");
if (error) {
	return new Response("Error del servidor", { status: 500 });
}

getEmDashEntry()

Obtener una entrada individual por slug o ID. El siguiente ejemplo carga un post y redirige cuando no existe:

import { getEmDashEntry } from "emdash";

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

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

Parámetros

ParámetroTipoDescripción
collectionstringSlug de la colección
slugOrIdstringSlug o ID de la entrada
options{ locale?: string }Opcional. Locale para resolución de slug

El modo de vista previa se maneja automáticamente — el middleware detecta tokens _preview y sirve contenido borrador vía AsyncLocalStorage. El parámetro opcional options solo acepta un locale para la resolución de slug; el estado de vista previa no requiere parámetro.

Retorna

La función resuelve a un EntryResult:

interface EntryResult<T> {
	entry: ContentEntry<T> | null; // null si no se encontró
	error?: Error; // Solo para errores reales, no para "no encontrado"
	isPreview: boolean; // true si se está sirviendo contenido borrador
}

Ejemplos

Los siguientes ejemplos obtienen por slug e ID, leen el estado de vista previa y distinguen errores de no-encontrado:

// Obtener por slug
const { entry: post } = await getEmDashEntry("posts", "hello-world");

// Obtener por ID
const { entry: post } = await getEmDashEntry("posts", "01HXK5MZSN0FVXT2Q3KPRT9M7D");

// La vista previa es automática — isPreview es true cuando hay un token _preview válido
const { entry, isPreview, error } = await getEmDashEntry("posts", slug);

// Manejar errores vs no-encontrado
if (error) {
	return new Response("Error del servidor", { status: 500 });
}
if (!entry) {
	return Astro.redirect("/404");
}

Tipos de contenido

ContentEntry

Las funciones de consulta devuelven entradas con la siguiente forma:

interface ContentEntry<T = Record<string, unknown>> {
	id: string;
	data: T;
	edit: EditProxy; // Anotaciones de edición visual
}

El proxy edit proporciona anotaciones de edición visual. Distribúyelo en elementos para habilitar la edición en línea: {...entry.edit.title}. En producción, esto no produce salida.

El objeto data contiene todos los campos de contenido más campos del sistema:

  • id - Identificador único
  • slug - Identificador amigable para URL
  • status - “draft” | “published” | “archived”
  • createdAt - Marca de tiempo ISO
  • updatedAt - Marca de tiempo ISO
  • publishedAt - Marca de tiempo ISO o null
  • Más todos los campos personalizados definidos en tu esquema de colección

Sistema de vista previa

generatePreviewToken()

Generar un token de vista previa para contenido borrador. El siguiente ejemplo crea un token que expira en una hora:

import { generatePreviewToken } from "emdash";

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

verifyPreviewToken()

Verificar un token de vista previa y leer su contenido:

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 está en formato "collection:id", ej. "posts:my-draft-post"
}

isPreviewRequest()

Verificar si una solicitud incluye un token de vista previa, luego leerlo:

import { isPreviewRequest, getPreviewToken } from "emdash";

if (isPreviewRequest(Astro.url)) {
	const token = getPreviewToken(Astro.url);
	// Verificar y mostrar contenido de vista previa
}

Conversores de contenido

Convertir entre formatos Portable Text y ProseMirror:

import { prosemirrorToPortableText, portableTextToProsemirror } from "emdash";

// De ProseMirror (editor) a Portable Text (almacenamiento)
const portableText = prosemirrorToPortableText(prosemirrorDoc);

// De Portable Text a ProseMirror
const prosemirrorDoc = portableTextToProsemirror(portableText);

Configuración del sitio

Leer la configuración global del sitio con getSiteSettings y getSiteSetting:

import { getSiteSettings, getSiteSetting } from "emdash";

// Obtener toda la configuración
const settings = await getSiteSettings();

// Obtener una configuración individual
const title = await getSiteSetting("title");

La configuración es de solo lectura desde la API de ejecución. Usa la API de administración para actualizarla.

Menús

Obtener menús de navegación e iterar sus elementos, incluidos hijos anidados:

import { getMenu, getMenus } from "emdash";

// Obtener todos los menús
const menus = await getMenus();

// Obtener menú específico con elementos
const primaryMenu = await getMenu("primary");

if (primaryMenu) {
	primaryMenu.items.forEach(item => {
		console.log(item.label, item.url);
		// Elementos anidados para desplegables
		item.children.forEach(child => console.log("  -", child.label));
	});
}

Taxonomías

Obtener términos de taxonomía, un término individual, los términos de una entrada o entradas por término:

import { getTaxonomyTerms, getTerm, getEntryTerms, getEntriesByTerm } from "emdash";

// Obtener todos los términos de una taxonomía (estructura de árbol para jerárquicas)
const categories = await getTaxonomyTerms("category");

// Obtener un término individual
const news = await getTerm("category", "news");

// Obtener términos asignados a una entrada de contenido
const postCategories = await getEntryTerms("posts", "post-123", "category");

// Obtener entradas con un término específico
const newsPosts = await getEntriesByTerm("posts", "category", "news");

Áreas de widgets

Obtener áreas de widgets y los widgets que contienen:

import { getWidgetArea, getWidgetAreas } from "emdash";

// Obtener todas las áreas de widgets
const areas = await getWidgetAreas();

// Obtener área de widgets específica con widgets
const sidebar = await getWidgetArea("sidebar");

if (sidebar) {
	sidebar.widgets.forEach(widget => {
		console.log(widget.type, widget.title);
	});
}

Secciones

Obtener secciones y filtrarlas:

import { getSection, getSections } from "emdash";

// Obtener todas las secciones (paginadas)
const { items, nextCursor } = await getSections();

// Filtrar secciones
const { items: themeSections } = await getSections({ source: "theme" });
const { items: results } = await getSections({ search: "newsletter" });

// Obtener una sección individual por slug
const cta = await getSection("newsletter-cta");

getSections(options?) devuelve { items: Section[]; nextCursor?: string }. Las opciones son source ("theme" | "user" | "import"), search, limit (por defecto 50, máx. 100) y cursor.

Búsqueda

Ejecutar una búsqueda global a través de colecciones. Los resultados incluyen fragmentos resaltados:

import { search } from "emdash";

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

// search() resuelve a { items, nextCursor? }
results.items.forEach(result => {
	console.log(result.title);
	console.log(result.snippet); // Contiene etiquetas <mark>
	console.log(result.score);
});

// Paginar: pasa el nextCursor anterior como `cursor` para obtener la siguiente página.
// nextCursor es undefined cuando no hay más resultados.
if (results.nextCursor) {
	const next = await search("hello world", {
		collections: ["posts", "pages"],
		limit: 20,
		cursor: results.nextCursor,
	});
}

Manejo de errores

EmDash exporta clases de error para manejar fallos específicos. El siguiente ejemplo captura errores de validación y esquema:

import {
  EmDashDatabaseError,
  EmDashValidationError,
  EmDashStorageError,
  SchemaError,
} from "emdash";

try {
  await repo.create({ ... });
} catch (error) {
  if (error instanceof EmDashValidationError) {
    console.error("Validación fallida:", error.message);
  }
  if (error instanceof SchemaError) {
    console.error("Error de esquema:", error.code, error.details);
  }
}