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

@wisdomai/react

v0.0.10

Published

Wisdom AI React SDK

Readme

@wisdomai/react

React SDK for Wisdom AI. Ships a React context provider, auth hook, and a typed GraphQL client:

  • <WisdomProvider> — fetches a short-lived JWT + the tenant baseUrl from your backend's /auth-token endpoint and exposes them via context. Accepts an optional theme prop (see Theming) and an optional getAuthToken callback to bypass the default endpoint (see Custom auth token source).
  • useWisdomAuth() — hook returning { jwt, baseUrl, client, isLoading, error, refresh }.
  • useWisdomClient() — hook returning a ready-to-use WisdomClient (null until auth succeeds).
  • useWisdomTheme() — hook returning the active WisdomTheme (the prop passed to <WisdomProvider>, or the default).
  • WisdomClient — typed GraphQL client. Currently exposes client.dashboards.get(id).

Capabilities

The SDK renders dashboards authored on the Wisdom platform directly in your React app — live data, your theme, and interactive filtering. Render a full dashboard with <Dashboard>, or drop in individual widgets with <DashboardWidget>.

  • Visualizations — all chart types, data tables (with server-side paging), single- and multi-value metric cards, and text.
  • Filters — interactive string, numeric (integer and float), enum, and date filters, driven by row-click, the filter drawer, or programmatically via setFilterValue (see Dashboard filters).

The layout, data, and filter specs come from the dashboard you built in Wisdom; the SDK renders them client-side and keeps them in sync with the platform.

Installation

npm install @wisdomai/react \
  @mui/material@^7 @mui/x-date-pickers@^7 \
  @emotion/react@^11 @emotion/styled@^11 \
  highcharts@^12 highcharts-react-official@^3 \
  graphql@^16 luxon@^3

Keep the version pins — installing these peers unpinned resolves to their latest majors and fails ERESOLVE against the SDK's peer ranges. Your app must additionally provide react (>=18) and react-dom (>=18).

Using an AI coding agent? The package ships an AGENTS.md with condensed, copy-ready setup steps — point your agent at it to scaffold the integration.

Quick start: authentication

The SDK never sees your long-lived Wisdom access token. Your backend mints a short-lived JWT from that access token and serves it; <WisdomProvider> fetches the JWT in the browser and refreshes it before it expires.

1. Serve a token endpoint from your backend

Expose POST /auth-token on the same origin as your app, returning { jwt, baseUrl }. Keep WISDOM_ACCESS_TOKEN server-side only.

Protect this route with your app's own authentication. It exchanges your server-side access token for browser credentials, so only signed-in users of your app should be able to call it — an open /auth-token lets anyone mint a Wisdom JWT for your org. The examples below omit that guard for brevity; add your existing session/authz check before the exchange (and mint a per-user token with impersonateUser when each user should see only their own data).

import { WisdomAI } from '@wisdomai/node';
import Fastify from 'fastify';

const wisdom = new WisdomAI({
  accessToken: process.env.WISDOM_ACCESS_TOKEN!,
  baseUrl: process.env.WISDOM_BASE_URL!,
});

const app = Fastify();

// Returns { jwt, baseUrl } — a short-lived token plus your tenant API URL.
app.post('/auth-token', () => wisdom.getAuthToken());

await app.listen({ port: 3000 });

Not on Node? getAuthToken() is just a thin wrapper over the GraphQL exchangeAccessToken query, so any backend can do the same exchange — POST {baseUrl}/graphql with your access key, then pair the returned JWT with your tenant baseUrl:

// exchangeAccessToken(accessToken: String!): String!  — returns a bare ~60-min JWT.
app.post('/auth-token', async () => {
  const res = await fetch(`${process.env.WISDOM_BASE_URL}/graphql`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: 'query Exchange($t: String!) { exchangeAccessToken(accessToken: $t) }',
      variables: { t: process.env.WISDOM_ACCESS_TOKEN },
    }),
  });
  const { data } = await res.json();
  return { jwt: data.exchangeAccessToken, baseUrl: process.env.WISDOM_BASE_URL };
});

