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

@tiendanube/live-state

v1.3.0

Published

Generic React library for rendering live state notifications

Readme

@tiendanube/live-state

React library for rendering dynamic, context-aware notifications based on backend-computed state

npm version License: MIT

A generic React library for rendering live state notifications (banners, alerts) driven entirely by backend-computed state. Built for the Tiendanube/Nuvemshop ecosystem using the Nimbus Design System.


Features

  • Backend-controlled — all content and logic comes from the API, zero hardcoding
  • Type-safe — full TypeScript support with strict types
  • Analytics built-in — automatic Amplitude + Clarity tracking for view, click, and close events
  • Graceful degradation — fails silently, never breaks the host application
  • Nimbus Design System — uses @nimbus-ds/components

Installation

yarn add @tiendanube/live-state

Install peer dependencies if not already present:

yarn add react react-dom @nimbus-ds/components @nimbus-ds/icons

Quick start

1. Add the provider

import { LiveStateProvider } from '@tiendanube/live-state';

async function fetchLiveState() {
  try {
    const res = await fetch('/api/lending/live-state', {
      headers: { Authorization: `Bearer ${token}` },
    });
    return res.status === 204 ? null : res.json();
  } catch {
    return null;
  }
}

function App() {
  return (
    <LiveStateProvider
      fetcher={fetchLiveState}
      analytics={{
        amplitudeKey: process.env.REACT_APP_AMPLITUDE_KEY,
        clarityProjectId: process.env.REACT_APP_CLARITY_PROJECT_ID,
      }}
    >
      <YourApp />
    </LiveStateProvider>
  );
}

2. Render notifications

import { useLiveState, LiveStateRenderer } from '@tiendanube/live-state';

function LendingNotifications() {
  const { liveState, isLoading } = useLiveState();

  return (
    <LiveStateRenderer
      data={liveState}
      loading={isLoading}
      trackingConfig={{ prefix: 'lending_', page: 'dashboard' }}
    />
  );
}

That's it. The library handles rendering, tracking, and CTA behavior automatically.


Caching behaviour (SWR)

The lib uses SWR internally for data fetching, caching, and deduplication. Key implications:

  • Single request per session — all useLiveState() calls inside the same LiveStateProvider share one cached result. The backend is called once, regardless of how many pages or components use the hook.
  • Cache key is fixed — the cache key is the string 'live-state', not the fetcher URL. This means changing the page prop on LiveStateRenderer does not trigger a new request — the page is a frontend-only concern for tracking event names.
  • Fetcher reference stability — SWR does not re-fetch when the fetcher function reference changes, because the key is fixed. Even so, it is good practice to define the fetcher outside the component (or use useCallback/useMemo) to avoid unnecessary re-renders.
  • Revalidation on reconnect — the lib revalidates automatically when the browser reconnects to the network.
  • No revalidation on focus — focus-based revalidation is disabled to avoid extra requests when the user switches tabs.
  • Manual refresh — call refresh() from useLiveState() to force a re-fetch at any time.
// ✅ Define fetcher outside the component — stable reference, no re-renders
const fetcher: LiveStateFetcher = async () => { ... };

function App() {
  return <LiveStateProvider fetcher={fetcher}>...</LiveStateProvider>;
}

// ❌ Avoid defining fetcher inline — new reference on every render
function App() {
  return (
    <LiveStateProvider fetcher={async () => { ... }}>...</LiveStateProvider>
  );
}

Testing utilities

Import from @tiendanube/live-state/testing in your test files:

import {
  MockLiveStateProvider,
  createMockLiveState,
  mockUseLiveState,
} from '@tiendanube/live-state/testing';

// Render with controlled live state data
render(
  <MockLiveStateProvider liveState={createMockLiveState({ type: 'alert' })}>
    <MyComponent />
  </MockLiveStateProvider>
);

// Mock the hook directly in unit tests
vi.mock('@tiendanube/live-state', async (importOriginal) => ({
  ...(await importOriginal()),
  useLiveState: () => mockUseLiveState({ liveState: createMockLiveState() }),
}));

MockLiveStateProvider automatically sets disabled={true}, suppressing all analytics SDK calls in tests.


Disabling analytics (dev / test / staging)

Pass disabled={true} to LiveStateProvider to prevent the Amplitude and Clarity SDKs from being initialised. The prop value should come from your app's own environment variable — the library does not define or read any env var itself.

// Vite
<LiveStateProvider
  fetcher={fetchLiveState}
  disabled={import.meta.env.VITE_APP_ENV !== 'production'}
>
  ...
</LiveStateProvider>

// Create React App / Next.js
<LiveStateProvider
  fetcher={fetchLiveState}
  disabled={process.env.NODE_ENV !== 'production'}
>
  ...
</LiveStateProvider>

When disabled is true, onEvent callbacks still fire normally so you can observe tracking without hitting the real SDKs.


Fetcher timeouts

The library does not impose a timeout on the fetcher — if the endpoint hangs, isLoading will remain true indefinitely. Because live state notifications are non-critical UI, you should configure a timeout directly in your fetcher so that a slow backend never blocks the page.

// Using axios
const fetcher: LiveStateFetcher = async () => {
  const { data } = await axios.get('/api/live-state', { timeout: 5000 });
  return data ?? null;
};

// Using native fetch + AbortSignal
const fetcher: LiveStateFetcher = async () => {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), 5000);
  try {
    const res = await fetch('/api/live-state', { signal: controller.signal });
    return res.ok ? await res.json() : null;
  } catch {
    return null; // timeout or network error — fail silently
  } finally {
    clearTimeout(id);
  }
};

Documentation


Contributing

This is an internal Tiendanube/Nuvemshop library. For questions or issues, contact the team.


License

MIT © Tiendanube/Nuvemshop