npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@oc-mui/query

v2.0.0

Published

Data-fetching and plugin-config facade (TanStack Query) for the Opencast Management UI and its plugins.

Readme

@oc-mui/query

Data-fetching layer. Wraps TanStack Query and graphql-request behind a single workspace import, exposes typed GraphQL hooks generated from .graphql files, and owns the definePluginConfig reader API.

Contract: implements the Config Contract — see docs/reference/contracts.md and docs/reference/configuration.md. Public API surface tracked in etc/query.api.md.

The wrapper rule

This package is the only place in the workspace allowed to import from @tanstack/react-query. Apps, plugins, and other packages must import useQuery, useMutation, QueryClient, … from here. The rule is enforced by no-restricted-imports in @oc-mui/eslint-config with an explicit exception for this directory.

If we ever need to swap or major-bump the underlying library, we change it here without touching plugins or apps.

Usage

Read your plugin's config slice

import { z } from "zod";
import { definePluginConfig } from "@oc-mui/query";

const schema = z.object({
  pageSize: z.number().int().positive().default(20),
});

export const myPluginConfig = definePluginConfig({
  id: "my-plugin",
  schema,
  defaults: { pageSize: 20 },
});

// In a component:
const { pageSize } = myPluginConfig.use();

// In an event handler:
const { pageSize } = myPluginConfig.read();

Run a typed GraphQL query

import { useMuiGetMyEventsQuery } from "@oc-mui/query";

const { data, isLoading } = useMuiGetMyEventsQuery({ limit: 20 });
const events = (data?.currentUser?.myEvents?.nodes ?? [])
  .filter((e): e is NonNullable<typeof e> => e !== null);

Surface

| Symbol | Purpose | |--------|---------| | QueryProvider | Wraps the app in a TanStack QueryClientProvider. The shell mounts it; plugins consume the client through hooks. | | definePluginConfig({ id, schema, defaults }) | Builds a typed config reader. Returns { id, schema, defaults, register, use, read }. Reading another plugin's slice is forbidden — enforced by the local/no-cross-plugin-config lint rule. | | useAppConfig() | Reads the merged AppConfig. Source of truth for app.theme, app.locale, app.enabledPlugins. | | useGetUserInfo() | Currently-signed-in user. | | Generated hooks (useMuiGetMyEventsQuery, …) | One hook per .graphql operation (operation names carry the mandatory Mui prefix), regenerated by GraphQL Codegen into src/gql-generated.ts. | | EVENT_SORTABLE_FIELDS, SERIES_SORTABLE_FIELDS, PLAYLIST_SORTABLE_FIELDS | Runtime lists of the fields the backend accepts in EventOrderByInput / SeriesOrderByInput / PlaylistOrderByInput. Derived from the schema by codegen (see below); fed into restrictSortingToFields from @oc-mui/ui so tables only offer sorts the backend supports. | | gql (re-export from graphql-request) | For ad-hoc operations; prefer codegen for anything reused. |

For the exhaustive list, see etc/query.api.md.

Code generation

Two source files in this package are generated from the committed schema — src/schema.graphql — and committed to the repo, so the rest of the workspace (and CI) builds and regenerates without a backend:

| Generated file | Produced by | Contains | |----------------|-------------|----------| | src/gql-generated.ts | @graphql-codegen typescript + typescript-operations + typescript-react-query plugins (plus add for the two header lines) | Types and React Query hooks for every .graphql operation. The Mui…Document / Mui…FragmentDoc constants are plain strings. | | src/schema-input-fields.generated.ts | the local codegen-plugins/input-field-names.mjs plugin | Runtime as const arrays of the field names in each *OrderByInput / *FilterByInput type. TypeScript input types are erased at runtime, so this is how the UI knows which fields are orderable/filterable without hardcoding them. |

You only need to run codegen when an operation or the schema changes — not as part of normal setup or per-build. The generated files are committed; a fresh clone builds fine without ever running codegen. pnpm codegen:check (part of pnpm verify and CI) regenerates from the committed schema and fails on any diff, so inputs and outputs cannot drift apart.

Adding or changing an operation (.graphql files) needs no backend at all:

pnpm --filter @oc-mui/query codegen

When the backend schema changed, refresh the committed SDL first — this is the deliberate, reviewed step that does need a backend (endpoint from the repo-root .env):

pnpm --filter @oc-mui/query schema:refresh   # updates src/schema.graphql — review the diff!
pnpm --filter @oc-mui/query codegen

schema.graphql's header records which Opencast version it was taken from. Mind that Opencast's *MetadataInput types are per-organisation (readOnly catalog fields are absent from them) — refresh from an instance whose catalog configuration matches what the UI should support. If schema-input-fields.generated.ts changes, src/sortableFields.test.ts may need its pinned expectations updated — that test failing is the intended signal that the set of sortable/filterable fields shifted.

The schema's custom scalars are mapped explicitly in the codegen config — DateTime and Duration to string, Long to number, JSON to unknown — matching what the backend puts on the wire. Nullable result fields are generated as required-with-null (title: string | null), not optional; only @skip/@include/@defer make a field optional.

The config lives in src/codegen.ts; the refresh script in src/refresh-schema.mjs. typescript-operations ≥ 6 would re-emit every input type and enum an operation names, duplicating the typescript plugin's declarations in the same file — the config points its importSchemaTypesFrom back at the output file so it emits neither (see the comment there). Post-processing (src/fix-fetcher-import.mjs) unwraps the TypedDocumentString objects typescript-react-query ≥ 7 forces onto the document constants back into plain strings (a String subclass would break === and graphql-request's client.request() at runtime, and types nothing here), and annotates the generated hooks' return types explicitly so the emitted .d.ts never references tanstack's NoInfer — that reference only resolves on some @tanstack/react-query minors, and where it doesn't, every hook's data silently degrades to any for consumers (#354). test:consumer-types guards both halves.

Layer

Integration. Depends on @oc-mui/plugin-system, @oc-mui/utils. The Config Contract reader (definePluginConfig) ties it to @oc-mui/ui-config for the AppConfig shape.

See also