exchangeAccessToken issues an org-level JWT (the same identity for every caller). For multi-user production embeds where each end user should see only their own data, mint a per-user JWT with impersonateUser instead and return that as jwt — the provider contract ({ jwt, baseUrl }) is the same.

2. Wrap your app and read a dashboard

<WisdomProvider> calls POST /auth-token, exposes a ready-to-use client via useWisdomClient() (null until auth succeeds), and silently re-fetches the JWT shortly before it expires and when the tab regains focus.

import { WisdomProvider, useWisdomClient } from '@wisdomai/react';
import { useEffect, useState } from 'react';

function App() {
  return (
    <WisdomProvider>
      <DashboardName id="dashboard-id-123" />
    </WisdomProvider>
  );
}

function DashboardName({ id }: { id: string }) {
  const client = useWisdomClient();
  const [name, setName] = useState<string | null>(null);

  useEffect(() => {
    if (!client) return;
    client.dashboards.get(id).then((dashboard) => setName(dashboard.name));
  }, [client, id]);

  if (!client) return <p>Authenticating…</p>;
  return <p>{name ?? 'Loading…'}</p>;
}

If your app already holds a Wisdom JWT (e.g. the SDK is mounted inside an authenticated app), skip the endpoint entirely with the getAuthToken callback. For the exact endpoint contract and error handling, see Requirements on the partner backend.

Usage

import { WisdomProvider, useWisdomClient, WisdomDashboardNotFoundError } from '@wisdomai/react';
import { useEffect, useState } from 'react';

function App() {
  return (
    <WisdomProvider>
      <DashboardView />
    </WisdomProvider>
  );
}

function DashboardView() {
  const client = useWisdomClient();
  const [name, setName] = useState<string | null>(null);
  const [notFound, setNotFound] = useState(false);

  useEffect(() => {
    if (!client) return;
    client.dashboards
      .get('dashboard-id-123')
      .then((dashboard) => setName(dashboard.name))
      .catch((err) => {
        if (err instanceof WisdomDashboardNotFoundError) setNotFound(true);
        else throw err;
      });
  }, [client]);

  if (!client) return <p>Authenticating…</p>;
  if (notFound) return <p>Dashboard not found</p>;
  return <p>{name ?? 'Loading…'}</p>;
}

Requirements on the partner backend

WisdomProvider sends POST /auth-token to the same origin and expects a JSON response of shape { jwt: string, baseUrl: string }. This matches the sdk-playground Fastify server exactly. If your backend hosts the token endpoint at a different path, you'll need a dev proxy or a reverse proxy in front of your app.

baseUrl must include the scheme. Use the full origin, e.g. https://canary.gowisdom.ai — not a bare host (canary.gowisdom.ai). The SDK derives its WebSocket endpoint from baseUrl, and a value without an http(s):// prefix throws SubscriptionTransport: unrecognized baseUrl protocol.

Custom auth token source

