Add custom GraphQL queries, mutations, and field resolvers to Riven’s schema from a plugin using type-graphql decorators and the PluginContext injectors.
Use this file to discover all available pages before exploring further.
Every plugin must export at least one GraphQL resolver. Resolvers let your plugin expose queries, mutations, and field extensions that clients — such as the Riven frontend or a custom dashboard — can call directly. Riven merges all plugin resolvers into a single executable schema at startup using type-graphql.
import { PluginContext, PluginDataSource } from '@repo/util-plugin-sdk';import { Arg, FieldResolver, Mutation, Query, Resolver, Root } from 'type-graphql';import { ObjectType, Field } from 'type-graphql';
Never define an @ObjectType() class with the same name as one that already exists in the SDK or another plugin. GraphQL requires globally unique type names — duplicate names will crash schema building at startup.
Injects the entire plugin context for the given plugin symbol. The context object is whatever your plugin’s optional context() factory function returns — typically a settings bag or pre-computed values.
import { PluginContext } from '@repo/util-plugin-sdk';import { pluginConfig } from '../my-plugin.config.ts';import type { MyPluginContext } from '../my-plugin-context.ts';@Resolver()export class MyResolver { @Query(() => String) async greeting( @PluginContext(pluginConfig.name) ctx: MyPluginContext, ): Promise<string> { return `Hello from ${ctx.instanceName}`; }}
Injects a specific BaseDataSource instance from the plugin context’s DataSourceMap. This is the standard way for a resolver to reach an HTTP API client.
PluginDataSource throws at runtime if the requested DataSource constructor was not listed in the plugin’s dataSources array, because it won’t be present in the DataSourceMap.
The minimal resolver every plugin should provide is a connectivity check — it re-uses the validate() method that is already required by BaseDataSource:
import { PluginDataSource } from '@repo/util-plugin-sdk';import { Query, Resolver } from 'type-graphql';import { pluginConfig } from '../comet-plugin.config.ts';import { CometAPI } from '../datasource/comet.datasource.ts';@Resolver()export class CometResolver { @Query(() => Boolean) public async cometIsValid( @PluginDataSource(pluginConfig.name, CometAPI) api: CometAPI, ): Promise<boolean> { return api.validate(); }}
Every plugin should also extend the global Settings type so that clients can discover the plugin’s configuration keys through GraphQL introspection. The Settings base type is exported from the SDK.
import { Settings } from '@repo/util-plugin-sdk';import { FieldResolver, Resolver } from 'type-graphql';import { CometSettings } from './types/comet-settings.type.ts';@Resolver(() => Settings)export class CometSettingsResolver { @FieldResolver(() => CometSettings) public comet(): CometSettings { return { apiKey: 'comet-api-key', }; }}
The matching GraphQL object type lives in lib/schema/types/:
import { Field, ObjectType } from 'type-graphql';@ObjectType()export class CometSettings { @Field(() => String) public apiKey!: string;}
Register both resolvers in your plugin’s resolvers array:
Pass all resolver classes to the resolvers array in your plugin definition. The array must have at least one element (validated at startup by the RivenPlugin Zod schema).