---
url: https://docs.ogmabox.com/de/plugins/README.md
description: >-
  Entwickeln, paketieren, installieren, aktivieren und verteilen Sie
  Ogma-Plugins mit Backend-Logik, Frontend-Panels, Befehlen, Berechtigungen und
  Marketplace-Metadaten.
---

# Ogma-Plugin-System {#ogma-plugin-system}

Ogma-Plugins erweitern das Tool um eigene Backend-Logik, Frontend-UI-Panels und Workflow-Schritte. Plugins werden lokal aus einem Verzeichnis auf dem Datenträger installiert, pro Projekt aktiviert und in einer Sandbox-Umgebung ausgeführt.

Dieses Dokument ist die zentrale Referenz für Plugin-Autoren.

Für den schnellstmöglichen Einstieg verwenden Sie den [Plugin-Schnellstart](/de/plugins/quickstart).

***

## Schnellstart {#quick-start}

### Minimales Backend-Plugin {#minimal-backend-plugin}

```
my-plugin/
  manifest.json
  backend/script.js
```

`manifest.json`:

```json
{
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "plugins": [
    {
      "kind": "backend",
      "id": "my-plugin-backend",
      "entrypoint": "backend/script.js"
    }
  ]
}
```

`backend/script.js` (ES2020; Imports sind mit einem Bundler möglich):

```js
async function init(sdk) {
  sdk.console.log("my-plugin started");

  sdk.events.onInterceptResponse(function(req, res) {
    if (res.getCode() === 403) {
      sdk.console.warn("403 on " + req.getUrl());
    }
  });
}
```

Das genügt für ein funktionierendes Plugin nur mit Backend. Belassen Sie es als einzelne Datei in `backend/script.js` und verweisen Sie in `manifest.json` direkt darauf.

### Build-Ablauf in einer Minute (TypeScript-Quellcode) {#one-minute-build-flow-typescript-source}

Wenn Sie TypeScript verwenden, nutzen Sie diese Struktur:

```text
my-plugin/
  manifest.json
  backend/
    src/index.ts
```

Build:

```bash
pnpm add -D @ogmabox/ogma-sdk esbuild typescript
pnpm exec esbuild backend/src/index.ts --bundle --format=iife --platform=neutral --external:@ogma/sdk --external:@ogmabox/ogma-sdk --outfile=backend/script.js
```

Installation: **Plugins > Installieren**, wählen Sie das Verzeichnis `my-plugin/` aus. Aktivieren Sie anschließend das Plugin.

***

## Manifest-Referenz {#manifest-reference}

`manifest.json` befindet sich im Stammverzeichnis des Pakets. Bei allen Feldern wird die Groß-/Kleinschreibung beachtet.

### Felder auf oberster Ebene {#top-level-fields}