If your app already has access to a JWT (e.g., the SDK is mounted inside an app that holds the user's session), pass a getAuthToken callback to bypass the default POST /auth-token fetch. The callback must resolve to { jwt, baseUrl } (typed as WisdomAuthTokenResult), where baseUrl is the Wisdom tenant API URL (the same value the partner backend would otherwise return from /auth-token) — not the host app's origin, unless the host app reverse-proxies /graphql and the WS endpoints to Wisdom.

import { WisdomProvider, type WisdomAuthTokenResult } from '@wisdomai/react';
import { useCallback } from 'react';
import { getAuthToken } from '@/services/auth';

const WISDOM_BASE_URL = 'https://your-tenant.wisdom.ai';

function App() {
  const resolveAuth = useCallback(async (): Promise<WisdomAuthTokenResult> => {
    const jwt = await getAuthToken();
    return { jwt, baseUrl: WISDOM_BASE_URL };
  }, []);

  return (
    <WisdomProvider getAuthToken={resolveAuth}>
      <DashboardView />
    </WisdomProvider>
  );
}

When getAuthToken is set, the SDK does not call POST /auth-token — your callback is the sole token source. Throw from the callback to surface an auth error via useWisdomAuth().error. Wrap the callback in useCallback (or define it at module scope) so its identity is stable across renders; the provider re-fetches whenever the callback reference changes.

Theming

Pass a theme prop to <WisdomProvider> to control the colors, fonts, and chart palette used by SDK-rendered components (Dashboard, DashboardWidgets, DashboardFilters, WisdomChart). The theme is exposed to your own components via useWisdomTheme() so partner UI can stay visually consistent.

import { WisdomProvider, type WisdomTheme } from '@wisdomai/react';

const theme: WisdomTheme = {
  primaryTextColor: '#ffffff',
  secondaryTextColor: '#a0a0a0',
  background: '#1a1a1a',
  border: '#2a2a2a',
  fontFamily: 'Inter, sans-serif',
  chartColors: ['#4f46e5', '#10b981', '#f59e0b'],
};

<WisdomProvider theme={theme}>
  <DashboardView />
</WisdomProvider>;

fontFamily and chartColors are optional; everything else is required. If theme is omitted, a light default is used. The SDK does not ship light/dark presets — partner apps own their full color system.

You can pass theme as an inline object literal without causing chart re-renders on every parent render; the provider stabilizes its identity by content.

Dashboard filters

Interactive filtering (row-click, drawer, or programmatic) goes through setFilterValue(filterId, filter) from the dashboard context. Two parts of the contract are easy to get wrong:

filterId is the lookup key

setFilterValue matches the filterId against dashboard.filterSpecs[*].filterId exactly. A filterId that doesn't match any spec throws Filter not found on dashboard: <filterId>. The same filterId keys highlight/active-filter lookups, so it must be the spec's filterId verbatim — not the parameterName, displayName, or column name.

The columnRef vs column shape asymmetry

A FilterSpec exposes its column under spec.columnRefs[0] (a ColumnRef). But the serialized filter lhs reads the column from lhs.expression.flattened[0].column (a DataframeColumn) when building the GraphQL input. These are different shapes at different layers — the SDK maps between them in buildLhsFromSpec. If you hand-assemble an lhs, you must populate expression.flattened[0].column; leaving it empty throws a malformed lhs error naming the filterId (it does not silently render a blank chart).

Filtering a column the widgets don't query

A filter only changes a widget if that widget's underlying query references the filtered column (WidgetFilterStatus.WIDGET_FILTER_STATUS_ADDED). If you set a filter whose column no visible widget queries — common for chat-authored widgets whose SQL never selected the entity column — setFilterValue resolves successfully but nothing visibly changes. The SDK emits a console.warn in this case so the no-op is observable during development.

Errors

All errors thrown by the client extend WisdomError:

  • WisdomAuthError — JWT rejected or expired (HTTP 401/403, or GraphQL UNAUTHENTICATED / INVALID_TOKEN). Consumers should call refresh() to re-fetch a token.
  • WisdomDashboardNotFoundErrordashboards.get(id) could not return a dashboard because the ID does not exist or the caller lacks access (server emits NOT_FOUND or FORBIDDEN).
  • WisdomError — everything else (network failure, 5xx, malformed response, uncategorized backend errors). Carries an optional cause and, for GraphQL-level failures, an errors array.

Releasing

The SDK ships a frozen set of GraphQL operations to consumers who cannot re-run codegen, so a backend schema change that removes a field one of those operations uses will hard-fail every dashboard with HTTP 400. To guard against that, the published operation set is snapshotted to published-operations.graphql and the sdk-schema-compat CI gate validates it against the live app-server schema on every change.

When cutting a release, after bumping the version:

pnpm run sdk:snapshot-operations   # from the javascript/ root — refreshes published-operations.graphql

Commit the refreshed snapshot alongside the version bump, then publish. Skipping this only weakens protection for newly-added operations; it never produces a false CI failure.