Plugin System

Plugins are the primary extension model for Pipe Bomb. Music sources, metadata providers, search backends, and automation steps are provided by plugins - nothing is hardcoded into the server.

What is a plugin?

A plugin is a Node.js package installed into the server's plugin directory. It exports a single default class that extends the base Plugin interface from the SDK:

import { Plugin, PluginApiContext } from "@pipe-bomb/plugin-sdk";

export default class MyPlugin extends Plugin {
	async enable(ctx: PluginApiContext): Promise<void> { ... }
	async disable(): Promise<void> { ... }
}

The server loads all subdirectories of the plugin directory at startup (except for directories that start with .), calls enable() on each, and passes a PluginApiContext that the plugin uses to register its capabilities.

What plugins can register

Registration call What it does
registerLibraryHandler(handler) Exposes a music source that can be scanned and streamed
registerAttributeSource(source) Enriches tracks/artists/albums with metadata
registerTrackIdentifier(id) Assigns canonical identities to tracks
registerArtistIdentifier(id) Assigns canonical identities to artists
registerAlbumIdentifier(id) Assigns canonical identities to albums
registerEphemeralSource(source) Integrates an external catalog (search without indexing)
registerSearchSource(source) Provides a search backend for the local library
registerTask(task) Adds a background task runnable from the Tasks UI
registerConfigManager(mgr) Adds a global plugin settings page
registerUserConfigManager(id, mgr) Adds per-user plugin settings
registerLanguageDirectory(path) Provides i18n strings for the frontend
registerIconDirectory(path) Provides icons used by the frontend
registerExternalUrlSource(source) Adds external links to entities (e.g. "Open in Spotify")
getWorkflowClient() Register custom workflow triggers and steps
getPlaylistClient() Manage playlists programmatically

Plugin lifecycle

  1. Server starts → scans the plugin directory
  2. Each plugin directory is loaded: package.json is validated, the entry file is imported, the class is instantiated
  3. enable(ctx) is called - the plugin registers its capabilities
  4. On uninstall: the plugin directory is deleted; the plugin is not hot-unloaded (restart required)

Installing plugins

Plugins are installed from a git URL via the Settings → Installed Plugins UI or the API. The server clones the repo, runs npm ci and (if configured) npm run build, then moves the result into the plugin directory and calls enable() on it.

See users/Marketplace for installing from a curated registry.

Plugin inter-communication

Plugins can retrieve other loaded plugins via ctx.getPlugin(pluginId). This returns the raw plugin instance, so the calling plugin must know the API the target plugin exposes. This is the mechanism for plugin dependency chains.