Esta guía es para autores de plugins sandboxed escritos contra la forma anterior de definePlugin(). Trabaja los cambios incompatibles en orden. Ninguno de ellos cambia cómo se comportan tus hooks o rutas en tiempo de ejecución; cambian cómo se declara, construye y publica el plugin.
Para la lista completa de cambios en cada paquete, consulta el changelog de EmDash.
Cambios incompatibles
Renombrado: @emdash-cms/registry-cli ahora es @emdash-cms/plugin-cli
Las versiones anteriores incluían la CLI como @emdash-cms/registry-cli, con un binario emdash-registry.
El paquete ahora es @emdash-cms/plugin-cli y el binario es emdash-plugin. El paquete antiguo ya no se publica.
¿Qué debo hacer?
Reemplaza la dependencia:
pnpm remove @emdash-cms/registry-cli
pnpm add -D @emdash-cms/plugin-cli
Reemplaza emdash-registry con emdash-plugin en todos los lugares donde lo llames. Cada subcomando mantiene su nombre (bundle, publish, login, whoami, switch, validate), y se agregan init, build y dev. Ver La CLI de plugins.
Cambiado: los plugins sandboxed se definen con satisfies SandboxedPlugin
Las versiones anteriores envolvían los hooks y rutas del plugin en definePlugin() importado de emdash, con los parámetros de cada manejador anotados manualmente.
Un plugin sandboxed ahora es una exportación por defecto simple anotada con satisfies SandboxedPlugin. El tipo proviene de emdash/plugin, un punto de entrada solo de tipos que el bundler elimina. TypeScript infiere event y ctx de cada manejador a partir del nombre del hook o ruta, por lo que los parámetros del manejador no necesitan anotaciones.
¿Qué debo hacer?
Realiza cuatro cambios en el archivo fuente del plugin. Reemplaza la importación:
import { definePlugin, type ContentHookEvent, type PluginContext } from "emdash";
import type { SandboxedPlugin } from "emdash/plugin";
Reemplaza el envoltorio definePlugin() con un objeto simple y una anotación satisfies:
export default definePlugin({ /* hooks, routes */ });
export default { /* hooks, routes */ } satisfies SandboxedPlugin;
Elimina las anotaciones de parámetros de cada manejador:
handler: async (event: ContentHookEvent, ctx: PluginContext) => {
handler: async (event, ctx) => {
El resultado es un único objeto exportado por defecto:
import type { SandboxedPlugin } from "emdash/plugin";
export default {
hooks: {
"content:beforeSave": {
handler: async (event, ctx) => {
return event.content;
},
},
},
} satisfies SandboxedPlugin;
Para nombrar un tipo de evento en una función auxiliar, impórtalo desde emdash/plugin:
import type { ContentHookEvent, PluginContext } from "emdash/plugin";
El event de un manejador es siempre el tipo canónico para ese hook. Anotar un manejador con una interfaz más estrecha ya no pasa la verificación de tipos. Valida cualquier campo del que dependas en tiempo de ejecución con una verificación typeof o un guard, que es el enfoque correcto para datos que provienen de fuera del sistema de tipos.
Cambiado: un plugin es un src/plugin.ts más emdash-plugin.jsonc
Las versiones anteriores dividían un plugin en dos archivos: src/index.ts devolvía un PluginDescriptor (id, version, capabilities, storage, entrypoint), y src/sandbox-entry.ts contenía los hooks y rutas.
Un plugin ahora es un archivo de tiempo de ejecución, src/plugin.ts (hooks y rutas), y un manifiesto editado manualmente, emdash-plugin.jsonc (identidad y contrato de confianza). Los campos entrypoint y format desaparecen; la compilación los conecta.
¿Qué debo hacer?
Mueve los hooks y rutas a src/plugin.ts usando la forma anterior. Mueve los metadatos del descriptor a emdash-plugin.jsonc junto a package.json. El id del descriptor se convierte en el slug del manifiesto; capabilities, allowedHosts y storage mantienen su forma; version se lee de package.json, así que omítelo.
El siguiente ejemplo muestra el equivalente en manifiesto de un descriptor que declaraba una colección de almacenamiento:
{
"$schema": "./node_modules/@emdash-cms/plugin-cli/schemas/emdash-plugin.schema.json",
"slug": "plugin-hello",
"publisher": "did:plc:abc123def456",
"license": "MIT",
"author": { "name": "Jane Doe", "url": "https://example.com" },
"security": { "email": "security@example.com" },
"capabilities": [],
"allowedHosts": [],
"storage": { "events": { "indexes": ["timestamp"] } }
}
Ver El manifiesto del plugin para todos los campos, y Fijación de publicador para el campo publisher.
En package.json, apunta la exportación "./sandbox" al archivo de tiempo de ejecución compilado:
"./sandbox": "./dist/sandbox-entry.mjs"
"./sandbox": "./dist/plugin.mjs"
Agrega el manifiesto a files para que se envíe con el paquete:
"files": ["dist"]
"files": ["dist", "emdash-plugin.jsonc"]
Cambiado: compilar con emdash-plugin build
Las versiones anteriores compilaban los dos archivos fuente con un script tsdown escrito manualmente.
emdash-plugin build lee emdash-plugin.jsonc y src/plugin.ts y emite los artefactos dist/. emdash-plugin dev observa y recompila.
¿Qué debo hacer?
Reemplaza el script de compilación y agrega un script de observación:
"scripts": {
"build": "tsdown src/index.ts src/sandbox-entry.ts --format esm --dts --clean"
"build": "emdash-plugin build",
"dev": "emdash-plugin dev"
}
Luego valida y compila:
emdash-plugin validate
emdash-plugin build
Eliminado: exportaciones de tipos y funciones de formato estándar desde emdash
Las versiones anteriores exportaban StandardPluginDefinition, StandardHookHandler, StandardHookEntry, StandardRouteHandler, StandardRouteEntry y la función isStandardPluginDefinition desde emdash.
Estos se eliminan. Eran alias auxiliares para la forma anterior de definePlugin.
¿Qué debo hacer?
Usa SandboxedPlugin de emdash/plugin para el mismo propósito. La exportación por defecto de un plugin sandboxed ya está tipada por su anotación satisfies SandboxedPlugin, por lo que no hay reemplazo para isStandardPluginDefinition; identifica un plugin por su estructura ({ hooks?, routes? }) si lo necesitas.
Renombrado: el tipo de tiempo de ejecución SandboxedPlugin ahora es SandboxedPluginInstance
Esto solo afecta a autores de un SandboxRunner personalizado, como @emdash-cms/cloudflare. La mayoría de los autores de plugins pueden omitir esto.
SandboxedPlugin de emdash ahora se refiere a la forma de origen orientada al autor. El identificador de tiempo de ejecución devuelto por SandboxRunner.load es SandboxedPluginInstance.
¿Qué debo hacer?
Si importas SandboxedPlugin de emdash para tipar un sandbox runner o mantener identificadores de plugins de tiempo de ejecución, cambia la importación a SandboxedPluginInstance:
import type { SandboxedPlugin } from "emdash";
import type { SandboxedPluginInstance } from "emdash";
Informa a tus usuarios
Los sitios que instalen tu plugin también necesitan cambiar su importación. Indícales la nueva forma: elimina las llaves y los ().
import { helloPlugin } from "@my-org/plugin-hello";
import hello from "@my-org/plugin-hello";
export default defineConfig({
integrations: [
emdash({
sandboxed: [helloPlugin()],
sandboxed: [hello],
}),
],
});
Si tu plugin aceptaba configuración a través de su factory, esa configuración se mueve a la configuración de plugins de la interfaz de administración. Léela en tiempo de ejecución a través de ctx.kv o settings. Ver Configuración.