User guidePluginsDeveloping plugins
Plugins

Developing plugins

Create custom plugins to extend VerifyWise with new features.

Overview

Create custom plugins to extend VerifyWise with new features tailored to your organization. This guide covers the plugin architecture, available APIs, and best practices for plugin development.

Plugin development requires familiarity with JavaScript or TypeScript. For detailed technical documentation, refer to the PLUGIN_SPEC.md file in the VerifyWise repository.

Getting started

The fastest way to create a plugin is to start from a template:

  1. Clone the plugin marketplace repository from GitHub
  2. Copy a template that matches your use case
  3. Modify the manifest.json with your plugin details
  4. Implement your plugin logic in index.ts or index.js
  5. Test by copying to your VerifyWise plugins directory
bash
# Clone the marketplace repository
git clone https://github.com/bluewave-labs/plugin-marketplace.git

# Copy a template
cp -r templates/template-basic-plugin plugins/my-plugin

# Test locally
cp -r plugins/my-plugin /path/to/verifywise/Servers/plugins/marketplace/

Plugin structure

Every plugin requires the following files:

text
my-plugin/
ā”œā”€ā”€ manifest.json    # Plugin metadata and configuration schema
ā”œā”€ā”€ index.ts         # Main plugin code (or index.js)
└── icon.svg         # Optional plugin icon (24x24 recommended)

The manifest file

The manifest.json file defines your plugin metadata, permissions, and configuration options:

json
{
  "id": "my-plugin",
  "name": "My Plugin",
  "description": "A brief description of what my plugin does",
  "version": "1.0.0",
  "author": {
    "name": "Your Name",
    "url": "https://your-website.com"
  },
  "type": "feature",
  "tags": ["custom", "example"],
  "permissions": [
    "events:listen",
    "database:read"
  ],
  "config": {
    "apiKey": {
      "type": "string",
      "required": true,
      "secret": true,
      "label": "API key",
      "description": "Your service API key"
    }
  },
  "compatibility": {
    "minVersion": "1.6.0"
  }
}

Manifest fields

FieldDescription
idUnique identifier using lowercase letters, numbers, and hyphens
nameDisplay name shown in the UI
descriptionBrief summary of plugin functionality
versionSemantic version (major.minor.patch)
typeCategory: integration, feature, framework, or reporting
permissionsArray of required permissions
configConfiguration schema for plugin settings

Plugin code

Your plugin exports a default object that implements the Plugin interface:

typescript
import type { Plugin, PluginContext } from "../core";

const myPlugin: Plugin = {
  id: "my-plugin",
  name: "My Plugin",

  // Called when plugin is loaded
  async onLoad(context: PluginContext) {
    console.log("Plugin loaded!");
  },

  // Called when plugin is unloaded
  async onUnload(context: PluginContext) {
    console.log("Plugin unloaded!");
  },

  // Called when plugin is enabled
  async onEnable(context: PluginContext) {
    console.log("Plugin enabled!");
  },

  // Called when plugin is disabled
  async onDisable(context: PluginContext) {
    console.log("Plugin disabled!");
  },
};

export default myPlugin;

Plugin context

The PluginContext object provides access to VerifyWise APIs:

  • context.config: Read plugin configuration values
  • context.events: Subscribe to and emit events
  • context.logger: Log messages with proper formatting
  • context.storage: Store plugin-specific data
  • context.models: Access Sequelize models (with permission)
  • context.scheduler: Schedule recurring tasks
  • context.metadata: Attach custom data to entities

Event system

Plugins can listen to system events and emit their own:

typescript
async onEnable(context: PluginContext) {
  // Listen for model updates
  context.events.on("model:updated", async (payload) => {
    context.logger.info("Model updated:", payload.modelId);
  });

  // Listen for task completions
  context.events.on("task:completed", async (payload) => {
    // Send notification to external service
    await notifyExternalService(payload);
  });
}

Common events you can listen to:

  • model:created, model:updated, model:deleted: AI model changes
  • task:created, task:completed: Task lifecycle events
  • risk:identified, risk:mitigated: Risk management events
  • compliance:status-changed: Compliance status updates
  • user:login, user:logout: Authentication events

Dashboard widgets

Plugins can provide dashboard widgets that users can add to their view:

