Zum Inhalt springen

Was ein Plugin ist

TrakState bringt kein festes Datenmodell mit, und es bringt auch keine feste Funktionsliste mit. Was das Produkt kann, entsteht zu einem großen Teil aus Plugins — die eigenen Pakete des Herstellers laufen über dieselbe Naht wie Ihre.

Ein Plugin ist ein signiertes ZIP-Archiv mit einer manifest.json in der Wurzel. Darin stecken bis zu drei Dinge:

Teil Was es ist Wann Sie ihn brauchen
Oberfläche Ein Module-Federation-Remote, das die Schale zur Laufzeit lädt Nur wenn Ihr Plugin eigene Seiten hat
Backend Code auf dem Server — ein TypeScript-Modul oder ein eigener Prozess Nur wenn serverseitig etwas passieren soll
Deklarationen Contributions: Routen, Befehle, Einstellungen, Seitentypen, Konnektoren Fast immer

Ein Konnektor-Plugin ist reines Backend. Es liefert keine Oberfläche und kein Stylesheet: das Einstellungsformular entsteht aus dem, was der Konnektor-Typ deklariert. Wenn Sie für einen Konnektor Oberfläche schreiben, ist etwas schiefgelaufen.

Ein Plugin wird gegen dieses Paket gebaut und gegen nichts anderes — nie gegen den Quelltext des Hosts. Was dort exportiert ist, ist das, was der Host weiter zu erfüllen verspricht. Was nicht exportiert ist, gehört nicht zum Vertrag, so praktisch es von außen aussieht.

import { parseManifest, type PluginManifest, type Plugin, type PluginHost } from '@prodlog/sdk';

Das SDK trägt vier Gruppen von Dingen:

  • Manifest — Schema, Typen und die Prüffunktionen parseManifest / parseUploadedManifest.
  • Laufzeit — Plugin, PluginHost, CapabilityDefinition, InvocationContext, CapabilityConflictError.
  • Oberfläche — ShellContext, Surface, ScopedStore, PageInstance und der Seitentyp-Vertrag.
  • Konnektoren und Konfiguration — ConnectorType, connectorContribution, das Konfigurationsdokument eines Templates.

Das ist keine Höflichkeit, sondern die tragende Grenze des Systems.

  • Keine Datenbankverbindung. Kein Handle, keine Zugangsdaten. Jede Abfrage läuft über die vermittelte Host-Oberfläche und damit unter dem Mandantenkontext des Aufrufs (Row Level Security).
  • Kein Zugriff auf fremde Plugin-Daten. Tabellen sind auf den Plugin-Namensraum festgenagelt, und der Host prüft das vor dem Laden.
  • Kein Dateisystem außerhalb des eigenen Arbeitsverzeichnisses.
  • Keine Umgebungsvariablen außer einer kurzen Erlaubnisliste (TZ, LANG, LC_ALL, NODE_ENV). DATABASE_URL und alles Geheime sind strukturell nicht erreichbar.
  • Kein Mandantenwechsel. Auf dem Aufrufkontext gibt es überhaupt kein Feld, mit dem ein Plugin einen anderen Mandanten benennen könnte.

Wenn Ihnen etwas fehlt, ist das ein Gespräch über den Vertrag — kein Loch, um das man herumbaut.

Diese Verwechslung ist der häufigste Fehler beim ersten Paket.

  • permissions sagt, was Ihr Code auf den Host-Schnittstellen erreichen darf: data:read, data:write, plugin:manage, capability:invoke, audit:read, net:request, net:socket. Ein Betreiber liest diese Liste auf dem Installationsdialog.
  • rbacPermissions sagt, was ein Mensch in Ihrem eigenen Namensraum tun darf, zum Beispiel acme.tcp:configure.

Beide Riegel müssen halten. Ein fehlendes data:write endet in permission_denied, auch wenn die Rolle des Benutzers alles erlaubt — und umgekehrt.

SDK-Version und Host-Version bewegen sich im Gleichschritt. Ihr Manifest nennt den Bereich, gegen den Sie gebaut haben:

"sdk": "^0.9.0"

Ein Host stellt seine eigene Vertragsversion bereit plus jede ältere, die er noch vollständig erfüllt. Der Host 0.9.0 stellt damit 0.9.0, 0.8.0, 0.7.0 und 0.6.0 bereit; ein Paket auf ^0.6.0 läuft dort unverändert weiter. Das ist eine gepflegte Tabelle, keine Regel über 0.x-Versionen: 0.6.0 war selbst brechend. Lesen Sie, was sich geändert hat, bevor Sie eine Minor-Version überspringen.

Passt der Bereich nicht, wird das Paket mit sdk_incompatible abgelehnt und lädt nie.

Der Weg von der leeren Mappe zum installierten Paket

Abschnitt betitelt „Der Weg von der leeren Mappe zum installierten Paket“
  1. Manifest schreiben und mit parseManifest gegen den eigenen Übersetzer prüfen.
  2. Backend-Art wählen — in-process oder Sidecar.
  3. Bauen und packen — deterministisch, sonst wandert der Digest bei jedem Bau.
  4. Signieren — Ed25519 über die Archivbytes.
  5. Installieren — hochladen oder über den Katalog des Betreibers.
  6. Einschalten — Installieren ist nicht Einschalten. Erst beim Einschalten startet ein Backend.

Jeder dieser Schritte hat weiter unten in diesem Kapitel ein eigenes Thema.

Im Produkt-Arbeitsbereich liegen vier echte Pakete, und sie decken zusammen jede Bauform ab:

Paket Wofür es das Muster ist
plugins/tcp Sidecar-Konnektor: Python-Backend, gehaltener Socket, Konnektor-Typ als Daten, eigenes Pack-Skript
plugins/tenant-user Elf Capabilities, zwei Rechte-Achsen, ein System-Plugin ohne eigene Tabellen
plugins/board Seitentyp, in-process-Backend, eigene Tabellen aus der Manifest-Beschreibung

@prodlog/sdk liegt noch nicht in einer öffentlichen Registry. npm install @prodlog/sdk funktioniert von außen nicht; heute wird ein Plugin im Arbeitsbereich des Produkts gebaut. Diese Anleitung wandert mit, sobald sich das ändert.