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

@sentinel-core/sentinel

v1.0.63

Published

Runtime intelligence for your UI.

Readme

@sentinel-core/sentinel

Runtime intelligence for your React UI — hover to inspect, click to deep-dive into props, Redux state, and Saga effects.

Installation

npm install @sentinel-core/sentinel

Import the CSS in your client entry point:

import "@sentinel-core/sentinel/index.css";

Usage

Wrap your app with SentinelProvider in the client entry point only (never server-side):

import { SentinelProvider } from "@sentinel-core/sentinel";
import "@sentinel-core/sentinel/index.css";

function ClientApp() {
  return (
    <SentinelProvider>
      <App />
    </SentinelProvider>
  );
}

Toggle the toolbar with the floating button (bottom-right) or Ctrl+Shift+S.

SentinelProvider Props

| Prop | Type | Description | |---|---|---| | store | ReduxStore | Redux store for live state inspection | | sagaMonitor | SentinelSagaMonitor | Saga monitor from createSentinelSagaMonitor() | | reduxMiddleware | SentinelReduxMiddleware | Action log middleware from createSentinelReduxMiddleware() | | serverState | unknown | Server-side Redux state snapshot (SSR) | | serverSagaEffects | EffectRecord[] | Server-side saga effects (SSR) | | serverActionLog | ActionRecord[] | Server-side action log (SSR) | | externalLinks | ExternalLink[] | Deep-link buttons shown in the component dialog header |

Redux Integration

import { SentinelProvider } from "@sentinel-core/sentinel";

<SentinelProvider store={reduxStore}>
  <App />
</SentinelProvider>

Pass serverState for SSR apps to show a Client/Server toggle in the State tab:

<SentinelProvider store={reduxStore} serverState={window.__INITIAL_STATE__}>
  <App />
</SentinelProvider>

Action Log

Record dispatched actions with top-level state diffs in the toolbar's Log tab:

import { createSentinelReduxMiddleware } from "@sentinel-core/sentinel";

const sentinelMiddleware = createSentinelReduxMiddleware(); // options: { maxRecords } (default 50)
const store = createStore(reducer, applyMiddleware(sentinelMiddleware.middleware));
<SentinelProvider store={store} reduxMiddleware={sentinelMiddleware}>
  <App />
</SentinelProvider>

Framework actions (@@…, persist/…) are hidden by default behind a System toggle, and consecutive duplicates collapse into a single grouped row.

Saga Integration

import { createSentinelSagaMonitor } from "@sentinel-core/sentinel";

const sagaMonitor = createSentinelSagaMonitor(); // options: { maxRecords } (default 100)
const sagaMiddleware = createSagaMiddleware({ sagaMonitor });

// Pass to both the middleware and the provider
<SentinelProvider sagaMonitor={sagaMonitor}>
  <App />
</SentinelProvider>

Supports redux-saga v1.x and v0.x.

The Saga tab shows CALL effects by default; TAKE/FORK/PUT plumbing is one click away via the type filters.

API Layer

With a saga monitor connected, clicking a component shows an API Layer tab in the dialog:

  • Lists HTTP calls extracted from saga effects — both Axios responses and rejections (rejected calls keep their status code and request config)
  • Filters to the requests whose response data matches the clicked component's props; a Props match / All toggle switches views
  • A collapsed props mapping accordion traces each prop to the response field it came from (price ← variants[0].price), and matched fields are highlighted (and auto-expanded) in the response tree
  • Copy as cURL rebuilds the request with method, URL, headers, and body

Server-side calls from serverSagaEffects are included and tagged with a server badge.

External Links

externalLinks lets you add custom deep-link buttons to the component dialog header. When a component is clicked, matching links are resolved and shown.

import { SentinelProvider } from "@sentinel-core/sentinel";

<SentinelProvider
  externalLinks={[
    {
      label: "Open in Storybook",
      match: (componentName) => storybookComponents.includes(componentName),
      url: (props) => `https://storybook.example.com/?path=/story/${props.id}`,
    },
  ]}
>
  <App />
</SentinelProvider>

ExternalLink type

type ExternalLink = {
  match: (componentName: string, props: Record<string, any>) => boolean;
  url: (props: Record<string, any>, sagaEffects: EffectRecord[]) => string;
  label: string;
};

Voltran MFE Integration

Use the built-in voltranExternalLink helper to deep-link to Voltran microfrontend components. It resolves the URL automatically from getFragments saga effects.

import { SentinelProvider, voltranExternalLink } from "@sentinel-core/sentinel";

<SentinelProvider
  sagaMonitor={sagaMonitor}
  serverSagaEffects={serverSagaEffects}
  externalLinks={[
    voltranExternalLink({
      label: "Open in Voltran",         // optional, default: "Open in Microfrontend"
      baseUrl: "https://voltran.example.com", // optional, for relative fragment paths
      preview: true,                    // optional, appends ?preview to the URL
    }),
  ]}
>
  <App />
</SentinelProvider>

The helper matches any component with a fragmentInfo.id prop and resolves the URL from the getFragments saga call's result (client) or config (server).

SSR

Pass server-side data to show Client/Server tabs in the toolbar:

// server entry — collect saga effects and the action log
const sagaMonitor = createSentinelSagaMonitor();
const sentinelMiddleware = createSentinelReduxMiddleware();
await store.dispatch(runSagas());
const serverSagaEffects = sagaMonitor._getSerializableEffects();
const serverActionLog = sentinelMiddleware._getSerializableRecords();

// send to client via window.__SENTINEL__ or similar

// client entry
<SentinelProvider
  store={store}
  sagaMonitor={clientSagaMonitor}
  reduxMiddleware={clientSentinelMiddleware}
  serverState={window.__SENTINEL__.state}
  serverSagaEffects={window.__SENTINEL__.sagaEffects}
  serverActionLog={window.__SENTINEL__.actionLog}
>
  <App />
</SentinelProvider>

Plugin

Use @sentinel-core/sentinel-plugin to automatically wrap your components at build time — no manual <Sentinel> wrapper needed.

Webpack

Add conditionNames to your resolve config:

resolve: {
  conditionNames: ["require", "default"],
}

License

MIT