typescript
const myPlugin: Plugin = {
  id: "my-plugin",
  name: "My Plugin",

  widgets: [
    {
      id: "my-widget",
      name: "My Custom Widget",
      description: "Displays custom metrics",
      template: "stats-card",
      defaultSize: { w: 2, h: 1 },
      dataEndpoint: "/api/plugins/my-plugin/widget-data",
    }
  ],
};

Available widget templates:

TemplateBest for
stats-cardDisplaying key metrics and statistics
listShowing lists of items or activities
tableTabular data with columns
chartVisualizing trends and data over time
progressProgress bars and completion status
timelineChronological events and activities
calendarDate-based events and schedules

Custom pages

Add custom pages to the sidebar navigation:

typescript
const myPlugin: Plugin = {
  id: "my-plugin",
  name: "My Plugin",

  pages: [
    {
      id: "my-page",
      title: "My Custom Page",
      icon: "Settings",
      path: "/plugins/my-plugin",
      // Use iframe to embed external content
      iframe: {
        src: "https://my-service.com/embed",
        sandbox: ["allow-scripts", "allow-same-origin"],
      },
      // Or provide HTML content directly
      // content: "<div>My page content</div>",
    }
  ],
};

Custom API routes

Plugins can register custom API endpoints:

typescript
const myPlugin: Plugin = {
  id: "my-plugin",
  name: "My Plugin",

  routes: [
    {
      method: "GET",
      path: "/status",
      handler: async (req, res, context) => {
        res.json({ status: "ok", timestamp: Date.now() });
      },
    },
    {
      method: "POST",
      path: "/webhook",
      handler: async (req, res, context) => {
        // Process incoming webhook
        const data = req.body;
        context.events.emit("my-plugin:webhook-received", data);
        res.json({ received: true });
      },
    },
  ],
};

Routes are automatically prefixed with /api/plugins/{plugin-id}/.

Scheduled tasks

Use the scheduler API to run periodic tasks:

typescript
async onEnable(context: PluginContext) {
  // Run every hour
  context.scheduler.register({
    id: "hourly-sync",
    cron: "0 * * * *",
    handler: async () => {
      context.logger.info("Running hourly sync...");
      await syncData();
    },
  });
}

async onDisable(context: PluginContext) {
  // Clean up scheduled tasks
  context.scheduler.unregister("hourly-sync");
}

Configuration options

Define configuration fields in your manifest for user-configurable settings:

json
"config": {
  "apiKey": {
    "type": "string",
    "required": true,
    "secret": true,
    "label": "API key",
    "description": "Your service API key"
  },
  "syncInterval": {
    "type": "number",
    "default": 60,
    "label": "Sync interval (minutes)",
    "description": "How often to sync data"
  },
  "enableNotifications": {
    "type": "boolean",
    "default": true,
    "label": "Enable notifications",
    "description": "Send notifications for important events"
  }
}

Access configuration values in your plugin code:

typescript
async onEnable(context: PluginContext) {
  const apiKey = context.config.get("apiKey");
  const interval = context.config.get("syncInterval") || 60;
  
  if (!apiKey) {
    throw new Error("API key is required");
  }
}

Testing your plugin

To test your plugin during development:

  1. Copy your plugin to the plugins/marketplace directory
  2. Restart the VerifyWise server
  3. Navigate to Settings > Plugins
  4. Find and enable your plugin
  5. Check server logs for errors
  6. Test all plugin features
Use context.logger for debugging. Log messages appear in the server console and Event Tracker.

Publishing to the marketplace

To share your plugin with the community:

  1. Fork the plugin-marketplace repository on GitHub
  2. Add your plugin to the plugins/ directory
  3. Create a zip file of your plugin
  4. Add an entry to registry.json
  5. Submit a pull request

Best practices

  • Request minimal permissions: Only request permissions your plugin actually needs
  • Handle errors gracefully: Use try-catch and provide meaningful error messages
  • Clean up on disable: Remove event listeners and scheduled tasks when disabled
  • Use the logger: Log important events for debugging and auditing
  • Validate configuration: Check required settings before enabling
  • Document your plugin: Include clear descriptions and usage instructions
  • Version semantically: Use semantic versioning for releases
PreviousPlugin marketplace
Developing plugins - Plugins - VerifyWise User Guide