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

@rustra/react

v0.8.3

Published

React and React Native bindings and hooks for rustra-bridge

Readme

English | 한국어

@rustra/react

React hooks and context bindings for Rustra command clients.

import { RustraProvider, useCommand } from '@rustra/react';
import { getItem } from './generated/commands.js';

function Item({ id }: { id: string }) {
  const { data, loading, error } = useCommand(getItem, { id });
  if (loading) return <span>Loading...</span>;
  if (error) return <span>{error.message}</span>;
  return <span>{data?.name}</span>;
}

<RustraProvider engine={engine}>
  <Item id="item-1" />
</RustraProvider>;

The package provides RustraProvider, useRustraEngine, useCommand, useMutation, useEvent, useSuspenseCommand, invalidateCommands, and configureSuspenseCache. React is a peer dependency; configure the platform-specific Rustra engine before rendering the provider.

useSuspenseCommand(commandFn, input?, options?) is the Suspense-compatible read: it suspends by throwing the in-flight promise until the command resolves, then returns the value directly (a rejection is re-thrown to the nearest error boundary). Results are keyed by the provider's EngineClient identity, command name, and structural input. Use a separate provider engine for every SSR request or account; sharing one engine intentionally shares its cache. Without a provider, all components share the current global registration scope. Replacing or disposing the registration creates a fresh scope on the next render; stale retained callbacks cannot invoke the replacement engine. Use a request-specific Provider for concurrent SSR users.

Each engine keeps at most 256 entries. Completed entries expire 5 minutes after settlement; insertion at capacity evicts the least recently accessed settled entry. Pending promises are protected from eviction so Suspense retries reuse the same work. If all slots are pending, a new key throws a capacity error to the error boundary. A pending entry rejects after 30 seconds and can then be evicted or expire. The cache deadline stops waiting; it does not cancel the underlying engine operation. Invocation options apply only when creating the entry.

configureSuspenseCache({ maxEntries, ttlMs, pendingTimeoutMs }, engine?) changes one engine's policy and clears its existing entries; omit the engine to configure the global default scope. Values must be positive safe integers (time values at most 2,147,483,647 ms). Explicitly invalidating pending work leaves its promise intact for current callers, but late completion never repopulates the cache.

  • invalidateCommands('getItem', engine) clears that exact command in one engine.
  • invalidateCommands(undefined, engine) clears one engine's entire cache.
  • invalidateCommands('getItem') clears that exact command across live engines.
  • invalidateCommands() clears every live cache.

Invalidation and expiry take effect on the next render; neither triggers a render by itself. Engines are weakly held, and cached results also have finite retention.

import { Suspense } from 'react';
import { invalidateCommands, useSuspenseCommand } from '@rustra/react';
import { getItem, saveItem } from './generated/commands.js';

function Item({ id }: { id: string }) {
  const item = useSuspenseCommand(getItem, { id }); // suspends until resolved
  return <span>{item.name}</span>;
}

async function rename(id: string, name: string) {
  await saveItem({ id, name });
  invalidateCommands('getItem'); // next render of <Item> re-fetches
}

<Suspense fallback={<span>Loading...</span>}>
  <Item id="item-1" />
</Suspense>;

useCommand and useSuspenseCommand accept structural inputs containing plain records, arrays, bigint, Set, Map, Date, ArrayBuffer, and typed binary views. Keys include value types and binary contents; plain-record field order is ignored, while Set/Map iteration order and binary view types are preserved. Functions, symbols, cyclic structures, and unsupported class instances are rejected with a TypeError instead of silently colliding. The engine receives the original input.

useMutation resets visible state when its engine or resolved command changes. An in-flight call can still settle and return to its caller, but it cannot update a replacement scope or a reset/unmounted hook. Success/error/settled callbacks are captured at invocation time and still belong to that invocation, including when it settles after a reset or scope change. Overlapping calls keep loading true until all current-scope calls settle; only the latest call updates data/error.

Engine identity. Engines are keyed by object identity (a WeakMap), not by value. Pass a stable engine to RustraProvider — a module-level constant or a useMemo result; an unstable engine prop (a new object every render) is observed as an engine swap and resets useMutation state on every render. Intentional swaps resetting state are by design.

useEvent accepts synchronous or asynchronous unsubscribe registration. Replacing an event/subscriber or unmounting immediately disables delivery from the old subscription. A cleanup function that arrives afterward is invoked once.