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

nearlyin

v0.2.0

Published

Waitlist form (React), server helpers and webhook verification for NearlyIn

Readme

nearlyin

The waitlist form, the server helpers and the webhook check for NearlyIn: collect sign-ups, confirm addresses, invite people, and let your own sign-up check who is invited.

Full documentation: nearlyin.com/docs

npm install nearlyin

You need a product in the NearlyIn dashboard. It gives you a public key (ni_pk_…) for the browser and a secret key (ni_sk_…) for your server, each for test mode and for live.

The form

import { WaitlistForm } from "nearlyin";

export function Signup() {
  return <WaitlistForm productKey="ni_pk_test_…" locale="en" layout="pill" hideLabel />;
}

The component brings its own styles and loads nothing from other servers. It posts to https://nearlyin.com unless you pass another serviceUrl. Allow the address of your page in the dashboard under "Allowed origins"; a pattern such as https://*-team.vercel.app covers preview deployments. React 18 or newer.

| Prop | What it does | | --- | --- | | layout | "inline" (default): address and button side by side, wrapping where there is no room. "stacked": the button below, both full width. "pill": both in one round field, stacked on narrow screens. | | radius | Rounding of field and button, as pixels (12) or any CSS length. Default 8, fully round for pill. | | hideLabel | Hides the label from sight; screen readers still read it. | | colors | accent, accentHover, accentText, text, inputBackground, inputText, border, error. Any CSS colour value. | | texts | Your own wording, per text. locale ("de" or "en") picks the defaults. | | unstyled | Leaves out the built-in styles. A hidden label and the trap for bots still work. | | className | A class of your own on the outer element. | | referral, source | If your page knows the referral code and the source itself. | | onSuccess | A next step of your own once the address is accepted. |

These class names are stable, with or without unstyled, so your own styles can hang on them:

.wlf          the outer element, with data-layout and data-status (idle, submitting, success, error)
.wlf-form     the form
.wlf-label    the label
.wlf-row      address and button
.wlf-input    the address field
.wlf-button   the button
.wlf-error    the error message (empty while there is none)
.wlf-status   "check your inbox", after sending
.wlf-title    its heading
.wlf-text     its text

If a sign-up fails, the browser's console says why: a blocked connection (see the CSP below), or an origin that is missing under "Allowed origins" (origin_not_allowed). With a test key the form shows the latter itself.

Content-Security-Policy

If your site sends one, add NearlyIn to these directives:

connect-src https://nearlyin.com
form-action https://nearlyin.com

Letting invited people in

The invitation mail links to your product with ?invite=<code>. Set the product's link in the dashboard to the page that checks it, usually your sign-up page. On your server:

import { admitInvitedAccount, isInvited, redeemInvite, verifyInvite } from "nearlyin/server";

// When the page opens: whose code is this? Does not use it up.
const email = await verifyInvite(searchParams.invite); // "[email protected]" or null

// When your server creates the account: works exactly once.
const invited = await redeemInvite(code, { idempotencyKey: signupId });
if (!invited) throw new Error("This invitation is no longer valid.");

// Without a code: is this address allowed in?
await isInvited("[email protected]");

With a login that creates the account itself

Clerk, Auth0, Supabase Auth or Auth.js create the account; your app has no moment of its own to redeem the code in. Hand the code on with the provider's sign-up (Clerk's unsafeMetadata, Supabase's user_metadata, a cookie) and check it when the new account makes its first request:

import { admitInvitedAccount } from "nearlyin/server";

const admitted = await admitInvitedAccount({
  code: user.unsafeMetadata.invite,
  verifiedEmails: user.emailAddresses.filter((a) => a.verification?.status === "verified").map((a) => a.emailAddress),
  attemptId: user.id,
});
if (!admitted) redirect("/sign-up?invite=required");

It returns true only when the code is a valid invitation for one of the verified addresses (case does not matter), and redeems it then. It returns false without a code, for an unknown, expired or used code, and for a code of another address, which stays unused, so a forwarded link does not let a stranger in. It never throws: when NearlyIn cannot be asked it returns false and passes the error to onError (default console.error). attemptId makes a retry within 24 hours get the first answer; use the account's id. Recipes for Clerk, Supabase Auth and Auth.js: nearlyin.com/docs/auth/clerk.

Configuration

Set NEARLYIN_SECRET_KEY in your server's environment; that is all. NEARLYIN_URL is only needed when NearlyIn runs somewhere else than https://nearlyin.com. You can also pass secretKey and serviceUrl to each call. The secret key must never reach the browser: the helpers refuse to run there.

nearlyin/server also manages the list: listEntries, getEntry, inviteEntry, inviteNext, reinviteEntry, moveUpEntry and deleteEntry.

Webhooks

import { verifyWebhook } from "nearlyin/webhooks";

const event = await verifyWebhook(rawBody, request.headers.get("NearlyIn-Signature"), process.env.NEARLYIN_WEBHOOK_SECRET!);
// event.type: "entry.created" | "entry.confirmed" | "entry.invited" | "entry.redeemed" | ...

It uses the Web Crypto API and runs in Node 18+, Deno, Bun and edge runtimes. Pass the body exactly as it arrived, before any JSON parsing.

Without React

examples/form.html in this package is a plain HTML form. Or use the script from the dashboard; it needs no package at all:

<script src="https://nearlyin.com/embed.js" data-key="ni_pk_live_…" async></script>

In React or Next.js, which move script tags into <head>, mark the place with a placeholder and load the script once, anywhere:

<div data-nearlyin="ni_pk_live_…" data-variant="compact" data-layout="pill"></div>
<script src="https://nearlyin.com/embed.js" async></script>

The script takes data-layout, data-radius and data-hide-label like the props above. For a CSP, it needs script-src and frame-src https://nearlyin.com (and connect-src, for its own button in your colour).