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

@alphinex/auth

v1.0.1

Published

Auth state/session primitives: AuthProvider, useAuth, route guards.

Readme

@alphinex/auth

Backend-agnostic auth state and session primitives: an AuthProvider/useAuth context driven by a pluggable AuthAdapter, a RequireAuth route guard, and swappable session storage strategies. This package doesn't know about Sanctum, CSRF, or bearer tokens — that lives in @alphinex/api-laravel (or any backend adapter you write); auth just needs an AuthAdapter.

AuthProvider / useAuth

AuthProvider takes an adapter: AuthAdapter<TUser, TCredentials> — an object with fetchSession(), login(credentials), and logout() — and calls fetchSession() once on mount to resolve the initial status ("idle""loading""authenticated"/"unauthenticated"). useAuth() reads status, user, error, and exposes login, logout, and refresh:

import { AuthProvider, useAuth, type AuthAdapter } from "@alphinex/auth";
import { ApiError } from "@alphinex/api";

interface Credentials {
  email: string;
  password: string;
}

const authAdapter: AuthAdapter<AppUser, Credentials> = {
  fetchSession: async () => {
    try {
      return await apiClient.get<AppUser>("/user");
    } catch (error) {
      if (error instanceof ApiError && error.status === 401) return null;
      throw error;
    }
  },
  login: (credentials) => apiClient.post<AppUser>("/login", credentials),
  logout: () => apiClient.post("/logout"),
};

function Root() {
  return (
    <AuthProvider adapter={authAdapter}>
      <App />
    </AuthProvider>
  );
}

function LoginForm() {
  const { login, error } = useAuth<AppUser, Credentials>();
  const fieldErrors = error instanceof ApiError ? error.fieldErrors : undefined;

  async function handleSubmit(email: string, password: string) {
    await login({ email, password });
  }
  // ...
}

Pass storage to persist the last-known user across reloads (see session storage below), and subscribeSessionExpired to wire a backend-emitted session-expiry signal — e.g. @alphinex/api-laravel's events.on("session-expired", ...) — to an immediate local sign-out, without this package depending on api-laravel directly:

import { createLaravelApiClient } from "@alphinex/api-laravel";

const { client, events } = createLaravelApiClient({ baseUrl: "https://api.example.com" });

<AuthProvider
  adapter={authAdapter}
  subscribeSessionExpired={(handler) => events.on("session-expired", () => handler())}
>
  <App />
</AuthProvider>;

useAuth() throws if called outside an AuthProvider.

RequireAuth

A route guard that renders children only once useAuth() resolves to "authenticated". Renders loading while status is "idle"/"loading", fallback while "unauthenticated" (both default to nothing), and calls onUnauthenticated as a side effect when the user becomes unauthenticated — kept as a callback rather than a hard router dependency so you can navigate("/login") with whichever router you use:

import { RequireAuth } from "@alphinex/auth";
import { useNavigate } from "react-router-dom";

function ProtectedRoute() {
  const navigate = useNavigate();
  return (
    <RequireAuth
      loading={<p>Checking session…</p>}
      fallback={<LoginForm />}
      onUnauthenticated={() => navigate("/login")}
    >
      <Dashboard />
    </RequireAuth>
  );
}

Session storage (createInMemorySessionStorage, createLocalStorageSessionStorage)

AuthProvider's storage option implements the SessionStorage<TUser> contract (getUser()/setUser()). It defaults to createInMemorySessionStorage() — nothing persists across a reload. Use createLocalStorageSessionStorage(key?) to avoid an auth-status flash on reload; it's purely an optimistic-UI cache, fetchSession() remains the source of truth:

import { AuthProvider, createLocalStorageSessionStorage } from "@alphinex/auth";

<AuthProvider adapter={authAdapter} storage={createLocalStorageSessionStorage("myapp.auth.user")}>
  <App />
</AuthProvider>;

AuthAdapter / AuthStatus

The contract the whole package is built around. AuthStatus is "idle" | "loading" | "authenticated" | "unauthenticated". AuthAdapter<TUser, TCredentials> requires fetchSession(): Promise<TUser | null>, login(credentials): Promise<TUser>, and logout(): Promise<void> — implement it against whatever backend you use (Sanctum via @alphinex/api-laravel, a different API, or a mock for tests).

See documentation/ARCHITECTURE.md for the full package contract, dependency rules, and roadmap placement.