| Feld | Erforderlich | Typ | Hinweise |
|-------|----------|------|-------|
| `id` | ja | Zeichenkette | Nur Kleinbuchstaben, Ziffern und Bindestriche. Maximal 64 Zeichen. Unter den installierten Plugins eindeutig. |
| `version` | ja | Zeichenkette | Semver: `MAJOR.MINOR.PATCH` |
| `name` | nein | Zeichenkette | Anzeigename in der Oberfläche. Standardmäßig `id`. |
| `description` | nein | Zeichenkette | Einzeilige Zusammenfassung. |
| `author` | nein | Objekt | `{ "name": "...", "email": "...", "url": "..." }` |
| `homepage` | nein | Zeichenkette | URL zum Quellcode-Repository oder zur Dokumentation. |
| `plugins` | ja | Array | Ein oder mehrere Plugin-Komponenteneinträge (siehe unten). |
| `permissions` | nein | Array | Liste der Namen erforderlicher Berechtigungen (siehe [Berechtigungen](#permissions)). |

### Plugin-Komponenteneintrag {#plugin-component-entry}

Jedes Objekt im Array `plugins` beschreibt eine Komponente.

**Backend-Komponente:**

```json
{
  "kind": "backend",
  "id": "my-plugin-backend",
  "entrypoint": "backend/script.js",
  "runtime": "javascript",
  "assets": "backend/assets"
}
```

**Frontend-Komponente:**

```json
{
  "kind": "frontend",
  "id": "my-plugin-frontend",
  "entrypoint": "frontend/script.js",
  "style": "frontend/style.css",
  "assets": "frontend/assets",
  "backend": { "id": "my-plugin-backend" }
}
```

| Feld | Erforderlich | Hinweise |
|-------|----------|-------|
| `kind` | ja | `"backend"` oder `"frontend"` |
| `id` | ja | Innerhalb des Manifests eindeutig. Kleinbuchstaben, Bindestriche. |
| `entrypoint` | ja | Relativer Pfad zur JS-Einstiegsdatei. |
| `style` | nein | CSS-Datei, die im Plugin-Iframe geladen wird. |
| `assets` | nein | Verzeichnis statischer Assets, die unter `/plugins/{id}/assets/` bereitgestellt werden. |
| `backend.id` | nein | Verknüpft eine Frontend-Komponente mit ihrer Backend-Komponente für `sdk.backend.*`-RPC. |
| `runtime` | nein (nur Backend) | `"javascript"` (Standard und einziger unterstützter Wert). |

***

## Backend-Plugin-API (sdk) {#backend-plugin-api-sdk}

Das Backend-Objekt `sdk` wird an Ihre Funktion `init(sdk)` übergeben. Alle Methoden sind synchron, sofern sie nicht mit `async` gekennzeichnet sind.

### `sdk.console` {#sdk-console}

```js
sdk.console.log("message")
sdk.console.warn("message")
sdk.console.error("message")
```

Schreibt in den Protokollpuffer des Plugins (sichtbar auf der Registerkarte Protokolle). Maximal 500 Einträge werden aufbewahrt. Jede Nachricht wird auf 1 KB gekürzt.

### `sdk.meta` {#sdk-meta}

```js
sdk.meta.id()          // > string: plugin id (e.g. "my-plugin")
sdk.meta.packageId()   // > string: same as id
sdk.meta.version()     // > string: semver (e.g. "1.0.0")
sdk.meta.path()        // > string: writable data directory for this plugin
```

`sdk.meta.path()` verweist auf das beschreibbare private Datenverzeichnis des Plugins, z. B. `~/.local/share/ogma/plugins/my-plugin/data`. Das Verzeichnis wird automatisch erstellt und kann verwendet werden, um Plugin-Daten über Neustarts hinweg dauerhaft zu speichern.

`sdk.storage`, `sdk.path` und `sdk.fs` stehen ebenfalls für Zustandsverwaltung und Dateihilfsfunktionen zur Verfügung.

### `sdk.storage` {#sdk-storage}

```js
sdk.storage.get("key")      // > string | null
sdk.storage.set("key", "value")
sdk.storage.delete("key")
sdk.storage.clear()
sdk.storage.keys()          // > string[]
```

`sdk.storage` ist auf die Plugin-ID beschränkt und bleibt über Plugin-Neustarts hinweg erhalten.

### `sdk.fs` {#sdk-fs}

```js
sdk.fs.readFile("relative/file.txt")      // > string
sdk.fs.writeFile("relative/file.txt", "text")
sdk.fs.appendFile("relative/file.txt", "more")
sdk.fs.exists("relative/file.txt")        // > boolean
sdk.fs.existsSync("relative/file.txt")    // > boolean
sdk.fs.list("relative/dir")              // > string[]
sdk.fs.mkdir("relative/dir")
```

`sdk.fs` ist auf Dateien unterhalb von `sdk.meta.path()` beschränkt.

`read` und `write` bleiben als Kompatibilitätsaliase für `readFile` und `writeFile` erhalten. Verwenden Sie `exists` oder `existsSync`, bevor Sie eine Datei erstellen, die Sie nicht überschreiben möchten. Diese APIs arbeiten in der Plugin-Laufzeit synchron; sie entsprechen nicht dem vollständigen Node.js-Modul `fs`. Der Dateizugriff von Plugins erfordert die Berechtigung `plugin_storage` und bleibt auf das private Datenverzeichnis des Plugins beschränkt. Workflow-JavaScript hat einen anderen Dateisystemkontext; siehe [Dateizugriff in Workflows](../app/workflows.md#javascript-and-files).

### `sdk.path` {#sdk-path}

```js
sdk.path.join("a", "b", "c")
sdk.path.basename("/tmp/file.txt")
sdk.path.dirname("/tmp/file.txt")
sdk.path.extname("file.txt")
sdk.path.resolve("/a", "b")
sdk.path.isAbsolute("/tmp/file.txt")
sdk.path.sep
```

### `sdk.events` {#sdk-events}

Registrieren Sie Callbacks für Ogma-Ereignisse. Alle Callbacks werden synchron innerhalb der QuickJS-Sandbox aufgerufen.

```js
sdk.events.onInterceptRequest(function(req) {
  // req: RequestSpecRaw
  // Return a modified RequestSpecRaw to mutate the request.
  // Return null/undefined to pass through unchanged.
});

sdk.events.onInterceptResponse(function(req, res) {
  // req: Request (read-only), res: Response (read-only)
  // Return value is ignored.
});

sdk.events.onProjectChange(function() {
  // no callback args
});

sdk.events.onFindingCreated(function(finding) {
  // finding: { id, title, reporter }
});
```

### `sdk.requests` {#sdk-requests}

```js
// Get a single HTTP entry by id
var entry = sdk.requests.get("entry-id");
// entry: { id, method, host, path, query, tls, ... } or null

// Search HTTP history
var results = sdk.requests.search({ limit: 20, offset: 0 });
// results: { entries: [...], total: N }

// Send an HTTP request (requires send_requests permission)
var response = await sdk.requests.send(spec);
// spec: RequestSpecRaw (see below)
// response: Response
```

`sdk.requests.send` erfordert, dass die Berechtigung `send_requests` im Manifest deklariert und vom Nutzer erteilt wird. Siehe [Berechtigungen](#permissions).

### `sdk.findings` {#sdk-findings}

```js
// Create a finding (requires write_findings permission)
sdk.findings.create({
  title: "SSRF via redirect",
  reporter: "my-plugin",
  dedupeKey: "ssrf-" + request.getId(),
  request: { id: request.getId() }
});

// Check if a finding already exists (dedup check)
var exists = sdk.findings.exists({ dedupeKey: "ssrf-abc" });

// List findings
var page = sdk.findings.list({ limit: 20, offset: 0 });

// Get a single finding
var finding = sdk.findings.get("finding-id");
```

Aufrufgrenzen für `sdk.findings.create`: 10 pro Minute, 500 pro Plugin-Sitzung, 3 pro Ereignis-Callback.

### `sdk.api` {#sdk-api}

Registrieren Sie Backend-RPC-Funktionen, die das Frontend über `sdk.backend.*` aufrufen kann:

```js
// In backend init:
sdk.api.register("getScans", function(scanId) {
  return { scans: [] };
});

// Emit an event to connected frontends:
sdk.api.send("scan:complete", { scanId: 1, status: "ok" });
```

Der Handler erhält die vom Frontend übergebenen Argumente (es wird kein zusätzliches `sdk`-Argument eingefügt). Rückgabewerte werden als JSON serialisiert und an den Aufrufer zurückgesendet.

Das Frontend ruft diese Funktionen über `sdk.backend.getScans(scanId)` auf – siehe [Frontend-Plugin-API](#frontend-plugin-api-sdk).

`sdk.api.send` stellt Ereignisse in eine Plugin-spezifische Warteschlange (maximal 200 Einträge). Frontends fragen diese Warteschlange über `sdk.backend.onEvent` ab.

### `sdk.replay`, `sdk.projects`, `sdk.scope`, `sdk.workflows`, `sdk.matchReplace` {#sdk-replay-sdk-projects-sdk-scope-sdk-workflows-sdk-matchreplace}

Dies sind schreibgeschützte Abfragenamensräume. Vollständige Methodensignaturen finden Sie in der [Backend-SDK-Referenz](./backend-sdk.md).

### Anfrageklassen {#request-classes}

**`RequestSpecRaw`** – stellt eine abgefangene Anfrage dar. Sie erhalten dieses Objekt in `onInterceptRequest`.

```js
spec.getMethod()          // > string
spec.setMethod("POST")
spec.getHost()            // > string
spec.setHost("example.com")
spec.getPort()            // > number
spec.getPath()            // > string
spec.setPath("/new/path")
spec.getQuery()           // > string
spec.getTls()             // > boolean
spec.getHeaders()         // > Record<string, string[]>
spec.setHeader("X-Foo", "bar")
spec.getBody()            // > Body | null
spec.setBody("new body")
spec.getRaw()             // > Uint8Array (raw bytes) or []
spec.setRaw(bytes)        // set raw bytes

// Create a new spec from a URL string:
var spec = new RequestSpecRaw("https://example.com/path?q=1");
```

**`Request`** – eine schreibgeschützte aufgezeichnete Anfrage (aus `sdk.requests.get`).

```js
req.getId()
req.getMethod()
req.getHost()
req.getPort()
req.getTls()
req.getPath()
req.getQuery()
req.getUrl()           // > full URL string
req.getHeaders()       // > Record<string, string>
req.getHeader("name")
req.getBody()          // > Body | null
req.getCreatedAt()     // > Date
req.toSpec()           // > RequestSpec (mutable copy)
```

**`Response`** – eine schreibgeschützte aufgezeichnete Antwort.

```js
res.getCode()            // > number (HTTP status)
res.getHeaders()         // > Record<string, string>
res.getHeader("name")
res.getBody()            // > Body | null
res.getRoundtripTime()   // > number (ms)
res.getCreatedAt()       // > Date
```

**`Body`**:

```js
body.toText()    // > string
body.toJson()    // > parsed object or null
body.toRaw()     // > Uint8Array
body.length      // > number (original size, may differ from toText() if truncated)
```

***

## Frontend-Plugin-API (sdk) {#frontend-plugin-api-sdk}

Frontend-Plugin-Code läuft in einem Iframe mit Sandbox, das von `/plugins/{id}/ui` geladen wird. Das Iframe verwendet `postMessage` zur Kommunikation mit dem Ogma-Host, der Aufrufe an das Backend weiterleitet.

Das SDK ist über `window.ogmaSDK` verfügbar. Rufen Sie `ogmaSDK.ready(cb)` auf, um das einsatzbereite SDK zu erhalten, sobald die Host-Bridge eingerichtet ist:

```js
ogmaSDK.ready(function(sdk) {
  // sdk is the live SDK - safe to call any method here
  sdk.log.info("frontend ready");
});
```

Alle SDK-Methoden geben Promises zurück.

### `sdk.log` {#sdk-log}

```js
sdk.log.info("message")
sdk.log.warn("message")
sdk.log.error("message")
```

### `sdk.meta` {#sdk-meta-1}

```js
var meta = await sdk.meta.get();
// { pluginId, packageId, name, version, ogmaVersion }
```

### `sdk.requests` {#sdk-requests-1}

```js
var entry = await sdk.requests.get({ id: "entry-id" });
var result = await sdk.requests.search({ limit: 20, offset: 0, query: "host:example.com" });
```

Erfordert die Berechtigung `read_http_history` (automatisch erteilt; keine Zustimmung des Nutzers erforderlich).

### `sdk.findings` {#sdk-findings-1}

```js
var page = await sdk.findings.list({ limit: 20, offset: 0 });
```

Erfordert die Berechtigung `read_findings` (automatisch erteilt).

### `sdk.scope` {#sdk-scope}

```js
var scope = await sdk.scope.getActive();
```

### `sdk.projects` {#sdk-projects}

```js
var project = await sdk.projects.getCurrent();
```

### `sdk.backend` – Backend-RPC {#sdk-backend-backend-rpc}

Rufen Sie Funktionen auf, die im Backend mit `sdk.api.register` registriert wurden:

```js
// Call a named backend function
var result = await sdk.backend.call("getScans", [scanId]);

// Poll for backend-emitted events (sdk.api.send on the backend side)
var { events, next_since } = await sdk.backend.poll(since);
// events: [{ event: "scan:complete", args: [...] }]

// Register an event listener (uses polling internally)
sdk.backend.onEvent("scan:complete", function(data) {
  console.log("scan done", data);
});
```

`sdk.backend.onEvent` verwendet intern eine Polling-Schleife mit einem Intervall von 2 Sekunden. Beenden Sie das Abonnement durch Aufrufen der zurückgegebenen Abmeldefunktion:

```js
var unsub = sdk.backend.onEvent("scan:complete", handler);
// later:
unsub();
```

### `sdk.navigation` {#sdk-navigation}

```js
await sdk.navigation.addPage("/my-plugin", { title: "My Plugin" });
```

Registriert eine Navigationsseite. Wird derzeit vom Host bestätigt. Die vollständige Router-Integration ist in Arbeit.

### `sdk.sidebar` {#sdk-sidebar}

```js
await sdk.sidebar.registerItem("My Plugin", "/my-plugin", { icon: "puzzle" });
```

Registriert einen Seitenleisteneintrag. Derzeit auf das Plugin-UI-Panel beschränkt – die Anbindung an die globale Seitenleiste ist in Arbeit.

### `sdk.commands` {#sdk-commands}

```js
await sdk.commands.register("my-plugin:scan", {
  name: "Scan with My Plugin",
  handler: function(context) { /* ... */ }
});
```

Wird vom Host bestätigt. Die Integration in die Befehlspalette ist in Arbeit.

### `sdk.menu` {#sdk-menu}

```js
await sdk.menu.registerItem({
  type: "Request",
  commandId: "my-plugin:scan",
  leadingIcon: "shield"
});
```

Wird vom Host bestätigt. Das Einfügen in das Kontextmenü ist in Arbeit.

### `sdk.window` {#sdk-window}

```js
sdk.window.showToast("Scan complete", { variant: "success", duration: 3000 });
```

Zeigt eine Toast-Benachrichtigung im Plugin-Panel an. Varianten: `info`, `success`, `warning`, `error`.

### `sdk.ui` {#sdk-ui}

```js
sdk.ui.resize(600);                              // request iframe height change
sdk.ui.sidebar.registerItem("name", "/path");    // alias for sdk.sidebar.registerItem
```

***

## Berechtigungen {#permissions}

Deklarieren Sie Berechtigungen in `manifest.json`:

```json
{
  "permissions": ["send_requests", "write_findings"]
}
```

### Automatisch erteilte Berechtigungen (keine Zustimmung des Nutzers erforderlich) {#auto-granted-permissions-no-user-approval-needed}

Diese werden jedem installierten Plugin immer erteilt:

| Berechtigung | Erlaubte Funktionen |
|------------|----------------|
| `read_http_history` | `sdk.requests.get`, `sdk.requests.search` |
| `read_findings` | `sdk.findings.get`, `sdk.findings.list` |
| `read_scope` | `sdk.scope.getActive` |
| `read_projects` | `sdk.projects.getCurrent`, `sdk.projects.list` |
| `plugin_storage` | `sdk.storage`, `sdk.fs`, `sdk.path` |

### Geschützte Berechtigungen (Zustimmung des Nutzers erforderlich) {#protected-permissions-require-user-approval}

Diese müssen im Manifest deklariert und vom Nutzer auf der Registerkarte Berechtigungen ausdrücklich erteilt werden:

| Berechtigung | Erlaubte Funktionen |
|------------|----------------|
| `send_requests` | `sdk.requests.send` – ausgehende HTTP-Anfragen senden |
| `write_findings` | `sdk.findings.create`, `sdk.findings.update` |

Beim Aktivieren eines Plugins, das geschützte Berechtigungen deklariert, wird dem Nutzer eine Abfrage angezeigt. Er kann Berechtigungen auch jederzeit auf der Registerkarte Berechtigungen erteilen oder entziehen.

***

## Struktur eines Plugin-Pakets {#plugin-package-structure}

Ein Plugin-Paket kann aus einem lokalen Verzeichnis und bei browserbasierten Abläufen auch aus `.zip`-Exporten installiert werden.

```
my-plugin/
  manifest.json           - required
  backend/
    script.js             - bundled backend JS (ES2020)
  frontend/
    script.js             - bundled frontend JS
    style.css             - optional CSS
    assets/               - static assets (images, fonts, etc.)
```

### Anforderungen an Backend-Skripte {#backend-script-requirements}

* Muss eine einzelne, in sich geschlossene JS-Datei sein.
* `require()` und dynamisches `import()` werden nicht unterstützt.
* Muss eine Funktion `init(sdk)` exportieren (oder als globale Funktion definieren).
* Von QuickJS unterstützte ES2020-Teilmenge: `async/await`, `Promise`, `Map`, `Set`, `Symbol`, `Proxy`, `Date`, `RegExp`, `JSON`. Kein `fetch`, kein `Buffer`.
* Unterstützte statische Imports werden durch die Plugin-Vorverarbeitung aufgelöst: `@ogma/sdk`, `crypto`, `fs`, `path`.
* Maximale Dateigröße: 256 KB.

### Anforderungen an Frontend-Skripte {#frontend-script-requirements}

* Läuft in einem Iframe mit Sandbox. `connect-src: 'self'` ist erlaubt, damit das Plugin POST-Anfragen an `/plugins/{id}/api/*` senden und `/plugins/{id}/events/poll` abfragen kann.
* CSP: `default-src 'none'; script-src 'nonce-...'; style-src 'self'; img-src data: blob: 'self'; connect-src 'self'`.
* Kein `allow-same-origin` in der Iframe-Sandbox – das Plugin kann nicht auf Ogmas übergeordnetes DOM oder Cookies zugreifen.
* Verwenden Sie `ogmaSDK.ready(cb)`, um auf das SDK zuzugreifen; rufen Sie SDK-Methoden erst auf, wenn der Callback ausgelöst wurde.

***

## Ein Plugin für Ogma bauen {#building-a-plugin-for-ogma}

Da das Backend eine einzelne gebündelte JS-Datei sein muss, müssen Sie Ihren TypeScript-/ES-Modul-Quellcode vor der Installation bündeln.

Empfohlene Toolchain:

```bash
# Install dependencies
pnpm install

# Bundle backend (outputs a single CJS/IIFE file):
esbuild packages/backend/src/index.ts \
  --bundle \
  --platform=neutral \
  --format=iife \
  --global-name=_plugin \
  --outfile=dist/backend/script.js \
  --external:@ogma/sdk --external:@ogmabox/ogma-sdk

# Bundle frontend:
vite build packages/frontend --outDir ../../dist/frontend
```

Wenn Sie die Caido-Entwicklungs-Toolchain (`@caido-community/dev`) verwenden, führen Sie `caido-dev build` aus und kopieren Sie die Ausgabe anschließend in eine Ogma-kompatible Verzeichnisstruktur mit `manifest.json` im Stammverzeichnis.

***

## Ein Plugin installieren {#installing-a-plugin}

1. Öffnen Sie **Plugins** in der linken Seitenleiste.
2. Klicken Sie auf **Installieren** (oben auf der Registerkarte Installiert).
3. Klicken Sie in der Desktop-Anwendung auf **Durchsuchen**, um die native Ordnerauswahl zu öffnen. Geben Sie im Browser den vollständigen serverseitigen Pfad zum Plugin-Verzeichnis ein.
4. Klicken Sie auf **Validieren**, um das Manifest und den Dateibestand zu prüfen.
5. Klicken Sie auf **Installieren**, wenn die Validierung erfolgreich ist.
6. Wählen Sie das Plugin in der Liste aus und klicken Sie auf **Aktivieren**.
7. Wenn das Plugin geschützte Berechtigungen deklariert, prüfen und erteilen Sie diese vor dem Aktivieren auf der Registerkarte **Berechtigungen**.

***

## Problemlösung {#troubleshooting}

**Plugin-Initialisierung schlägt ohne Fehlermeldung fehl:** Prüfen Sie die Registerkarte **Protokolle**. Die häufigsten Ursachen:

* `sdk.meta.path()` wurde aufgerufen, aber das Datenverzeichnis konnte nicht erstellt werden.
* Eine unbehandelte Ausnahme in `init()`.
* Ein fehlender oder falsch geschriebener `sdk.*`-Aufruf.

**Frontend bleibt leer:** Prüfen Sie die Browserkonsole auf CSP-Verstöße. Stellen Sie sicher, dass Ihr Frontend-Skript `ogmaSDK.ready(cb)` aufruft, bevor es auf eine SDK-Methode zugreift.

**`sdk.requests.send` löst `Permission denied` aus:** Die Berechtigung `send_requests` muss im Manifest deklariert UND vom Nutzer auf der Registerkarte Berechtigungen erteilt sein.

**Mit `sdk.api.register` registrierte Funktionen sind vom Frontend aus nicht aufrufbar:** Das Backend muss aktiviert sein (nicht nur installiert). Der Funktionsname muss exakt mit dem Namen übereinstimmen, den das Frontend an `sdk.backend.call` übergibt (Groß-/Kleinschreibung beachten).

**Kompatibilitätswarnungen erscheinen als Fehler:** Diese verhindern den Betrieb nicht, weisen aber auf Lücken im API-Funktionsumfang hin. Die obigen SDK-Zuordnungstabellen zeigen die API-Abdeckung.
