Plugins brauchen Konfiguration—API-Keys, Feature-Flags, Anzeigeeinstellungen. EmDash bietet zwei Mechanismen: ein Einstellungsschema für im Admin konfigurierbare Optionen und einen KV-Store für programmatischen Zugriff.
Einstellungsschema
Deklarieren Sie ein Einstellungsschema in admin.settingsSchema, um automatisch eine Admin-Oberfläche zu erzeugen:
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 erzeugt ein Einstellungsformular im Admin-Bereich des Plugins. Nutzer bearbeiten Einstellungen, ohne Code anzufassen.
Feldtypen
String
Texteingabe für einzeilige oder mehrzeilige Strings.
siteTitle: {
type: "string",
label: "Site Title",
description: "Optional help text",
default: "My Site",
multiline: false // Set true for textarea
}
Number
Numerische Eingabe mit optionalen min/max-Grenzen.
maxItems: {
type: "number",
label: "Maximum Items",
default: 100,
min: 1,
max: 1000
}
Boolean
Schalter für true/false-Werte.
enabled: {
type: "boolean",
label: "Enabled",
description: "Turn this feature on or off",
default: true
}
Select
Dropdown mit vordefinierten Optionen.
theme: {
type: "select",
label: "Theme",
options: [
{ value: "light", label: "Light" },
{ value: "dark", label: "Dark" },
{ value: "auto", label: "System" }
],
default: "auto"
}
Secret
Verschlüsseltes Feld für sensible Werte wie API-Keys. Nach dem Speichern nie an den Client gesendet.
apiKey: {
type: "secret",
label: "API Key",
description: "Stored encrypted"
}
Zugriff auf Einstellungen
Lesen Sie Einstellungen in Hooks und Routes über ctx.kv:
"content:beforeSave": async (event, ctx) => {
// Read a setting
const maxLength = await ctx.kv.get<number>("settings:maxTitleLength");
const apiKey = await ctx.kv.get<string>("settings:apiKey");
// Use defaults if not set
const limit = maxLength ?? 60;
ctx.log.info("Using max length", { limit });
return event.content;
}
Einstellungen werden per Konvention mit dem Präfix settings: gespeichert. So unterscheiden sich nutzerkonfigurierbare Werte vom internen Plugin-Zustand.
KV-Store-API
Der KV-Store (ctx.kv) ist ein generischer Key-Value-Store für Plugin-Daten:
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 }>>;
}
Werte lesen
// Get a single value
const enabled = await ctx.kv.get<boolean>("settings:enabled");
// Get with type
const config = await ctx.kv.get<{ url: string; timeout: number }>("state:config");
Werte schreiben
// Set a value
await ctx.kv.set("settings:lastSync", new Date().toISOString());
// Set complex values
await ctx.kv.set("state:cache", {
data: items,
expiry: Date.now() + 3600000,
});
Werte auflisten
// List all settings
const settings = await ctx.kv.list("settings:");
// Returns: [{ key: "settings:enabled", value: true }, ...]
// List all plugin keys
const all = await ctx.kv.list();
Werte löschen
const deleted = await ctx.kv.delete("state:tempData");
// Returns true if key existed
Namenskonventionen für Keys
Verwenden Sie Präfixe, um KV-Daten zu strukturieren:
| Präfix | Zweck | Beispiel |
|---|---|---|
settings: | Nutzerkonfigurierbare Einstellungen | settings:apiKey |
state: | Interner Plugin-Zustand | state:lastSync |
cache: | Zwischengespeicherte Daten | cache:results |
// Good: clear prefixes
await ctx.kv.set("settings:webhookUrl", url);
await ctx.kv.set("state:lastRun", timestamp);
await ctx.kv.set("cache:feed", feedData);
// Avoid: no prefix, unclear purpose
await ctx.kv.set("url", url);
Einstellungen vs. Storage vs. KV
Wählen Sie den passenden Speichermechanismus:
| Anwendungsfall | Mechanismus |
|---|---|
| Im Admin bearbeitbare Einstellungen | admin.settingsSchema + ctx.kv mit settings: |
| Interner Plugin-Zustand | ctx.kv mit state: |
| Dokumentkollektionen | ctx.storage |
Einstellungen sind nutzerkonfigurierbare Werte—Dinge, die ein Admin ändern könnte. Sie erhalten eine automatisch erzeugte UI.
KV ist für internen Zustand wie Zeitstempel, Sync-Cursor oder gecachte Berechnungen. Keine UI, nur Code.
Storage ist für Dokumentkollektionen mit indexierten Abfragen—Formularübermittlungen, Audit-Logs usw.
Einstellungen in Routes laden
API-Routes können Einstellungen an Admin-UI-Komponenten liefern:
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 };
}
}
}
Standardwerte
Einstellungen aus settingsSchema werden nicht automatisch persistiert. Sie sind Standardwerte in der Admin-UI. Ihr Code sollte fehlende Werte abfangen:
"content:afterSave": async (event, ctx) => {
// Always provide a fallback
const enabled = await ctx.kv.get<boolean>("settings:enabled") ?? true;
const maxItems = await ctx.kv.get<number>("settings:maxItems") ?? 100;
if (!enabled) return;
// ...
}
Alternativ Standardwerte in plugin:install persistieren:
hooks: {
"plugin:install": async (_event, ctx) => {
// Persist schema defaults
await ctx.kv.set("settings:enabled", true);
await ctx.kv.set("settings:maxItems", 100);
}
}
Speicher-Implementierung
KV-Werte werden in der Tabelle _options mit plugin-namespaced Keys gespeichert:
INSERT INTO _options (name, value) VALUES
('plugin:seo:settings:siteTitle', '"My Site"'),
('plugin:seo:settings:maxTitleLength', '60');
Das Präfix plugin:seo: wird automatisch ergänzt. Ihr Code nutzt settings:siteTitle, und EmDash speichert es als plugin:seo:settings:siteTitle.
So können Plugins einander nicht versehentlich Daten überschreiben.