3.2 KiB
sidebar_position
| 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.
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
{
"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
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.
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
- Create the plugin folder in the desktop plugins directory.
- Open the Plugin Manager.
- Register or refresh local plugins.
- Grant required capabilities.
- Activate the plugin.
- Inspect plugin logs in the manager.
For broad API examples, compare against the E2E fixture plugin under toju-app/public/plugins/e2e-all-api/.