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

@sqlos/headless

v11.1.1

Published

SqlOS headless AuthPage state machine. Drives identify, password, OTP, MFA, and consent until an authorization code; it is not an OAuth/OIDC client.

Readme

@sqlos/headless

Typed state machine for a product-owned login UI on top of SqlOS AuthPage.

Your app draws the screens. This package holds the current view, opaque flow tokens, and field errors; posts each user action to SqlOS; and stops when SqlOS returns an authorization code (or an external provider URL). Pin the npm version to the same SqlOS NuGet release.

It is not a general OAuth/OIDC client. Do not use it to call /token, store refresh tokens, or replace Auth.js, angular-oauth2-oidc, expo-auth-session, or ASP.NET Core AddOpenIdConnect. Those libraries still own PKCE startup, callback handling, and token exchange.

Install

npm install @sqlos/headless

In this repository, examples resolve the package from file:../../packages/headless so local and CI installs never need npmjs.com.

Web app with a custom login page

Your OIDC library starts /authorize with S256 PKCE. SqlOS redirects the browser to your page (for example /auth/authorize?request=…). This package resumes that saved request, then you render a loop over the current view until SqlOS is ready to leave your page.

import { createHeadlessFlow } from "@sqlos/headless";

const flow = createHeadlessFlow({
  issuer: "https://id.example.com/sqlos/auth",
  clientId: "acme-app",
  redirectUri: "https://app.example.com/api/auth/callback/sqlos",
  credentials: "include",
});

await flow.resume(window.location);

flow.subscribe(() => {
  if (flow.status === "redirect" && flow.redirectUrl) {
    window.location.assign(flow.redirectUrl);
    return;
  }

  switch (flow.viewModel?.view) {
    case "login":
      // email form → flow.identify({ email })
      break;
    case "password":
      // password form → flow.password.login({ password })
      break;
    case "organization":
    case "mfa":
    case "consent":
      // render the returned view model
      break;
    default:
      break;
  }
});

React (and React Native) use the same snapshots so memoized children update without mirroring flow state into useState:

import { useHeadlessAuth } from "@sqlos/headless/react";

const { flow, status, view, viewModel, error, fieldErrors, redirectUrl } =
  useHeadlessAuth({
    issuer,
    clientId,
    redirectUri,
    credentials: "include",
  });

// status === "loading" while an action runs
// error / fieldErrors are the only error channels for normal failures
// when status === "redirect", window.location.assign(redirectUrl)

Native app (React Native / Expo)

On native there is no browser redirect into your page. Call flow.start() so SqlOS creates the authorization request, then render the same view loop in-app. When the flow reaches an authorization code, hand that code to your OIDC library for /token — this package never calls /token.

import { exchangeCodeAsync } from "expo-auth-session";
import * as Crypto from "expo-crypto";
import { createHeadlessFlow, createPkceGenerator } from "@sqlos/headless";

// Hermes has no Web Crypto `subtle`: inject expo-crypto primitives. The
// package still owns the verifier format (43-char base64url) and S256.
const generatePkce = createPkceGenerator({
  randomBytes: (size) => Crypto.getRandomBytesAsync(size),
  sha256: async (data) =>
    new Uint8Array(await Crypto.digest(Crypto.CryptoDigestAlgorithm.SHA256, data)),
});

const flow = createHeadlessFlow({
  issuer: "https://id.example.com/sqlos/auth",
  clientId: "example-expo",
  redirectUri: "sqlos-expo://auth-callback",
  generatePkce,
});

await flow.start({
  scope: "openid profile email offline_access",
  view: "login",
});

// Render switch (flow.viewModel.view) → identify / password / MFA / …

if (flow.status === "redirect" && flow.authorization) {
  const tokens = await exchangeCodeAsync(
    {
      clientId: "example-expo",
      code: flow.authorization.code,
      redirectUri: flow.authorization.redirectUri,
      extraParams: {
        code_verifier: flow.authorization.codeVerifier ?? "",
      },
    },
    { tokenEndpoint: `${issuer}/token` },
  );
  // Store tokens in your app session — not in this package.
}

If status === "redirect" and authorization is null, SqlOS returned an external provider URL in redirectUrl. Open that URL in a system browser; do not treat it as a code callback.

Errors and status

| status | Meaning | | --- | --- | | idle | No request loaded yet | | loading | An action is in flight | | view | Render viewModel.view | | redirect | Leave via redirectUrl (and read authorization when a code is present) | | error | Read error and fieldErrors |

Server and validation failures do not reject. Actions resolve with the new status, and error / fieldErrors update on the flow. You do not need try/catch or local error state for the normal path.

Programmer mistakes reject with a HeadlessProgrammerError subclass and also set status === "error": HeadlessFlowBusyError (a second action while one is in flight — disable inputs while status === "loading"), HeadlessFlowNotLoadedError (action before resume/start, or a view without the token the action needs), HeadlessApiPathMismatchError, and HeadlessTokenEndpointError. Fix the integration when those appear. resume and start coalesce an identical in-flight call, so React StrictMode's double effect needs no guard.

Subscribe with flow.subscribe(listener) outside React, or use useHeadlessAuth inside React. Inline fetch / generatePkce options do not rebuild the hook's flow; only the identity options (issuer, client, redirect URI, base path, credentials) do.

Beyond the named actions

  • credentialEnabled(viewModel.settings, "email_otp") applies the hosted AuthPage rule (enabled type and runtime configured) so every custom UI shows the same sign-in methods.
  • flow.submit(path, body) posts to a headless route the SDK does not name yet, through the same status and token bookkeeping, and applies the returned view model or action result.
  • flow.passwordReset carries the password.forgot() result (maskedEmail, expiresAt, nextAllowedSendAt) for resend-cooldown UX.
  • Render a fallback for HeadlessView values your UI does not draw; the examples send those users to hosted AuthPage.

Docs

What this package does not do

  • Token exchange, refresh, ID-token validation, logout, or device-code polling
  • Admin APIs, FGA, or the dashboard
  • Writing tokens to localStorage