Building Plugins

Developer guide to the Pomavo plugin system: the SDK, the manifest, the sandboxed UI bridge, and the lifecycle of an installable plugin.

Overview

A Pomavo plugin is a small, self-hosted web service that the host application talks to over a well-defined contract. Plugins extend Pomavo without touching the core: they add widgets, which are UI panels embedded in the app, themes, and integrations, and they run completely isolated from the host.

Everything a plugin needs is provided by the @pomavo/sdk package, which ships two halves:

Anatomy of a Plugin

A typical plugin is an Express or another Node HTTP server that exposes a handful of endpoints and serves one or more widget bundles:

text
my-plugin/
├── manifest.json         # id, widgets, params, lifecycle
├── src/
│   ├── index.ts          # HTTP server entry
│   ├── routes/
│   │   ├── lifecycle.ts  # install / uninstall / update
│   │   ├── api.ts        # data endpoints (token-guarded)
│   │   └── widgets.ts    # serves widget bundles
│   └── widgets/
│       └── MyWidget.tsx  # React UI for the iframe
└── package.json

The host never runs your code directly. Instead:

The host sends lifecycle events

When an organization installs your plugin, Pomavo POSTs an installed event to your lifecycle.url, carrying an installationId and a sharedSecret you store and use to verify future requests.

The host embeds your widgets

Each widget you declare in the manifest is loaded into a sandboxed iframe at the URL you provide. The host hands the iframe a short-lived token and the current context, such as the ticket being viewed.

Your widget calls your backend

The widget fetches your own API endpoints, passing the host token as a Bearer credential. Your backend verifies the token with the shared secret and resolves the org/user/ticket from it.

Your backend can call Pomavo

If your plugin needs to read or write Pomavo data, it uses the PomavoClient with an integration API key delivered during installation.

Install the SDK

GNU Bashbash
npm install @pomavo/sdk

The package exposes two entry points so the browser bundle never pulls in server-only code:

TypeScripttypescript
// In your widget (browser)
import { PomavoBridge } from '@pomavo/sdk/client';
 
// In your backend (Node)
import {
  PomavoClient,
  createLifecycleHandler,
  createTokenVerifier,
  verifyPluginToken,
} from '@pomavo/sdk/server';

The Security Model

Plugins are designed so that installing one can never compromise the rest of Pomavo:

  • Sandboxed UI - widget code runs in an isolated iframe (allow-scripts allow-same-origin allow-popups). It cannot read the host DOM, cookies, or session.
  • Explicit context - a widget only receives what the host chooses to pass through the bridge: a token, its saved settings, and the current ticket.
  • Signed tokens - the host token is an HS256 JWT signed with your per-installation sharedSecret, so your backend can trust the org/user it names.
  • Scoped integrations - Pomavo API access is granted through integration API keys tied to the installing organization and the permissions your manifest requests.
  • Per-organization installs - a plugin is only active for organizations that install it, and uninstalling fully revokes its widgets and keys.

The first-party GitHub plugin is built entirely on this system. See the end-to-end example for a complete, working plugin.

Next Steps