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

stableref

v0.1.0

Published

Proof-carrying referential stability for React and Preact.

Readme

stableref

Proof-carrying referential stability for React and Preact. Objects and functions must carry a private Stable<T> brand; primitives pass through unchanged.

import { memo } from "react";
import {
  useCallback,
  useMemo,
  type Stable,
} from "stableref/react";

type Item = { id: string };
type ItemListProps = {
  items: Stable<Item[]>;
  onSelect: Stable<(id: string) => void>;
  title: string;
};

const ItemList = memo((props: ItemListProps) => null);

function Screen({ source }: { source: Stable<Item[]> }) {
  const items = useMemo(() => source.filter(Boolean), [source]);
  const onSelect = useCallback((id: string) => console.log(id), []);
  return <ItemList items={items} onSelect={onSelect} title="Items" />;
}

The strict entry exports React's original hook references under stronger signatures. There are no wrapper functions and no new hook names. Unproven reference dependencies are immediate type errors, including in effects.

Install

pnpm add stableref

React 18+ or Preact 10.10+, plus TypeScript 5.4+, are peer dependencies.

Strict React hooks

Import dependency-bearing hooks from the React entry:

import {
  useCallback,
  useEffect,
  useMemo,
} from "stableref/react";

The exported values are identical to React's functions at runtime:

strictUseMemo === React.useMemo; // true

Their signatures require every dependency to be a primitive or carry Stable<T> proof:

const proven = stable({ id: 1 });
const raw = { id: 2 };

useMemo(() => proven.id, [proven]); // Stable<number>
useMemo(() => raw.id, [raw]);
//                         ^ type error

useEffect(sync, [proven]);
useEffect(sync, [raw]);
//               ^ type error

When a dependency is unproven, the error is written to be actionable rather than cryptic. Instead of failing against never, the offending element is mapped to a string literal that names the fix, and TypeScript prints it verbatim in the diagnostic:

useMemo(() => raw.id, [raw]);
// Type '{ id: number; }' is not assignable to type
// 'This dependency is not Stable<T>: memoize it with useMemo/useCallback,
//  source it from useState, depend on a useRef container rather than its mutable
//  current value, or wrap a module-scope constant with stable().'

The caret lands on the exact dependency, so a human reading it in their editor, or a coding agent reading it out of tsc, is told what to do next.

The entry also brands the contracts already supplied by useState, useReducer, useRef, and useTransition.

Package entries

The package root exports only the framework-neutral types and stable(). Import hooks and createStableContext from stableref/react or stableref/preact. The package does not augment hooks imported directly from React or Preact because module augmentation cannot remove their permissive dependency signatures.

Stable sources

Module constants

stable is an identity assertion for values whose lifetime is already stable. Reserve it for module scope:

import { stable } from "stableref/react";

export const EMPTY_ITEMS = stable([] as Item[]);

Context

createStableContext pushes the proof requirement to the provider:

import {
  createStableContext,
  type Stable,
} from "stableref/react";

const ThemeContext = createStableContext<Theme | null>(null);

function ThemeProvider({ value }: { value: Stable<Theme> }) {
  return <ThemeContext.Provider value={value} />;
}

Preact

The Preact entry provides the same strict API using Preact's original hook references:

import {
  useEffect,
  useMemo,
  type Stable,
} from "stableref/preact";

Hooks imported directly from preact/hooks are unchanged.

Limitations

Like every TypeScript brand, Stable<T> can be bypassed deliberately with a type assertion. The package does not include an ESLint plugin. stable() is also an explicit assertion and must be reserved for values whose lifetime really is stable.

The brand is compile-time only. The strict exports add a small re-export module, but preserve the original React and Preact hook identities and add no wrapper calls.