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

@spacefast/auth

v0.8.0

Published

Verify Spacefast visitor tokens offline and keep short-lived credentials fresh.

Readme

@spacefast/auth

Auth primitives for apps running on Spacefast. Two entry points, one contract:

  • @spacefast/auth/server — verify a visitor token offline and get back the identity contract every Spacefast surface shares.
  • @spacefast/auth/tokens — keep any short-lived credential fresh without writing refresh code again.

The library verifies and manages. It never mints — identity always comes from the platform.

Verify on the server

import { createVerifier } from "@spacefast/auth/server";

// The full relying-party profile is mandatory. A signing key alone only says
// who signed a token — issuer, audience, host, purpose, and claim version are
// what make it *yours*. The JWKS is data you already have, never a URL: no
// network round-trip hides in your request path.
const verify = createVerifier({
  jwks, // { keys: [...] } — Ed25519 public keys
  issuer: "spacefast-api",
  audience: "spc_1234", // your Space
  host: "docs.example.com", // the host this token must be bound to
  purpose: "handoff", // tokens minted for any other lane never pass
  claimVersion: 1,
});

const auth = await verify(request); // AuthContext | null

// AuthContext — the shared contract:
// { principal: "account:usr_8m2p" | "person:per_…" | "guest:local",
//   authorities: ["member:usr_8m2p"],
//   capabilities: ["page.view", "comments.write"],
//   isGuest, isAuthenticated, displayName, email?, emailVerified?, picture? }

verify accepts a Request (it reads Authorization: Bearer or X-SF-Authorization) or a raw token string.

The four states

null is fine for the main path — anything that isn't a verified identity is a guest. When you need to know why, ask for the outcome:

import { guestContext } from "@spacefast/auth/server";

const outcome = await verify.outcome(request);
// { state: "verified", auth }        the token proves an identity
// { state: "no-token" }              nothing to verify
// { state: "invalid-token", reason } provably not acceptable here
// { state: "verifier-unavailable", reason }
//                                    this process can't render a verdict —
//                                    e.g. a key id your JWKS doesn't know yet

const auth = outcome.state === "verified" ? outcome.auth : guestContext();

Fail open to guest: every non-verified state serves the guest experience. The states exist so your logs can tell a forged token from a stale key deployment. An unknown kid is deliberately unavailable, not invalid — during key rotation the honest answer is "I can't know", never "forged".

Defaults worth knowing: 5 seconds of clock skew on exp/nbf; azp is checked only when you pass authorizedParties; a malformed claim — even an optional one — makes the whole token invalid. Bad data fails loud, not soft.

Keep a credential fresh

import { createTokenManager, TokenRefusedError } from "@spacefast/auth/tokens";

const tickets = createTokenManager({
  mint: async () => {
    const response = await fetch("/__spacefast/collab/ticket", { method: "POST" });
    if (response.status === 403) throw new TokenRefusedError("forbidden");
    if (!response.ok) throw new Error(`ticket ${response.status}`); // transient
    const { data } = await response.json();
    return { token: data.token, expiresAt: data.expiresAt };
  },
});

await tickets.current(); // mints once, then stays warm
tickets.onToken((token) => reconnect(token));
tickets.onRefusal((code) => teardown(code)); // "no" is terminal, not a retry
tickets.stop(); // cancels everything, leaks nothing

What the manager does for you:

  • Proactive refresh at 80% of each token's lifetime — callers never pay the mint latency on the hot path.
  • Jittered exponential backoff when minting fails transiently, while any unexpired token keeps being served.
  • Offline ≠ signed out. A caller with no live token during an outage gets a TokenOfflineError, never a null that reads as "no access". Refusals throw TokenRefusedError with the code the minter gave.
  • One mint at a time. Concurrent current() calls share the in-flight request — bursts don't stampede your token endpoint.