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.

Riven exposes a type-safe GraphQL API built with Apollo Server, type-graphql, and Express 5. It is the primary interface for external tools and media servers to query library state, inspect the virtual file system, and trigger actions such as resetting a media item or sharing diagnostic logs. The API is ready after the Bootstrap machine’s Initialising services state completes.

Endpoint and Configuration

The API defaults to http://localhost:3000/graphql. Both host and port are configurable:
SettingDefaultDescription
gqlHostlocalhostHostname the Express server binds to
gqlPort3000Port the server listens on
The GraphQL playground (Apollo Sandbox) is available at the same URL when running in development mode.

Authentication Context

Every resolver receives a typed context object. The core context interface extends GraphQLContext from the plugin SDK:
// @repo/util-plugin-sdk/types/graphql-context
interface GraphQLContext {
  logger: Logger;             // Winston logger instance
  sendEvent: (event: RivenExternalEvent) => void; // emit events into the runner
  plugins: Partial<Record<symbol, { dataSources: DataSourceMap }>>;
}

// apps/riven — ApolloServerContext adds the Core context behind a symbol key
interface ApolloServerContext extends GraphQLContext {
  [CoreKey]: {
    em: EntityManager;                     // forked MikroORM EntityManager (per-request)
    services: typeof services;             // database service layer
    sendEvent: MainRunnerMachineIntake;    // internal event bus
  };
}
Resolvers access the core context via the @CoreContext() parameter decorator, which unpacks the CoreKey-namespaced fields:
@Query(() => MediaItemUnion)
async mediaItemById(
  @CoreContext() { services }: CoreContext,
  @Arg("id", () => ID) id: UUID,
) {
  return services.mediaItemService.getMediaItemById(id);
}

Queries

Fetches a media item by its UUID. The return type is a GraphQL union (Movie | Show | Season | Episode) — the concrete type is determined by the underlying entity discriminator.
query GetMediaItem($id: ID!) {
  mediaItemById(id: $id) {
    ... on Movie {
      id
      fullTitle
      state
      expectedFileCount
    }
    ... on Show {
      id
      fullTitle
      state
      seasons(includeSpecials: false) {
        number
        totalEpisodes
      }
    }
    ... on Episode {
      id
      number
      absoluteNumber
      lookupKeys
      season {
        number
      }
    }
  }
}
Lists up to 25 media items from the library. Returns the base MediaItem type — use mediaItemById with inline fragments for type-specific fields.
query ListMediaItems {
  mediaItems {
    id
    fullTitle
    state
    type
  }
}
This query is limited to 25 results and is intended for administrative overview rather than bulk export. Use the database directly for large result sets.
Fetches a specific episode by its TVDB series ID and episode number. When seasonNumber is omitted, lookup uses absolute episode numbering (useful for anime titles that use a single continuous count).
# Standard season + episode lookup
query GetEpisode {
  episode(tvdbId: "83462", episodeNumber: 1, seasonNumber: 1) {
    id
    number
    absoluteNumber
    lookupKeys
    season {
      number
      show {
        fullTitle
      }
    }
  }
}

# Absolute numbering (no seasonNumber)
query GetEpisodeAbsolute {
  episode(tvdbId: "83462", episodeNumber: 42) {
    id
    number
    absoluteNumber
  }
}
Returns FUSE-level file statistics for the given VFS path — equivalent to calling stat() on the virtual mount. The size field is a BigInt.
query StatVfsEntry {
  vfsEntryStat(path: "/movies/Inception (2010)/Inception.mkv") {
    size
    mtime
    ctime
    mode
    nlink
    uid
    gid
  }
}
Returns the VFS entry at the given path as a union of MediaEntry or SubtitleEntry. Returns null if no entry exists at that path.
query GetVfsEntry {
  vfsEntry(path: "/movies/Inception (2010)/Inception.mkv") {
    ... on MediaEntry {
      id
      streamUrl
    }
    ... on SubtitleEntry {
      id
      language
    }
  }
}
Lists the paths of all entries under a VFS directory. Useful for programmatically enumerating the virtual file tree without mounting it locally.
query ListVfsDirectory {
  vfsDirectoryEntryPaths(path: "/movies/Inception (2010)") # returns string[]
}

Mutations

Removes an item request and all its associated media items from the library. Also clears any pending BullMQ deduplication jobs for the item so the queue does not attempt to process it after deletion.Returns true on success, false if an error occurred (check the server logs for details).
mutation RemoveRequest($id: ID!) {
  removeItemRequest(id: $id)
}
Internally this calls clearDeduplicationJob on both the process-item-request and process-media-item queues before removing the database record, then emits riven.item-request.removed into the event bus.
Resets a media item (and, for shows, all its child seasons and episodes) back to a clean state so that the full pipeline can be re-run. Returns the list of items that were reset.
mutation ResetItem($id: ID!) {
  resetMediaItem(id: $id) {
    ... on Movie {
      id
      fullTitle
      state
    }
    ... on Show {
      id
      fullTitle
      state
    }
  }
}
Use this mutation when a media item is stuck in an error state or when you want to force a fresh scrape with updated scraper settings.
Saves a stream permalink directly on a MediaEntry, bypassing the normal debrid acquisition flow. Useful for manually pinning a known-good stream URL or for recovery when the automatic stream link request has failed.Returns the updated MediaEntry.
mutation SaveStream($id: ID!, $url: String!) {
  saveStreamUrl(id: $id, url: $url) {
    id
    streamPermalink
  }
}
Uploads the last 24 hours of ECS-formatted logs to the shared Riven Elasticsearch instance and returns the session ID for lookup. This is intended for debugging sessions with Riven maintainers.Returns a String session ID that can be provided to the Riven team to locate your logs.
mutation ShareLogs {
  shareLogs
}
shareLogs throws if settings.loggingEnabled is false. The mutation streams log lines from the ECS symlink path and bulk-indexes them; it will also throw if no log entries are found within the last 24 hours.

Resolver Architecture

All resolver classes are registered at startup in apps/riven/lib/graphql/resolvers/index.ts:
export const resolvers = [
  MediaItemResolver,   // mediaItemById, mediaItems, resetMediaItem
  MediaEntryResolver,  // saveStreamUrl
  EpisodeResolver,     // episode query + season/lookupKeys field resolvers
  ItemRequestResolver, // removeItemRequest
  MovieResolver,       // expectedFileCount field resolver for Movie
  SeasonResolver,      // show, episodes, totalEpisodes, expectedFileCount field resolvers
  ShowResolver,        // seasons (with includeSpecials arg), expectedFileCount
  ShareLogsResolver,   // shareLogs
  VfsResolver,         // vfsEntryStat, vfsEntry, vfsDirectoryEntryPaths
] as const;
Plugins can contribute additional resolvers by including type-graphql resolver classes in their manifest. These are merged into the Apollo schema alongside the core resolvers during the startGqlServer bootstrap actor.

Type Safety

All resolvers use type-graphql decorators, so the schema is derived directly from TypeScript types. @Arg, @Query, @Mutation, and @FieldResolver decorators are the single source of truth — no separate .graphql schema files.

Per-Request Entity Manager

The buildContextFunction forks a new MikroORM EntityManager for every GraphQL request (database.em.fork()), giving each request its own identity map and preventing cross-request entity leakage.

Build docs developers (and LLMs) love