Zum Inhalt springen

Plugin-Einstellungen

Plugins brauchen oft Konfiguration, etwa API-Schlüssel, Feature-Flags oder Anzeigeoptionen. EmDash stellt dafür zwei Mechanismen bereit: ein Einstellungsschema für administrativ bearbeitbare Optionen und einen KV-Store für programmatischen Zugriff.

Deklarieren Sie ein Einstellungsschema in admin.settingsSchema, um automatisch eine Admin-Oberfläche zu generieren:

import { definePlugin } from "emdash";
export default definePlugin({
id: "seo",
version: "1.0.0",
admin: {
settingsSchema: {
siteTitle: {
type: "string",
label: "Website-Titel",
description: "Wird in Titel-Tags und Metadaten verwendet",
default: "",
},
maxTitleLength: {
type: "number",
label: "Maximale Titellänge",
description: "Anzahl der Zeichen vor dem Abschneiden",
default: 60,
min: 30,
max: 100,
},
generateSitemap: {
type: "boolean",
label: "Sitemap erzeugen",
description: "Erzeugt sitemap.xml automatisch",
default: true,
},
defaultRobots: {
type: "select",
label: "Robots-Vorgabe",
options: [
{ value: "index,follow", label: "Indexieren und folgen" },
{ value: "noindex,follow", label: "Nicht indexieren, folgen" },
{ value: "noindex,nofollow", label: "Nicht indexieren, nicht folgen" },
],
default: "index,follow",
},
apiKey: {
type: "secret",
label: "API-Schlüssel",
description: "Wird verschlüsselt gespeichert",
},
},
},
});

EmDash generiert ein Einstellungsformular im Admin-Bereich des Plugins. Benutzer können Einstellungen bearbeiten, ohne den Code anzufassen.

Texteingabe für einzeilige oder mehrzeilige Zeichenketten.

siteTitle: {
type: "string",
label: "Website-Titel",
description: "Optionaler Hilfetext",
default: "Meine Website",
multiline: false // Für Textarea auf true setzen
}

Numerische Eingabe mit optionalen Min-/Max-Beschränkungen.

maxItems: {
type: "number",
label: "Maximale Anzahl",
default: 100,
min: 1,
max: 1000
}

Umschalter für Wahr/Falsch-Werte.

enabled: {
type: "boolean",
label: "Aktiviert",
description: "Schaltet diese Funktion ein oder aus",
default: true
}

Dropdown für vordefinierte Optionen.

theme: {
type: "select",
label: "Design",
options: [
{ value: "light", label: "Hell" },
{ value: "dark", label: "Dunkel" },
{ value: "auto", label: "System" }
],
default: "auto"
}

Verschlüsseltes Feld für sensible Werte wie API-Schlüssel. Wird nach dem Speichern niemals an den Client gesendet.

apiKey: {
type: "secret",
label: "API-Schlüssel",
description: "Wird verschlüsselt gespeichert"
}

Lesen Sie Einstellungen in Hooks und Routen über ctx.kv:

"content:beforeSave": async (event, ctx) => {
// Eine Einstellung lesen
const maxLength = await ctx.kv.get<number>("settings:maxTitleLength");
const apiKey = await ctx.kv.get<string>("settings:apiKey");
// Verwenden Sie Standardwerte, falls nicht gesetzt
const limit = maxLength ?? 60;
ctx.log.info("Verwende maximale Länge", { limit });
return event.content;
}

Einstellungen werden per Konvention mit dem Präfix settings: gespeichert. Dies unterscheidet benutzerkonfigurierbare Werte vom internen Plugin-Zustand.

Der KV-Store (ctx.kv) ist ein allgemeiner Schlüssel-Wert-Speicher 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 }>>;
}
// Einzelnen Wert abrufen
const enabled = await ctx.kv.get<boolean>("settings:enabled");
// Mit Typ abrufen
const config = await ctx.kv.get<{ url: string; timeout: number }>("state:config");
// Einen Wert setzen
await ctx.kv.set("settings:lastSync", new Date().toISOString());
// Komplexe Werte setzen
await ctx.kv.set("state:cache", {
data: items,
expiry: Date.now() + 3600000,
});
// Alle Einstellungen auflisten
const settings = await ctx.kv.list("settings:");
// Gibt zurück: [{ key: "settings:enabled", value: true }, ...]
// Alle Plugin-Schlüssel auflisten
const all = await ctx.kv.list();
const deleted = await ctx.kv.delete("state:tempData");
// Gibt true zurück, wenn der Schlüssel existierte

Verwenden Sie Präfixe, um KV-Daten zu organisieren:

PräfixZweckBeispiel
settings:Benutzerkonfigurierbare Einstellungensettings:apiKey
state:Interner Plugin-Zustandstate:lastSync
cache:Zwischengespeicherte Datencache:results
// Gut: klare Präfixe
await ctx.kv.set("settings:webhookUrl", url);
await ctx.kv.set("state:lastRun", timestamp);
await ctx.kv.set("cache:feed", feedData);
// Vermeiden: kein Präfix, unklarer Zweck
await ctx.kv.set("url", url);

Wählen Sie den richtigen Speichermechanismus:

AnwendungsfallMechanismus
Admin-bearbeitbare Einstellungenadmin.settingsSchema + ctx.kv mit settings:
Interner Plugin-Zustandctx.kv mit state:
Sammlungen von Dokumentenctx.storage

Einstellungen sind für benutzerkonfigurierbare Werte gedacht, also für Dinge, die ein Admin ändern können soll. Dafür gibt es eine automatisch generierte Oberfläche.

KV ist für internen Zustand gedacht, etwa Zeitstempel, Synchronisations-Cursor oder zwischengespeicherte Berechnungen. Keine UI, nur Code.

Storage ist für Dokumentensammlungen mit indizierten Abfragen gedacht, zum Beispiel Formulareinreichungen, Audit-Logs und ähnliche Daten.

API-Routen können Einstellungen für Admin-UI-Komponenten bereitstellen:

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 };
}
}
}

Einstellungen aus settingsSchema werden nicht automatisch gespeichert. Sie dienen nur als Standardwerte in der Admin-Oberfläche. Ihr Code sollte fehlende Werte daher immer behandeln:

"content:afterSave": async (event, ctx) => {
// Immer einen Fallback bereitstellen
const enabled = await ctx.kv.get<boolean>("settings:enabled") ?? true;
const maxItems = await ctx.kv.get<number>("settings:maxItems") ?? 100;
if (!enabled) return;
// ...
}

Alternativ können Sie Standardwerte in plugin:install persistieren:

hooks: {
"plugin:install": async (_event, ctx) => {
// Standards des Schemas speichern
await ctx.kv.set("settings:enabled", true);
await ctx.kv.set("settings:maxItems", 100);
}
}

KV-Werte werden in der Tabelle _options mit plugin-namespaceten Schlüsseln gespeichert:

INSERT INTO _options (name, value) VALUES
('plugin:seo:settings:siteTitle', '"Meine Website"'),
('plugin:seo:settings:maxTitleLength', '60');

Das Präfix plugin:seo: wird automatisch hinzugefügt. Ihr Code verwendet settings:siteTitle, und EmDash speichert es als plugin:seo:settings:siteTitle.

Dies stellt sicher, dass Plugins sich nicht versehentlich gegenseitig überschreiben.