# @dorfteich/plugin-sdk The contract between the Dorfteich host app and a plugin bundle: the **manifest schema**, the **capability names**, and the typed **postMessage RPC protocol**. It is the one package a plugin author needs — it builds standalone and pulls in only `zod`. Read [ADR 0008](../../docs/architecture/adr/0008-plugin-sandbox.md) and [plugin-architecture.md](../../docs/architecture/plugin-architecture.md) first; the manifest example there is normative and mirrored by the fixtures under [`fixtures/manifests/`](./fixtures/manifests). ## What's in here | Module | Purpose | | ----------------- | ----------------------------------------------------------------------------------- | | `manifest.ts` | Zod schema for `manifest.json` + `validateManifest` / `parseManifest`. | | `api-version.ts` | `checkApiVersion` — is a plugin's `apiVersion` within the host's supported range? | | `capabilities.ts` | Capability names and the method → capability map that gates RPC calls. | | `rpc.ts` | Transport-agnostic RPC engine (`createRpcEndpoint`) + a `windowTransport` adapter. | | `host.ts` | `createHostBridge` — host end: routes plugin calls through the permission gate. | | `plugin.ts` | `createPlugin` — plugin end: answers lifecycle calls, exposes a typed `host` proxy. | ## Manifest ```ts import { validateManifest } from '@dorfteich/plugin-sdk'; const result = validateManifest(JSON.parse(raw)); if (!result.success) { // result.issues: [{ path: 'extensionPoints.0.type', message: '…' }, …] } ``` `validateManifest` never throws — it returns a flat list of `{ path, message }` issues so the install path (#71) can show a Site Admin every problem at once. `parseManifest` is the throwing variant. Cross-field rules enforced beyond the field shapes: - extension point types must match the plugin `kind` (`section_style` → `sectionStyle` only; `code` → `block`/`pageTool`); - extension point `id`s are unique within the manifest; - `section_style` plugins run no JavaScript and must not declare `permissions`. ## RPC protocol Every code-plugin surface runs in a sandboxed `