Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/rivenmedia/riven-ts/llms.txt

Use this file to discover all available pages before exploring further.

The Plugin SDK (@repo/util-plugin-sdk) is the TypeScript package that every Riven integration is built on. Whether you are connecting a new content source, wiring up a metadata provider, scraping a torrent index, or adding subtitle support, you express that integration as a plugin that implements the RivenPlugin interface and is registered at application startup. Once registered, Riven provisions each plugin’s own BullMQ queues, injects dependencies into GraphQL resolvers at request time, and routes typed events to the hook handlers the plugin declares.
The SDK is not yet published to npm. Plugins live inside the monorepo as workspace packages under packages/plugin-<name>. Community distribution via npm is planned for a future release.

The RivenPlugin interface

Every plugin exports a single named plugin constant that satisfies the RivenPlugin type. The SDK validates the shape at startup using Zod, so mismatches are caught before any handler fires.
interface RivenPlugin {
  name: symbol;                // Unique identifier — drives queue naming and DI
  version: string;             // Semver string, validated against the spec
  resolvers: Function[];       // At least one type-graphql resolver class
  hooks: Partial<EventHandlers>;       // Subset of the event handler map (may be {})
  settingsSchema: ZodObject;   // Zod schema — env vars are parsed through this
  dataSources?: DataSourceConstructor[];  // Optional HTTP client classes
  context?: (ctx: PluginContext) => Promise<Record<string, unknown>>;
  validator: (ctx: PluginContext) => Promise<boolean>;
}

interface PluginContext {
  dataSources: DataSourceMap;
  settings: PluginSettings;
}
Plugins retrieve their configuration by calling settings.get(YourSettingsSchema) — never by reading process.env directly. The registrar strips plugin environment variables out of the environment before importing any plugin module, so one plugin cannot read another plugin’s secrets.

Six extension points

Each key of RivenPlugin maps to a distinct extension point. You only need to implement the ones relevant to your plugin type.

DataSources

Subclass BaseDataSource to wrap an HTTP API. You get BullMQ-backed request queuing, configurable rate limiting, automatic retry with exponential back-off, response caching, and OpenTelemetry tracing — all without writing any infrastructure code. Instances are injected into resolvers via the @PluginDataSource() decorator.

GraphQL Resolvers

Register type-graphql resolver classes in the resolvers array. Each plugin must provide at least one resolver. Use the @PluginDataSource() parameter decorator to receive a DataSource instance scoped to the current plugin. A settings resolver extending the global Settings type lets clients discover available configuration keys.

Event Hooks

Declare handlers in the hooks object keyed by event type string. Each handler receives a { dataSources, settings, event } context and must return the expected payload shape. The SDK enforces handler signatures with Zod function schemas at startup, not at call time.

Settings Schema

A ZodObject passed as settingsSchema. Riven parses the plugin’s prefixed environment variables through this schema at registration time, applies defaults, and freezes the result. Fields annotated with .describe() are included in the generated settings documentation.

Context Factory

The optional context function runs once per request before resolvers execute. It receives the fully-initialised PluginContext and returns an additional Record<string, unknown> that is merged into the Apollo GraphQL context under the plugin’s Symbol key — useful for per-request state that multiple resolvers share.

Validator

The validator function is called during startup, after DataSources are initialised but before the plugin is marked as valid. It receives a fully-populated PluginContext with access to DataSources and settings. Return true to mark the plugin healthy, false to mark it invalid without crashing the rest of the application.

Plugin lifecycle

Understanding the order in which Riven initialises a plugin helps you write reliable validators and avoid accessing uninitialised dependencies.
1

Registration

At startup, apps/riven imports each plugin package and reads its exported plugin constant. The Zod schema for RivenPlugin validates the shape immediately.
2

Settings parsing

PluginSettings reads all RIVEN_PLUGIN_SETTING__<prefix>__<key> environment variables prefixed for this plugin, parses them through settingsSchema, applies defaults, and removes the variables from process.env.
3

DataSource initialisation

Each class listed in dataSources is instantiated with the parsed settings, a Redis connection, an HTTP cache adapter (Keyv/Redis), the plugin Symbol, and telemetry hooks. The BullMQ Queue, QueueEvents, and Worker are started immediately.
4

