Files
Toju/docs-site/docs/plugin-development/manifest.md
2026-04-29 17:15:01 +02:00

163 lines
4.2 KiB
Markdown

---
sidebar_position: 2
---
# Manifest Model
The manifest is the source of truth for plugin identity, compatibility, runtime shape, capabilities, data, events, UI hints, and distribution metadata.
```ts
type TojuPluginInstallScope = 'client' | 'server';
type PluginEventDirection = 'clientToServer' | 'serverRelay' | 'p2pHint';
type PluginEventScope = 'server' | 'channel' | 'user' | 'plugin';
type PluginCapabilityId =
| 'profile.read'
| 'profile.write'
| 'users.read'
| 'users.manage'
| 'roles.read'
| 'roles.manage'
| 'messages.read'
| 'messages.send'
| 'messages.editOwn'
| 'messages.deleteOwn'
| 'messages.moderate'
| 'messages.sync'
| 'channels.read'
| 'channels.manage'
| 'server.read'
| 'server.manage'
| 'p2p.data'
| 'p2p.media'
| 'media.playAudio'
| 'media.addAudioStream'
| 'media.addVideoStream'
| 'audio.volume'
| 'audio.effects'
| 'ui.settings'
| 'ui.pages'
| 'ui.sidePanel'
| 'ui.channelsSection'
| 'ui.embeds'
| 'ui.dom'
| 'storage.local'
| 'storage.serverData.read'
| 'storage.serverData.write'
| 'events.server.publish'
| 'events.server.subscribe'
| 'events.p2p.publish'
| 'events.p2p.subscribe';
interface TojuPluginManifest {
schemaVersion: 1;
id: string;
title: string;
description: string;
version: string;
kind: 'client' | 'library';
scope?: TojuPluginInstallScope;
apiVersion: string;
compatibility: {
minimumTojuVersion: string;
maximumTojuVersion?: string;
verifiedTojuVersion?: string;
};
entrypoint?: string;
bundle?: {
url: string;
entrypoint?: string;
};
readme?: string;
homepage?: string;
bugs?: string;
changelog?: string;
license?: string;
authors?: {
name: string;
email?: string;
url?: string;
}[];
capabilities?: PluginCapabilityId[];
events?: {
eventName: string;
direction: PluginEventDirection;
scope: PluginEventScope;
maxPayloadBytes?: number;
schema?: string;
}[];
data?: {
key: string;
schema?: string;
scope: string;
storage: 'local' | 'serverData';
}[];
relationships?: {
after?: string[];
before?: string[];
conflicts?: string[];
optional?: { id: string; versionRange?: string }[];
requires?: { id: string; versionRange?: string }[];
};
load?: {
priority?: 'bootstrap' | 'high' | 'default' | 'low';
};
pluginUser?: {
avatar?: string;
displayName: string;
label?: string;
};
settings?: Record<string, unknown>;
ui?: Record<string, unknown>;
}
```
## Required Fields
| Field | Meaning |
| --- | --- |
| `schemaVersion` | Manifest schema version. Currently `1`. |
| `id` | Stable plugin id. Use a reverse-DNS or package-style id. |
| `title` | Human-readable plugin name. |
| `description` | Short explanation shown in plugin UI. |
| `version` | Plugin version. |
| `kind` | `client` for runtime plugins, `library` for shared dependency-style entries. |
| `apiVersion` | Plugin API version expected by the plugin. |
| `compatibility.minimumTojuVersion` | Oldest app version the plugin supports. |
## Scope
`scope: "client"` installs the plugin for the current client. Omit `scope` for the same behavior.
`scope: "server"` marks a plugin as server-scoped. Server-scoped store entries can be installed to a chat server as requirements. Required server plugins are auto-installed for members when that server opens; optional requirements stay listed but do not auto-install.
## Entrypoint and Bundle
Use `entrypoint` for a browser-resolvable module relative to the manifest. Use `bundle.url` when publishing a cached browser bundle through a plugin source manifest. Desktop installs cache bundle files into app data and load the cached manifest afterward.
## Events
Every server or P2P plugin event should be declared before it is published or subscribed to.
```json
{
"events": [
{
"eventName": "poll:vote",
"direction": "p2pHint",
"scope": "channel",
"maxPayloadBytes": 2048
}
]
}
```
## Data Declarations
Use `data` to document plugin-owned data keys and intended storage.
- `local` maps to client-local plugin data.
- `serverData` maps to local per-user/per-server plugin data.
Signal server HTTP persistence for arbitrary plugin data is disabled by design.