Conectarse a eventos
Ejecutar código antes o después de que se guarden contenidos, se suban archivos multimedia y eventos del ciclo de vida del plugin.
El sistema de plugins de EmDash te permite extender el CMS sin modificar el código central. Los plugins pueden conectarse a eventos del ciclo de vida del contenido, almacenar sus propios datos, exponer configuraciones a los administradores y añadir interfaz de usuario personalizada al panel de administración.
Los plugins de EmDash son transformadores de configuración, no aplicaciones separadas. Se ejecutan en el mismo proceso que tu sitio Astro e interactúan a través de interfaces bien definidas.
Principios clave:
Conectarse a eventos
Ejecutar código antes o después de que se guarden contenidos, se suban archivos multimedia y eventos del ciclo de vida del plugin.
Almacenar datos
Persistir datos específicos del plugin en colecciones indexadas sin escribir migraciones de base de datos.
Exponer configuraciones
Declarar un esquema de configuración y obtener una interfaz de administración generada automáticamente.
Añadir páginas de administración
Crear páginas de administración personalizadas y widgets del panel con componentes React.
Crear rutas API
Exponer endpoints para la interfaz de usuario de administración de tu plugin o integraciones externas.
Realizar solicitudes HTTP
Llamar a APIs externas con restricciones de host declaradas por seguridad.
Cada plugin se crea con definePlugin():
import { definePlugin } from "emdash";
export default definePlugin({ id: "my-plugin", version: "1.0.0",
// A qué APIs necesita acceder el plugin capabilities: ["read:content", "network:fetch"],
// Hosts a los que el plugin puede hacer solicitudes HTTP allowedHosts: ["api.example.com"],
// Colecciones de almacenamiento persistente storage: { entries: { indexes: ["userId", "createdAt"], }, },
// Manejadores de eventos hooks: { "content:afterSave": async (event, ctx) => { ctx.log.info("Contenido guardado", { id: event.content.id }); }, },
// Endpoints de la API REST routes: { status: { handler: async (ctx) => ({ ok: true }), }, },
// Configuración de la interfaz de usuario de administración admin: { settingsSchema: { apiKey: { type: "secret", label: "Clave de API" }, }, pages: [{ path: "/dashboard", label: "Panel" }], widgets: [{ id: "status", size: "half" }], },});Cada hook y manejador de ruta recibe un objeto PluginContext con acceso a:
| Propiedad | Descripción | Disponibilidad |
|---|---|---|
ctx.storage | Colecciones de documentos del plugin | Siempre (si se declara) |
ctx.kv | Almacén clave-valor para configuraciones y estado | Siempre |
ctx.content | Leer/escribir contenido del sitio | Con read:content o write:content |
ctx.media | Leer/escribir archivos multimedia | Con read:media o write:media |
ctx.http | Cliente HTTP para solicitudes externas | Con network:fetch |
ctx.log | Logger estructurado (debug, info, warn, error) | Siempre |
ctx.plugin | Metadatos del plugin (id, versión) | Siempre |
ctx.site | Información del sitio: name, url, locale | Siempre |
ctx.url() | Generar URLs absolutas desde rutas | Siempre |
ctx.users | Leer información de usuario: get(), getByEmail(), list() | Con read:users |
ctx.cron | Programar tareas: schedule(), cancel(), list() | Siempre |
ctx.email | Enviar correo: send() | Con email:send + proveedor configurado |
La forma del contexto es idéntica en todos los hooks y rutas. Las propiedades controladas por capacidades solo están presentes cuando el plugin declara la capacidad requerida.
Las capacidades determinan qué APIs están disponibles en el contexto del plugin:
| Capacidad | Otorga Acceso A |
|---|---|
read:content | ctx.content.get(), ctx.content.list() |
write:content | ctx.content.create(), ctx.content.update(), ctx.content.delete() |
read:media | ctx.media.get(), ctx.media.list() |
write:media | ctx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete() |
network:fetch | ctx.http.fetch() (restringido a allowedHosts) |
network:fetch:any | ctx.http.fetch() (sin restricciones — para URLs configuradas por el usuario) |
read:users | ctx.users.get(), ctx.users.getByEmail(), ctx.users.list() |
email:send | ctx.email.send() (requiere un plugin proveedor) |
email:provide | Registrar hook exclusivo email:deliver (proveedor de transporte) |
email:intercept | Registrar hooks email:beforeSend / email:afterSend |
page:inject | Registrar hooks page:metadata / page:fragments |
Registra los plugins en tu configuración de Astro:
import { defineConfig } from "astro/config";import { emdash } from "emdash/astro";import seoPlugin from "@emdash-cms/plugin-seo";import auditLogPlugin from "@emdash-cms/plugin-audit-log";
export default defineConfig({ integrations: [ emdash({ plugins: [seoPlugin({ generateSitemap: true }), auditLogPlugin({ retentionDays: 90 })], }), ],});Los plugins se resuelven en tiempo de compilación. El orden importa para los hooks con la misma prioridad: los que aparezcan antes en el arreglo se ejecutan primero.
EmDash admite dos modos de ejecución de complementos:
| Modo | Descripción | Plataforma |
|---|---|---|
| Confiable | Los plugins se ejecutan en proceso con acceso completo | Cualquiera |
| Aislado | Los plugins se ejecutan en workers V8 aislados | Solo Cloudflare |
En el modo confiable, que es el predeterminado, las capacidades son documentación: los plugins pueden acceder a cualquier recurso. En el modo aislado, las capacidades sí se aplican en tiempo de ejecución.
Crear un plugin
Construye tu primer plugin con almacenamiento, hooks e interfaz de administración.
Hooks disponibles
Explora todos los hooks para contenido, medios y ciclo de vida del complemento.
Almacenamiento del plugin
Aprende cómo funciona el almacenamiento y cómo consultar datos del plugin.
Interfaz de administración
Añade páginas de administración y widgets del panel de administración.
Seguridad del sandbox
Comprende el aislamiento del sandbox en despliegues sobre Cloudflare y Node.js.