プラグインには設定が必要です — API キー、機能フラグ、表示設定など。EmDash は 2 つの仕組みを提供します: 管理画面で設定可能なオプション用の設定スキーマと、プログラムからアクセスするための KV ストアです。
設定スキーマ
admin.settingsSchema で設定スキーマを宣言すると、管理 UI が自動生成されます。
import { definePlugin } from "emdash";
export default definePlugin({
id: "seo",
version: "1.0.0",
admin: {
settingsSchema: {
siteTitle: {
type: "string",
label: "Site Title",
description: "Used in title tags and meta",
default: "",
},
maxTitleLength: {
type: "number",
label: "Max Title Length",
description: "Characters before truncation",
default: 60,
min: 30,
max: 100,
},
generateSitemap: {
type: "boolean",
label: "Generate Sitemap",
description: "Automatically generate sitemap.xml",
default: true,
},
defaultRobots: {
type: "select",
label: "Default Robots",
options: [
{ value: "index,follow", label: "Index & Follow" },
{ value: "noindex,follow", label: "No Index, Follow" },
{ value: "noindex,nofollow", label: "No Index, No Follow" },
],
default: "index,follow",
},
apiKey: {
type: "secret",
label: "API Key",
description: "Encrypted at rest",
},
},
},
});
EmDash がプラグインの管理セクションに設定フォームを生成します。ユーザーはコードに触れずに設定を編集できます。
フィールド型
String
単一行または複数行の文字列用テキスト入力。
siteTitle: {
type: "string",
label: "Site Title",
description: "Optional help text",
default: "My Site",
multiline: false // true でテキストエリア
}
Number
オプションの最小/最大制約付き数値入力。
maxItems: {
type: "number",
label: "Maximum Items",
default: 100,
min: 1,
max: 1000
}
Boolean
true/false 値用のトグルスイッチ。
enabled: {
type: "boolean",
label: "Enabled",
description: "Turn this feature on or off",
default: true
}
Select
定義済みオプション用のドロップダウン。
theme: {
type: "select",
label: "Theme",
options: [
{ value: "light", label: "Light" },
{ value: "dark", label: "Dark" },
{ value: "auto", label: "System" }
],
default: "auto"
}
Secret
API キーなどの機密値用の暗号化フィールド。保存後はクライアントに送信されません。
apiKey: {
type: "secret",
label: "API Key",
description: "Stored encrypted"
}
設定へのアクセス
フックとルートで ctx.kv 経由で設定を読み取ります。
"content:beforeSave": async (event, ctx) => {
// 設定を読み取り
const maxLength = await ctx.kv.get<number>("settings:maxTitleLength");
const apiKey = await ctx.kv.get<string>("settings:apiKey");
// 未設定時はデフォルトを使用
const limit = maxLength ?? 60;
ctx.log.info("Using max length", { limit });
return event.content;
}
設定は慣例として settings: プレフィックスで保存されます。これによりユーザー設定値とプラグイン内部状態が区別されます。
KV ストア API
KV ストア(ctx.kv)はプラグインデータ用の汎用キーバリューストアです。
interface KVAccess {
get<T>(key: string): Promise<T | null>;
set(key: string, value: unknown): Promise<void>;
delete(key: string): Promise<boolean>;
list(prefix?: string): Promise<Array<{ key: string; value: unknown }>>;
}
値の読み取り
// 単一値の取得
const enabled = await ctx.kv.get<boolean>("settings:enabled");
// 型付きで取得
const config = await ctx.kv.get<{ url: string; timeout: number }>("state:config");
値の書き込み
// 値を設定
await ctx.kv.set("settings:lastSync", new Date().toISOString());
// 複合値の設定
await ctx.kv.set("state:cache", {
data: items,
expiry: Date.now() + 3600000,
});
値の一覧
// 全設定の一覧
const settings = await ctx.kv.list("settings:");
// 返却: [{ key: "settings:enabled", value: true }, ...]
// 全プラグインキーの一覧
const all = await ctx.kv.list();
値の削除
const deleted = await ctx.kv.delete("state:tempData");
// キーが存在した場合 true を返す
キー命名規則
プレフィックスで KV データを整理します。
| プレフィックス | 用途 | 例 |
|---|---|---|
settings: | ユーザー設定可能なプリファレンス | settings:apiKey |
state: | プラグイン内部状態 | state:lastSync |
cache: | キャッシュデータ | cache:results |
// 良い: 明確なプレフィックス
await ctx.kv.set("settings:webhookUrl", url);
await ctx.kv.set("state:lastRun", timestamp);
await ctx.kv.set("cache:feed", feedData);
// 避ける: プレフィックスなし、用途不明
await ctx.kv.set("url", url);
設定 vs ストレージ vs KV
適切なストレージメカニズムを選択します。
| ユースケース | メカニズム |
|---|---|
| 管理画面で編集可能な設定 | admin.settingsSchema + ctx.kv(settings: 付き) |
| プラグイン内部状態 | ctx.kv(state: 付き) |
| ドキュメントのコレクション | ctx.storage |
設定はユーザー設定可能な値 — 管理者が変更する可能性のあるもの。自動生成 UI が付きます。
KV はタイムスタンプ、同期カーソル、キャッシュ計算などの内部状態用。UI なし、コードのみ。
ストレージはインデックス付きクエリを伴うドキュメントコレクション — フォーム送信、監査ログなど。
ルートでの設定の読み込み
API ルートで管理 UI コンポーネントに設定を公開できます。
routes: {
settings: {
handler: async (ctx) => {
const settings = await ctx.kv.list("settings:");
const result: Record<string, unknown> = {};
for (const entry of settings) {
const key = entry.key.replace("settings:", "");
result[key] = entry.value;
}
return result;
}
},
"settings/save": {
handler: async (ctx) => {
const input = ctx.input as Record<string, unknown>;
for (const [key, value] of Object.entries(input)) {
if (value !== undefined) {
await ctx.kv.set(`settings:${key}`, value);
}
}
return { success: true };
}
}
}
デフォルト値
settingsSchema の設定は自動的に永続化されません。管理 UI でのデフォルト値です。コードでは値がない場合を処理してください。
"content:afterSave": async (event, ctx) => {
// 常にフォールバックを提供
const enabled = await ctx.kv.get<boolean>("settings:enabled") ?? true;
const maxItems = await ctx.kv.get<number>("settings:maxItems") ?? 100;
if (!enabled) return;
// ...
}
または plugin:install でデフォルトを永続化します。
hooks: {
"plugin:install": async (_event, ctx) => {
// スキーマのデフォルトを永続化
await ctx.kv.set("settings:enabled", true);
await ctx.kv.set("settings:maxItems", 100);
}
}
ストレージの実装
KV 値はプラグイン名前空間付きのキーで _options テーブルに保存されます。
INSERT INTO _options (name, value) VALUES
('plugin:seo:settings:siteTitle', '"My Site"'),
('plugin:seo:settings:maxTitleLength', '60');
plugin:seo: プレフィックスは自動追加されます。コードでは settings:siteTitle を使い、EmDash が plugin:seo:settings:siteTitle として保存します。
これによりプラグイン同士が誤ってデータを上書きすることが防がれます。