Pular para o conteúdo

Visão Geral do Sistema de Plugins

O sistema de plugins do EmDash permite que você estenda o CMS sem modificar o código principal. Os plugins podem conectar-se a eventos do ciclo de vida do conteúdo, armazenar seus próprios dados, expor configurações aos administradores e adicionar interface personalizada ao painel administrativo.

Os plugins do EmDash são transformadores de configuração, não aplicações separadas. Eles são executados no mesmo processo do seu site Astro e interagem através de interfaces bem definidas.

Princípios-chave:

  • Declarativo — Hooks, armazenamento e rotas são declarados no momento da definição, não registrados dinamicamente
  • Type-safe — Suporte total ao TypeScript com objetos de contexto tipados
  • Pronto para sandboxing — APIs projetadas para execução isolada no Cloudflare Workers
  • Baseado em capacidades — Os plugins declaram o que precisam; o runtime impõe o acesso

Conectar-se a eventos

Execute código antes ou depois de salvar conteúdo, uploads de mídia e eventos do ciclo de vida do plugin.

Armazenar dados

Persista dados específicos do plugin em coleções indexadas sem escrever migrações de banco de dados.

Expor configurações

Declare um esquema de configurações e obtenha uma interface administrativa gerada automaticamente para configuração.

Adicionar páginas administrativas

Crie páginas administrativas personalizadas e widgets de painel com componentes React.

Criar rotas de API

Exponha endpoints para a interface administrativa do seu plugin ou integrações externas.

Fazer requisições HTTP

Chame APIs externas com restrições de host declaradas para segurança.

Cada plugin é criado com definePlugin():

import { definePlugin } from "emdash";
export default definePlugin({
id: "my-plugin",
version: "1.0.0",
// Quais APIs o plugin precisa acessar
capabilities: ["read:content", "network:fetch"],
// Hosts para os quais o plugin pode fazer requisições HTTP
allowedHosts: ["api.example.com"],
// Coleções de armazenamento persistente
storage: {
entries: {
indexes: ["userId", "createdAt"],
},
},
// Manipuladores de eventos
hooks: {
"content:afterSave": async (event, ctx) => {
ctx.log.info("Content saved", { id: event.content.id });
},
},
// Endpoints da API REST
routes: {
status: {
handler: async (ctx) => ({ ok: true }),
},
},
// Configuração da interface administrativa
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
},
pages: [{ path: "/dashboard", label: "Dashboard" }],
widgets: [{ id: "status", size: "half" }],
},
});

Cada hook e manipulador de rota recebe um objeto PluginContext com acesso a:

PropriedadeDescriçãoDisponibilidade
ctx.storageColeções de documentos do pluginSempre (se declarado)
ctx.kvArmazenamento chave-valor para configurações e estadoSempre
ctx.contentLer/escrever conteúdo do siteCom read:content ou write:content
ctx.mediaLer/escrever arquivos de mídiaCom read:media ou write:media
ctx.httpCliente HTTP para requisições externasCom network:fetch
ctx.logLogger estruturado (debug, info, warn, error)Sempre
ctx.pluginMetadados do plugin (id, versão)Sempre
ctx.siteInformações do site: name, url, localeSempre
ctx.url()Gerar URLs absolutas a partir de caminhosSempre
ctx.usersLer informações do usuário: get(), getByEmail(), list()Com read:users
ctx.cronAgendar tarefas: schedule(), cancel(), list()Sempre
ctx.emailEnviar email: send()Com email:send + provedor configurado

A forma do contexto é idêntica em todos os hooks e rotas. Propriedades controladas por capacidade estão presentes apenas quando o plugin declara a capacidade necessária.

As capacidades determinam quais APIs estão disponíveis no contexto do plugin:

CapacidadeConcede Acesso A
read:contentctx.content.get(), ctx.content.list()
write:contentctx.content.create(), ctx.content.update(), ctx.content.delete()
read:mediactx.media.get(), ctx.media.list()
write:mediactx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete()
network:fetchctx.http.fetch() (restrito a allowedHosts)
network:fetch:anyctx.http.fetch() (sem restrições — para URLs configuradas pelo usuário)
read:usersctx.users.get(), ctx.users.getByEmail(), ctx.users.list()
email:sendctx.email.send() (requer um plugin de provedor)
email:provideRegistrar hook exclusivo email:deliver (provedor de transporte)
email:interceptRegistrar hooks email:beforeSend / email:afterSend
page:injectRegistrar hooks page:metadata / page:fragments

Registre plugins na sua configuração do Astro:

typescript title="astro.config.mjs"
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 })],
}),
],
});

Os plugins são resolvidos no momento da compilação. A ordem importa para hooks com a mesma prioridade—os plugins anteriores no array são executados primeiro.

O EmDash suporta dois modos de execução de plugins:

ModoDescriçãoPlataforma
TrustedPlugins executados em processo com acesso totalQualquer
SandboxedPlugins executados em workers V8 isoladosApenas Cloudflare

No modo trusted (padrão), as capacidades são documentação—os plugins podem acessar qualquer coisa. No modo sandboxed, as capacidades são impostas no nível do runtime.