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

@lomray/consistent-suspense

v2.0.10

Published

React library for generate stable ID inside suspense.

Readme

A suspension that knows where it is

npm GitHub

Quality Gate Status Reliability Rating Security Rating Vulnerabilities Lines of Code Coverage

This package associates generated IDs and streamed HTML with React Suspense boundaries. It is intended for libraries that coordinate boundary-scoped state during streaming SSR. It is not a data-fetching library or a general replacement for React's useId. See the original motivating issue for the retry behavior that prompted it.

The peer range starts at React and React DOM 18. That range does not establish compatibility with every future streaming HTML format. The minimal example below is checked with release 2.0.9 and React/React DOM 18.3.1.

Getting started

The package is distributed using npm, the node package manager.

npm i --save @lomray/consistent-suspense

How to use

Use the provider and Suspense boundary from this package together. For SSR, render a fresh provider for each request. If you supply its optional store prop, create a new SuspenseStore for each request, never one shared across requests.

import React from 'react';
import { ConsistentSuspenseProvider, Suspense, useId } from '@lomray/consistent-suspense';

const Field = () => {
  const id = useId();
  return (
    <>
      <label htmlFor={id}>Name</label>
      <input id={id} />
    </>
  );
};

export const App = () => (
  <ConsistentSuspenseProvider>
    <Suspense fallback={<p>Loading...</p>}>
      <Field />
    </Suspense>
  </ConsistentSuspenseProvider>
);

This field does not suspend; it demonstrates the provider and ID wiring. When a boundary has several independently suspending children, wrap each in <Suspense.NS>...</Suspense.NS> to give it a separate namespace. Keep the server and client component structure consistent; IDs do not repair hydration mismatches.

Analyze suspense html chunks (streaming)

The server entry point is @lomray/consistent-suspense/server. This integration sketch assumes your application supplies app, App and its error handling. Create the analyzer inside the request handler. The callback may insert HTML; never interpolate untrusted state directly into a script. Use an audited serializer and your application's CSP strategy if you add state transfer.

import { Transform } from 'node:stream';
import { StringDecoder } from 'node:string_decoder';
import { renderToPipeableStream } from 'react-dom/server';
import { StreamSuspense } from '@lomray/consistent-suspense/server';

app.use('*', (req, res, next) => {
    const suspenseStream = StreamSuspense.create((suspenseId) => {
      // Observe completion without inserting application data into HTML.
      console.log('Completed Suspense boundary:', suspenseId);
      return '';
    });
    const decoder = new StringDecoder('utf8');
    const responseTransform = new Transform({
      transform(data, encoding, done) {
        // Decode bytes incrementally, including characters split between writes.
        const html = decoder.write(data);
        const rewrittenHtml = suspenseStream.analyze(html);

        // An empty string means the parser is waiting for the rest of a token.
        done(null, rewrittenHtml ?? html);
      },
      flush(done) {
        const html = decoder.end();
        const rewrittenHtml = suspenseStream.analyze(html);

        done(null, (rewrittenHtml ?? html) + suspenseStream.end());
      },
    });

    responseTransform.on('error', next);
    responseTransform.pipe(res);

    const stream = renderToPipeableStream(<App />, {
      onShellReady() {
        stream.pipe(responseTransform);
      },
      onShellError: next,
    });
});

Investigate demo app to more understand how it works.

Bugs and feature requests

Bug or a feature request, please open a new issue.

License

Made with 💚

Published under MIT License.