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

@elapse/react

v0.5.2

Published

Authorise, meter and receipt components for Elapse per-second billing.

Readme

@elapse/react

Authorise, meter and receipt components for Elapse — per-second billing. Your subscriber authorises, watches a live counter, and stops, inside your own app. Elapse never asks you to touch their wallet: every signature happens in a window Elapse opens.

npm install @elapse/react

Peers: react 18 or 19, react-dom, and motion.

Quickstart

1. Create a session on your server with @elapse/sdk and your secret key. Never put a secret key in the browser.

const session = await elapse.checkout.sessions.create({
  product: "prod_…",
  successUrl: "https://acme.com/ok",
  cancelUrl: "https://acme.com/cancel",
});
// send session.id to the page

2. Render the components with your publishable key (pk_…).

import { Authorize, ElapseProvider, Meter } from "@elapse/react";
import "@elapse/react/styles.css";

function Billing({ session }: { session: string }) {
  const [started, setStarted] = useState(false);
  return (
    <ElapseProvider publishableKey={process.env.NEXT_PUBLIC_ELAPSE_KEY!}>
      {started ? (
        <Meter session={session} onStopped={(e) => console.log("stopped", e.txHash)} />
      ) : (
        <Authorize session={session} onAuthorised={() => setStarted(true)} onStarted={() => setStarted(true)} />
      )}
    </ElapseProvider>
  );
}

That is the whole integration. <Authorize> shows how long the meter may run and what that can cost, then opens Elapse in a window for Face ID. <Meter> ticks the elapsed time and the amount, shows the controls the product allows, and turns into the receipt when the meter ends.

One window, every time. It used to open in a frame over your page and hand off to a window when the passkey needed enrolling — which browsers refuse inside a cross-origin frame, so the handoff was the common path and the subscriber saw a panel flash by first. Call authorise (or the components' buttons) straight from a click: browsers only allow a window inside the user's own gesture, and a blocked one shows a notice and a Try again.

No bundler? One script tag

<div id="elapse"></div>
<script type="module">
  import { mount } from "https://cdn.jsdelivr.net/npm/@elapse/react/dist/elapse.browser.js";
  mount("#elapse", {
    publishableKey: "pk_test_…",
    session: "cs_…",            // created on your server
    onStopped: (e) => console.log("stopped", e.txHash),
  });
</script>

This build carries its own React (~65 KB gzipped), so the page needs nothing else. If your app already runs React, install the package instead and use the components — you keep one React.

Components

| Component | What it renders | | --- | --- | | <ElapseProvider publishableKey baseUrl? appOrigin? sound?> | Configuration for everything below it. A key starting with sk_ throws. | | <Authorize session onAuthorised onStarted onError> | The cap step, then the Elapse window. | | <Meter session dock? controls? proof? onStopped onPauseRequest? onResumeRequest? onError> | The live meter, its controls, and the receipt. | | <TxLink hash chainId?> | A transaction as 0x4cbe…9143, linked to the explorer. Nothing renders it for you. |

<Meter> options

| Prop | Default | What it does | | --- | --- | --- | | dock | (none) | "bottom-right" or "bottom-left" floats the meter as a small capsule — a live dot, the clock, the amount — instead of a card in your layout. On a phone it spans the gutter. | | controls | true | false hides Stop and the pause requests entirely, for a meter only you stop. | | proof | false | Drops a card when the meter starts and when it ends, carrying that transaction. Off by default: most subscribers should never see a hash. | | onPauseRequest, onResumeRequest | — | Show Pause and Resume as requests to you. A subscriber cannot pause a meter (only the merchant can), so the button calls your handler — nothing is signed, nothing reaches Elapse — and your server pauses with subscriptions.pause. Pause renders only on a Product that allows pausing; omit the props and neither control renders. Return a promise and the meter does the rest: while it is pending it shows "Asked {you} to pause…" and disables the control, on resolve "{you} approved · pausing" until the meter itself turns paused, and on reject "{you} could not pause that meter." Your handler need only make the request and throw if it fails; you write no status UI. |

Sound is on by default: two short synthesised notes when a meter starts and when it stops, never one per second, with a mute the subscriber controls and the browser remembers. sound={false} on the provider turns it off for everyone.

Every event carries { subscription, txHash?, explorerUrl? }.

Hooks

useMeter also returns refresh(), which re-reads the session now rather than at the next 5 s poll — <Meter> calls it itself after a pause or resume you approve, so the meter catches up in about a second.

useAuthorize(session) and useMeter(session) return the same state the components render, for when you want your own markup:

const { elapsed, accrued, running, canStop, stop, receipt } = useMeter(session);

@elapse/react/math exports the meter's money math (accruedNano, formatAmount, …) on its own, for a server or a test.

Styling

@elapse/react/styles.css is plain CSS scoped to .elapse; no Tailwind needed. Change what you want with CSS variables:

.elapse {
  --elapse-accent: #7c3aed;
  --elapse-radius: 1rem;
  --elapse-font: "Inter", sans-serif;
  --elapse-bg: #ffffff;
  --elapse-fg: #101010;
  --elapse-muted: #6b7280;
}

The components follow the system's colour scheme; data-elapse-theme="light" or "dark" on a wrapper pins one.

Every animation stops under prefers-reduced-motion, and the meter never animates per second.

Two things this package will not do

  • It never takes a secret key. Sessions are created on your server.
  • It never shows your subscriber a hash, an address, or any other chain word unless you ask for it with proof or place a <TxLink> yourself. Otherwise those stay on your side, in the events.

MIT © Elapse