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

rozenite-zustand-manager

v0.0.4

Published

Rozenite DevTools plugin to inspect, edit, and time-travel Zustand stores in React Native apps.

Readme

rozenite-banner

A Rozenite plugin that brings live inspection, time-travel, and type-aware action invocation to Zustand stores in React Native.

mit licence npm version npm downloads CI Chat PRs Welcome

The Rozenite Zustand Manager Plugin provides real-time store inspection, time-travel debugging, snapshot capture, and type-aware action invocation for every Zustand store in your React Native app — without per-store wiring.

This plugin is a community contribution to the Rozenite DevTools ecosystem.

🚧 Status: 0.0.1 — alpha. API is stable, the panel UI is still being polished. Feedback and PRs welcome.

Zustand Manager Plugin

Features

  • Metro Autodiscovery: Babel transformer wraps your Metro config and registers every module-level create<T>()(...) Zustand store automatically. Your app source stays untouched.
  • Live Inspector: Tree, JSON, and table views with type-aware inline editing, path/value copy, search, and sensitive-key redaction.
  • Timeline: Every mutation captured as a diff event with real +/− line counts, kind filters (edit / action / replace / reset), restore-before, and side-by-side compare.
  • Snapshots: Capture, import/export JSON, restore-all or per-store, compare current state vs any snapshot in a side-by-side diff modal.
  • Type-aware Action Runner: Every action exposed as a button. Arity-0 actions fire immediately; parameterized actions open a form with per-arg type pills (string / number / boolean / object / array / null / undefined).
  • Safe by Default: Functions stripped before crossing the bridge, sensitive keys (token, password, email, secret, …) redacted server-side, mutations applied as top-level partials so your store actions are never wiped.

Installation

Install the plugin as a dev dependency:

npm install --save-dev rozenite-zustand-manager

Note: This plugin requires zustand (>= 5.0) as a peer dependency, plus Rozenite and @rozenite/metro wired into your project.

Quick Start

1. Install the Plugin

npm install --save-dev rozenite-zustand-manager

2. Wrap Your Metro Config

// metro.config.js
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
const { withRozenite } = require('@rozenite/metro');
const { withZustandManager } = require('rozenite-zustand-manager/metro');

const config = mergeConfig(getDefaultConfig(__dirname), {});

module.exports = withZustandManager(
  withRozenite(config, {
    enabled: process.env.WITH_ROZENITE !== 'false',
  }),
);

No include option needed — Rozenite auto-discovers any installed dependency that ships a dist/rozenite.json manifest.

3. Define Stores Normally

// src/stores/useAuthStore.ts
import { create } from 'zustand';

export const useAuthStore = create<AuthState>()((set) => ({
  user: null,
  signIn: (user) => set({ user }),
  signOut: () => set({ user: null }),
}));

The Metro transformer detects this declaration and injects a dev-only registerZustandStore({ name, file, store }) call. Your source stays untouched.

4. Access DevTools

Start your development server with Rozenite enabled and open React Native DevTools. You'll find the Zustand Manager panel in the DevTools interface.

WITH_ROZENITE=true npm start

Manual Registration

For stores the autodiscovery can't reach — factory functions, runtime-created stores, re-exports through a wrapper — register them explicitly:

import { registerZustandStore } from 'rozenite-zustand-manager';
import { createBottomSheetStore } from './createBottomSheetStore';

const sheet = createBottomSheetStore({ visible: false });

export const useSheetStore = sheet.useStore;

if (__DEV__) {
  registerZustandStore({
    name: 'useSheetStore',
    file: 'features/ui/sheets/useSheetStore.ts',
    store: useSheetStore,
  });
}

registerZustandStore returns a cleanup function. There is also a hook form for component-scoped registration:

import { useZustandManager } from 'rozenite-zustand-manager';

function App() {
  useZustandManager([
    { name: 'useAuthStore', store: useAuthStore },
    { name: 'useCartStore', store: useCartStore, redactPattern: /token|password/i },
  ]);
  return <YourApp />;
}

Configuration

withZustandManager(metroConfig, options?)

