107 lines
3.2 KiB
Markdown
107 lines
3.2 KiB
Markdown
---
|
|
sidebar_position: 1
|
|
---
|
|
|
|
# Create a Plugin
|
|
|
|
MetoYou plugins are browser-safe ES modules loaded by the Angular renderer. A plugin receives a frozen `TojuClientPluginApi`, declares every privileged capability in its manifest, and registers cleanup work through disposables.
|
|
|
|
## Folder Layout
|
|
|
|
A local desktop plugin is discovered from an immediate child folder under the app data `plugins` directory.
|
|
|
|
```text
|
|
my-plugin/
|
|
toju-plugin.json
|
|
main.js
|
|
README.md
|
|
icon.svg
|
|
```
|
|
|
|
The manifest file can be named `toju-plugin.json` or `plugin.json`. Entrypoints and readmes must stay inside the plugin folder.
|
|
|
|
## Minimal Manifest
|
|
|
|
```json
|
|
{
|
|
"schemaVersion": 1,
|
|
"id": "example.hello-world",
|
|
"title": "Hello World",
|
|
"description": "Adds a toolbar action that sends a message.",
|
|
"version": "1.0.0",
|
|
"kind": "client",
|
|
"scope": "client",
|
|
"apiVersion": "1.0.0",
|
|
"compatibility": {
|
|
"minimumTojuVersion": "1.0.0"
|
|
},
|
|
"entrypoint": "./main.js",
|
|
"capabilities": ["messages.send", "ui.pages"]
|
|
}
|
|
```
|
|
|
|
## Entrypoint
|
|
|
|
```js
|
|
export function activate(context) {
|
|
const { api } = context;
|
|
|
|
api.logger.info('Hello World activated');
|
|
|
|
const disposable = api.ui.registerToolbarAction('hello', {
|
|
label: 'Hello',
|
|
run: () => api.messages.send('Hello from my plugin')
|
|
});
|
|
|
|
context.subscriptions.push(disposable);
|
|
}
|
|
|
|
export function ready(context) {
|
|
context.api.logger.info('All ready plugins have loaded');
|
|
}
|
|
|
|
export function deactivate(context) {
|
|
context.api.logger.info('Hello World deactivated');
|
|
}
|
|
```
|
|
|
|
## Lifecycle Hooks
|
|
|
|
| Hook | When it runs | Use it for |
|
|
| --- | --- | --- |
|
|
| `activate(context)` | During explicit plugin activation. | Register UI, subscribe to events, initialize state. |
|
|
| `ready(context)` | After the load-order pass has activated ready plugins. | Cross-plugin coordination that needs other plugins loaded. |
|
|
| `deactivate(context)` | During unload or reload. | Flush state and log shutdown. Disposables are also cleaned up by the host. |
|
|
| `onPluginDataChanged(context, event)` | When plugin data changes are observed. | React to plugin-scoped persistence changes. |
|
|
| `onServerRequirementsChanged(context, snapshot)` | When server plugin requirements change. | Adapt to required, optional, blocked, or incompatible server plugins. |
|
|
|
|
## Cleanup
|
|
|
|
Every API registration returns a disposable. Push it into `context.subscriptions`.
|
|
|
|
```js
|
|
const subscription = api.messageBus.subscribe({
|
|
topic: 'poll:votes',
|
|
handler: (event) => api.logger.info('vote received', event.payload)
|
|
});
|
|
|
|
context.subscriptions.push(subscription);
|
|
```
|
|
|
|
The plugin host disposes subscriptions in reverse order when the plugin unloads.
|
|
|
|
## Capability Grants
|
|
|
|
A plugin can only call privileged APIs after the matching capability is declared in the manifest and granted by the user. Keep the manifest narrow. For example, a plugin that only adds a settings page does not need message or user management capabilities.
|
|
|
|
## Testing Locally
|
|
|
|
1. Create the plugin folder in the desktop plugins directory.
|
|
2. Open the Plugin Manager.
|
|
3. Register or refresh local plugins.
|
|
4. Grant required capabilities.
|
|
5. Activate the plugin.
|
|
6. Inspect plugin logs in the manager.
|
|
|
|
For broad API examples, compare against the E2E fixture plugin under `toju-app/public/plugins/e2e-all-api/`.
|