Validation

The validator function is called with a PluginContext containing the live DataSource instances and the frozen settings. Returning false marks the plugin invalid; the plugin’s queues remain up, but no events will be dispatched to it.
5

Hook worker registration

For every key declared in hooks, Riven creates a dedicated BullMQ worker subscribed to that event type. Each worker runs the handler and publishes the result as a new downstream event.
6

GraphQL schema merge

All resolver classes across all valid plugins are passed to type-graphql’s buildSchema. The merged schema is served through Apollo Server.

What the SDK exports

The package exports everything a plugin author needs from a single entry point (@repo/util-plugin-sdk) plus a set of sub-path exports for DTOs and utilities.
BaseDataSource<TSettings> — abstract class extending Apollo’s RESTDataSource with the BullMQ request pipeline built in. Override baseURL, serviceName, rateLimiterOptions, willSendRequest, and validate. Export RateLimiterOptions (re-exported from bullmq) to type the rate-limiter config.
import { BaseDataSource } from '@repo/util-plugin-sdk';
import type { RateLimiterOptions } from '@repo/util-plugin-sdk';
Two GraphQL parameter decorators are exported from @repo/util-plugin-sdk:
  • PluginContext(symbol) — injects the full plugin context object stored under the given Symbol in the Apollo context.
  • PluginDataSource(symbol, DataSourceClass) — resolves dataSources.get(DataSourceClass) from the plugin context and injects the live instance.
import { PluginDataSource, PluginContext } from '@repo/util-plugin-sdk';
  • RivenPlugin — Zod schema and inferred TypeScript type for the plugin manifest.
  • RivenPluginConfig — minimal config object ({ name: symbol }).
  • DataSourceConstructor — interface for a BaseDataSource constructor.
  • DataSourceMap — typed Map-like class keyed by constructor, used inside PluginContext.
  • PluginSettings — the parsed, frozen settings store.
import type { RivenPlugin, RivenPluginConfig, DataSourceMap } from '@repo/util-plugin-sdk';
All MikroORM entities and their associated GraphQL types are available under the /dto/entities sub-path export:
  • Movie, Show, Season, Episode — core media item hierarchy
  • MediaItem — union base type
  • Stream, BlacklistedStream — torrent stream records
  • FilesystemEntry, MediaEntry, SubtitleEntry — VFS path objects
  • ItemRequest — user content request record
import { Movie, Show, Episode } from '@repo/util-plugin-sdk/dto/entities';
All typed event schemas live in the @repo/util-plugin-sdk/events sub-path export. Import handler types to annotate hook functions:
import type { MediaItemScrapeRequestedEventHandler } from
  '@repo/util-plugin-sdk/schemas/events/media-item.scrape-requested.event';
The complete set of event keys available as hook keys is listed in the Events reference.
  • atLeastOnePropertyRequired — Zod refinement that rejects objects with all-undefined values.
  • recordIsNotEmpty — Zod refinement that rejects empty record objects.
import { atLeastOnePropertyRequired } from '@repo/util-plugin-sdk/validation';

Plugin categories

Riven’s event model is flexible enough to support a wide range of plugin types. The same RivenPlugin interface covers all of them — which hooks you declare determines what role the plugin plays.
Plugin typePrimary hook(s)Example
Content sourceriven.content-service.requestedSeerr, MDBList, Listrr
Metadata providerriven.media-item.index.requested.movie, .showTVDB, TMDB
Scraperriven.media-item.scrape.requestedComet, Torrentio
Downloaderriven.media-item.download.requestedStremThru
Stream-link providerriven.media-item.stream-link.requestedDebrid proxies
Subtitle providerriven.media-item.subtitle.requestedSubDL
Media serverriven.core.started, riven.media-item.index.successPlex, Jellyfin
Notification serviceVarious success/error eventsCustom webhook plugin

Next steps

Quickstart

Scaffold your first plugin with the Turborepo generator and have it running in minutes

Building a DataSource

Deep dive into BaseDataSource: rate limiting, caching, retry logic, and willSendRequest

GraphQL Resolvers

Wire up type-graphql resolvers and inject DataSources with the PluginDataSource decorator

Event Hooks

Subscribe to the full event catalogue and return typed payloads

Build docs developers (and LLMs) love