プラグインの設定

このページ

プラグインには設定が必要です — 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.kvsettings: 付き)
プラグイン内部状態ctx.kvstate: 付き)
ドキュメントのコレクション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 として保存します。

これによりプラグイン同士が誤ってデータを上書きすることが防がれます。