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 RivenPlugin interface is the top-level contract every Riven plugin must satisfy. Validated at startup using a Zod schema, it binds together your data sources, GraphQL resolvers, event hooks, settings schema, and startup validator into a single cohesive unit that Riven can discover, configure, and run.
The RivenPlugin Zod schema is exported from @repo/util-plugin-sdk. Export a value that satisfies it from your package so Riven can pick it up automatically via RivenPluginPackage.

Interface Fields

version
string
required
A semver string that identifies the plugin release. Validated against the standard semver regex at startup — an invalid string will prevent registration.
version: "1.0.0"
name
symbol
required
A unique Symbol that acts as the plugin’s identity key throughout Riven. Used as a map key inside GraphQLContext.plugins so resolvers can look up their own data sources at query time.
name: Symbol("my-plugin")
dataSources
[DataSourceConstructor, ...DataSourceConstructor[]]
A non-empty tuple of BaseDataSource subclass constructors (not instances). Riven instantiates each constructor at startup and injects the resulting instances into a DataSourceMap that is passed to your context factory and validator. Omit this field if your plugin has no data sources.
dataSources: [MyApiDataSource, MyDatabaseDataSource]
resolvers
Function[]
required
An array of type-graphql resolver classes. Riven merges these into the unified GraphQL schema it builds at startup. At least one resolver is required.
resolvers: [MyQueryResolver, MyMutationResolver]
hooks
Partial<Record<RivenEvent['type'], ZodFunction>>
required
A partial record mapping event type strings to handler functions. Every handler receives { event, dataSources, settings, logger } and must return a Promise of the corresponding response type. Only the events your plugin handles need to be present — supply an empty object {} if your plugin reacts to no events.
hooks: {
  "riven.content-service.requested": async ({ event, dataSources, settings, logger }) => ({
    movies: [],
    shows: [],
    updateIntervalSeconds: 300,
  }),
  "riven.media-item.scrape.requested": async ({ event }) => ({
    id: event.item.id,
    results: { "da39a3ee5e6b4b0d3255bfef95601890afd80709": "magnet:?xt=urn:btih:..." },
  }),
}
All hook handlers share the same argument shape:
{
  event:       <EventPayload without the "type" field>;
  dataSources: DataSourceMap;
  settings:    PluginSettings;
  logger:      Logger;          // Winston Logger
}
context
(args: { dataSources: DataSourceMap, settings: PluginSettings }) => Promise<Record<string, unknown>>
An optional async factory that contributes extra keys to the per-request GraphQLContext. Receives the plugin’s initialised DataSourceMap and a PluginSettings instance. Return an object whose keys will be merged into context.plugins[pluginName] for every incoming GraphQL request.
context: async ({ dataSources, settings }) => ({
  myApiClient: dataSources.get(MyApiDataSource),
})
settingsSchema
ZodObject
required
A z.object(...) schema describing every environment variable your plugin reads. Riven parses the matching RIVEN_PLUGIN_SETTING__<PREFIX>__<KEY> variables against this schema at startup and surfaces validation errors before any resolver runs.
settingsSchema: z.object({
  apiKey: z.string().min(1),
  baseUrl: z.url(),
})
validator
(args: { dataSources: DataSourceMap, settings: PluginSettings }) => Promise<boolean>
required
An async startup check that runs after data sources are initialised and settings are parsed. Return true to signal readiness, or false (or throw) to abort startup. Use this to verify API credentials, network reachability, or any other precondition.
validator: async ({ dataSources, settings }) => {
  const client = dataSources.get(MyApiDataSource);
  return client.ping();
}

Supporting Types

GraphQLContext

Injected into every type-graphql resolver via @Ctx(). Defined in lib/types/graphql-context.ts.

logger

A Winston Logger instance scoped to the current request. Use it for structured, levelled logging inside resolvers.

sendEvent

(event: RivenExternalEvent) => void — sends an external event into Riven’s event bus. Used by resolvers to trigger item requests (e.g. from a GraphQL mutation).

plugins

Partial<Record<symbol, { dataSources: DataSourceMap }>> — a map from plugin symbol to its DataSourceMap. Access your own data sources with context.plugins[MY_PLUGIN_SYMBOL]?.dataSources.
import type { GraphQLContext } from "@repo/util-plugin-sdk/types/graphql-context";

@Resolver()
export class MyResolver {
  @Query(() => String)
  async hello(@Ctx() ctx: GraphQLContext): Promise<string> {
    ctx.logger.info("hello query called");
    return "world";
  }
}

DataSourceMap

A typed Map<DataSourceConstructor, BaseDataSource> with an overridden .get() that throws instead of returning undefined when the requested constructor is not registered. This ensures failed lookups surface early rather than silently propagating undefined into resolvers.
import { DataSourceMap } from "@repo/util-plugin-sdk";

// Inside a context factory or validator:
const client = dataSources.get(MyApiDataSource);
// Throws: DataSource for MyApiDataSource not found in DataSourceMap

DataSourceConstructor

An interface describing a constructable BaseDataSource subclass, including an optional static rateLimiterOptions property for BullMQ rate limiting.
export interface DataSourceConstructor<T extends Record<string, any> = any> {
  rateLimiterOptions?: RateLimiterOptions | undefined;
  new (options: BaseDataSourceConfig<T>): BaseDataSource<T>;
}

Complete Plugin Example

The snippet below shows a minimal but complete plugin definition wiring together all required fields.
import {
  DataSourceMap,
  PluginSettings,
  RivenPlugin,
  RivenPluginPackage,
} from "@repo/util-plugin-sdk";
import z from "zod";

import { MyApiDataSource } from "./datasources/my-api.datasource.ts";
import { MyResolver } from "./resolvers/my.resolver.ts";

const PLUGIN_NAME = Symbol("my-plugin");

const settingsSchema = z.object({
  apiKey: z.string().min(1),
  baseUrl: z.url().default("https://api.example.com"),
});

const plugin = {
  version: "1.0.0",
  name: PLUGIN_NAME,
  dataSources: [MyApiDataSource],
  resolvers: [MyResolver],
  settingsSchema,

  context: async ({
    dataSources,
  }: {
    dataSources: DataSourceMap;
    settings: PluginSettings;
  }) => ({
    myApi: dataSources.get(MyApiDataSource),
  }),

  hooks: {
    "riven.content-service.requested": async ({ dataSources, settings, logger }) => {
      logger.info("Content service requested");
      return {
        movies: [],
        shows: [],
        updateIntervalSeconds: 3600,
      };
    },
  },

  validator: async ({
    dataSources,
  }: {
    dataSources: DataSourceMap;
    settings: PluginSettings;
  }): Promise<boolean> => {
    const api = dataSources.get(MyApiDataSource);
    return api.healthCheck();
  },
} satisfies RivenPlugin;

export const plugin_package = { plugin } satisfies RivenPluginPackage;
Use satisfies RivenPlugin instead of : RivenPlugin so TypeScript can infer the narrowest types for your hooks callbacks while still validating the full shape.

Build docs developers (and LLMs) love