コンテンツにスキップ

プラグインシステム概要

EmDashのプラグインシステムにより、コアコードを変更せずにCMSを拡張できます。プラグインはコンテンツライフサイクルイベントにフックし、独自のデータを保存し、管理者に設定を公開し、管理パネルにカスタムUIを追加できます。

EmDashプラグインは別個のアプリケーションではなく、設定トランスフォーマーです。これらはAstroサイトと同じプロセスで実行され、明確に定義されたインターフェースを通じて相互作用します。

主要原則:

  • 宣言的 — フック、ストレージ、ルートは定義時に宣言され、動的に登録されません
  • 型安全 — 型付けされたコンテキストオブジェクトによる完全なTypeScriptサポート
  • サンドボックス対応 — Cloudflare Workersでの分離実行のために設計されたAPI
  • 能力ベース — プラグインは必要なものを宣言し、ランタイムがアクセスを強制します

イベントにフック

コンテンツ保存、メディアアップロード、プラグインライフサイクルイベントの前後にコードを実行します。

データを保存

データベースマイグレーションを書かずに、インデックス付きコレクションにプラグイン固有のデータを永続化します。

設定を公開

設定スキーマを宣言し、設定用の自動生成された管理UIを取得します。

管理ページを追加

Reactコンポーネントでカスタム管理ページとダッシュボードウィジェットを作成します。

APIルートを作成

プラグインの管理UIまたは外部インテグレーション用のエンドポイントを公開します。

HTTPリクエストを実行

セキュリティのため、宣言されたホスト制限で外部APIを呼び出します。

すべてのプラグインはdefinePlugin()で作成されます:

import { definePlugin } from "emdash";
export default definePlugin({
id: "my-plugin",
version: "1.0.0",
// プラグインがアクセスを必要とするAPI
capabilities: ["read:content", "network:fetch"],
// プラグインがHTTPリクエストを送信できるホスト
allowedHosts: ["api.example.com"],
// 永続ストレージコレクション
storage: {
entries: {
indexes: ["userId", "createdAt"],
},
},
// イベントハンドラー
hooks: {
"content:afterSave": async (event, ctx) => {
ctx.log.info("Content saved", { id: event.content.id });
},
},
// REST APIエンドポイント
routes: {
status: {
handler: async (ctx) => ({ ok: true }),
},
},
// 管理UI設定
admin: {
settingsSchema: {
apiKey: { type: "secret", label: "API Key" },
},
pages: [{ path: "/dashboard", label: "Dashboard" }],
widgets: [{ id: "status", size: "half" }],
},
});

すべてのフックとルートハンドラーは、以下へのアクセス権を持つPluginContextオブジェクトを受け取ります:

プロパティ説明可用性
ctx.storageプラグインのドキュメントコレクション常時 (宣言されている場合)
ctx.kv設定と状態のためのキーバリューストア常時
ctx.contentサイトコンテンツの読み書きread:contentまたはwrite:contentを持つ場合
ctx.mediaメディアファイルの読み書きread:mediaまたはwrite:mediaを持つ場合
ctx.http外部リクエストのためのHTTPクライアントnetwork:fetchを持つ場合
ctx.log構造化ロガー (debug, info, warn, error)常時
ctx.pluginプラグインメタデータ (id, version)常時
ctx.siteサイト情報: name, url, locale常時
ctx.url()パスから絶対URLを生成常時
ctx.usersユーザー情報の読み取り: get(), getByEmail(), list()read:usersを持つ場合
ctx.cronタスクのスケジュール: schedule(), cancel(), list()常時
ctx.emailメール送信: send()email:send + プロバイダー設定済みの場合

コンテキストの形状はすべてのフックとルートで同一です。能力で制限されたプロパティは、プラグインが必要な能力を宣言した場合にのみ存在します。

能力は、プラグインコンテキストでどのAPIが利用可能かを決定します:

能力アクセス権を付与
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() (allowedHostsに制限)
network:fetch:anyctx.http.fetch() (無制限 — ユーザー設定URL用)
read:usersctx.users.get(), ctx.users.getByEmail(), ctx.users.list()
email:sendctx.email.send() (プロバイダープラグインが必要)
email:provideemail:deliver排他フックの登録 (トランスポートプロバイダー)
email:interceptemail:beforeSend / email:afterSendフックの登録
page:injectpage:metadata / page:fragmentsフックの登録

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

プラグインはビルド時に解決されます。同じ優先度を持つフックの場合、順序が重要です—配列内で先に指定されたプラグインが最初に実行されます。

EmDashは2つのプラグイン実行モードをサポートしています:

モード説明プラットフォーム
信頼済みプラグインはフルアクセス権限でプロセス内で実行されます任意
サンドボックス化プラグインは分離されたV8ワーカーで実行されますCloudflareのみ

信頼済みモード(デフォルト)では、機能は文書化された通りです—プラグインは何にでもアクセスできます。サンドボックス化モードでは、機能はランタイムレベルで強制されます。