Plugin Structure
Each plugin lives in its own directory inside the VMSC plugins folder. At minimum, a plugin needs a manifest and an entry point:
my-plugin/
├── manifest.json
└── index.js
Manifest
The manifest.json file describes your plugin and tells VMSC how to load it.
{
"name": "my-plugin",
"version": "1.0.0",
"description": "My custom plugin",
"entryPoint": "index.js"
}
| Field | Type | Description |
|---|---|---|
name | string | Unique plugin identifier (kebab-case recommended) |
version | string | Semver version string |
description | string | Short description shown in the Plugins UI |
entryPoint | string | Relative path to the main JS file |
Lifecycle
Your entry point must export two functions that VMSC calls to manage the plugin's lifecycle:
| Function | Description |
|---|---|
activate(context) | Called when the plugin is enabled. Receives the plugin API context object. Use this to register event listeners and initialize state. |
deactivate() | Called when the plugin is disabled or VMSC shuts down. Use this to clean up listeners, timers, or open connections. |
API Methods
The context object passed to activate() exposes the following APIs:
Events
| Method | Description |
|---|---|
context.events.emit(event, data) | Emit a stream event into the VMSC event bus. Other plugins and the rule engine will receive it. |
context.events.on(event, handler) | Subscribe to events from the event bus. The handler receives the event data object. |
Configuration
| Method | Description |
|---|---|
context.config.get(key) | Read a value from the plugin's scoped configuration store. |
context.config.set(key, value) | Write a value to the plugin's scoped configuration store. Values are persisted across restarts. |
Logging
| Method | Description |
|---|---|
context.logger.info(message) | Log an informational message. |
context.logger.warn(message) | Log a warning. |
context.logger.error(message) | Log an error. Errors also appear in the VMSC developer console. |
Example Plugin
A minimal plugin that logs gift events from TikTok:
module.exports = {
activate(context) {
context.events.on('stream-event', (event) => {
if (event.type === 'gift') {
context.logger.info(`Gift received: ${event.data.giftName}`)
}
})
},
deactivate() {
// Cleanup timers, connections, etc.
}
}
Security Notes
Plugins Run with Full Privileges
Plugins execute in the main Electron process and have full access to the Node.js API. Only install plugins from sources you trust.
- Plugins run in the main Electron process with no sandbox.
- Full Node.js API access is available, including file system, network, and child processes.
- Configuration keys are automatically scoped by plugin name to prevent cross-plugin access.