type WithZustandManagerOptions = {
  enabled?: boolean; // default true. Set to false in production builds.
};

StoreEntry

| Field | Type | Description | | --------------- | ------------- | ------------------------------------------------------------------------------------------------- | | name | string | Display name in the panel. Required. | | store | StoreApi<T> | The Zustand store (the value returned by create). Required. | | id | string | Stable id for diffing. Defaults to name. | | file | string | Source path, shown in the inspector header. Optional. | | actions | string[] | Whitelist of action names to expose. Defaults to all functions in state. | | editable | boolean | When false, panel disables Edit / Replace / Delete — store becomes read-only. | | redactPattern | RegExp | Custom regex for sensitive keys. Defaults to password\|token\|secret\|email\|apiKey\|authorization. |

Usage

Once you've configured the plugin, it provides:

  • Inspector tab: Sidebar of stores, central tree / JSON / table view of state, right-side detail pane with type-aware inline editing, path/value copy, exposed actions, and danger zone (reset / replace).
  • Timeline tab: Stream of every mutation with diff highlights and +/− counts. Filter by store and kind (edit / action / replace / reset), restore the state from before any event, or compare before/after side-by-side.
  • Snapshots tab: Manual capture or import JSON, restore one store or all, compare a snapshot vs current state in a side-by-side diff modal, export to JSON.
  • Action runner: Arity-0 actions fire on click; parameterized actions open a typed form modal where you pick the kind per parameter (string / number / boolean / object / array / null / undefined).
  • Sensitive-key redaction: Keys matching the redact pattern (default or custom) are masked in the panel and never crossed the bridge raw.

How It Works

The package ships three artifacts that talk through the typed Rozenite bridge:

  1. DevTools panel (dist/devtools/) — Vite-built React app shown in Chrome DevTools.
  2. React Native runtime (dist/react-native/) — singleton on globalThis.__ROZENITE_ZUSTAND_MANAGER_RUNTIME__. Subscribes to each store, sanitizes snapshots, applies remote mutations as top-level partials so actions survive every edit.
  3. Metro transformer (dist/metro/) — wraps @react-native/metro-babel-transformer. For files that import zustand and define module-level create<T>()(...) declarations, appends a __rozeniteZustandRegisterStore({ name, file, store }) call. Factory functions and indented const declarations are deliberately skipped to avoid ReferenceError on closure-scoped variables.

All mutation paths use setState(partial, false) so action functions are never wiped. Replace-state uses the explicit setState(value, true) form. Function values are stripped, and configurable redaction runs before any data crosses the bridge.

Limitations

  • The Metro transformer is regex-based. Only module-level const x = create<...>(...) declarations from zustand / zustand/vanilla are caught. Factories, namespace imports (import * as Z from 'zustand'), and dynamic helpers (createWithEqualityFn, combine, …) need manual registerZustandStore.
  • Action arguments are introspected via fn.length and a best-effort fn.toString() parse. Hermes-optimized builds fall back to generic arg0, arg1 names — the form still works, you just lose the original parameter names.
  • TypeScript type information is not available at runtime; the per-arg form uses kind pills for the user to pick the correct type.
  • Class instances, Date, Map, Set are coerced to JSON-friendly values before crossing the bridge; round-tripping back to the original instance is on you.

Plugin Development

pnpm install
pnpm dev            # vite + rozenite live reload of the panel
pnpm build          # typecheck → tests → vite build → rozenite build
pnpm test           # vitest
pnpm typecheck      # tsc --noEmit
pnpm example:start  # boot the RN example with Rozenite enabled

The example app under example/ reproduces the full flow with useAuthStore, useCartStore, and useUiStore.

Contributing

PRs and issues welcome. See CONTRIBUTING.md for the workflow and project layout. By participating, you agree to abide by the Code of Conduct.

Release notes live in CHANGELOG.md.

Made with ❤️ for the React Native community

rozenite-zustand-manager is a community plugin built on top of Rozenite, the modular DevTools framework crafted by the team at Callstack. Huge ⭐ to them for making the plugin model possible — go give the main repo some love.

If this plugin saves you time, please star the repo and join the Rozenite Discord to share what you build.