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

@uninspired/auth-client

v1.0.16

Published

Auth client for Uninspired Studio Products

Downloads

384

Readme

@uninspired/auth-client

Client SDK for integrating Uninspired Studio authentication, purchases, and checkout into product apps (e.g. Momentum, Unpinned).

Works in any JavaScript environment. Includes a React provider and hook for apps that use React.

Installation

bun add @uninspired/auth-client
# or
npm install @uninspired/auth-client

Peer dependencies

For React apps, also install:

bun add react react-dom

@posthog/react is an optional peer dependency — the AuthProvider automatically identifies users when a PostHog instance is available in the React tree.

What it provides

| Feature | Description | |---|---| | Session management | Fetch the current user session (including anonymous sessions) | | Anonymous sign-in | Automatically sign in visitors as anonymous users | | Sign out | End the current session | | Purchase data | Fetch Paddle transactions and Stripe/Paddle subscriptions | | Access checks | isPurchased() and isSubscribed() helpers for gating features | | Login URL builder | Generate a link to the accounts page with a post-login redirect back to your app | | Checkout URL builder | Generate a link to the hosted checkout flow | | Newsletter | Subscribe/unsubscribe from mailing lists | | PostHog integration | Auto-identify users in PostHog when authenticated |

Authentication methods (magic link, email OTP, passkey) are handled on the accounts page — this client manages sessions and purchase data, not the login UI itself.

Quick start (React)

import { AuthProvider, useAuth } from "@uninspired/auth-client";

function App() {
  return (
    <AuthProvider
      baseUrl="https://auth.uninspired.app"
      frontendUrl="https://uninspired.app"
      mailingListPublicKey="your-public-key"
    >
      <MyApp />
    </AuthProvider>
  );
}

function MyApp() {
  const { isLoggedIn, session, isPurchased, getLoginUrl, signOut } = useAuth();

  if (!isLoggedIn) {
    return (
      <a href={getLoginUrl({ redirectUrl: window.location.href, appName: "My App" })}>
        Log in
      </a>
    );
  }

  const hasPro = isPurchased(["pri_01234567890"]);

  return (
    <div>
      <p>Hello, {session?.user.email ?? "guest"}</p>
      {hasPro ? <ProFeature /> : <UpgradePrompt />}
      <button onClick={() => signOut()}>Sign out</button>
    </div>
  );
}

AuthClient (vanilla / SSR)

Use AuthClient directly when you are not in a React tree, or in server-side rendering.

import { AuthClient } from "@uninspired/auth-client";

const client = new AuthClient(
  "https://auth.uninspired.app",   // API URL
  "https://uninspired.app",        // Accounts frontend URL
  request.headers.get("cookie"),   // optional: forward cookies for SSR
  "your-mailing-list-public-key",  // optional
);

const session = await client.getSession();
const purchases = await client.getPurchases();

Constructor

new AuthClient(apiUrl, frontendUrl, cookie?, mailingListPublicKey?)

| Parameter | Description | |---|---| | apiUrl | Auth API base URL (e.g. https://auth.uninspired.app) | | frontendUrl | Accounts frontend URL (e.g. https://uninspired.app) | | cookie | Optional cookie header string for server-side session lookup | | mailingListPublicKey | Optional public key for mailing list endpoints |

All API requests use credentials: "include" in the browser, so session cookies are sent automatically on the same root domain.

Methods

Session

const session = await client.getSession();
// Returns Session | null

await client.signInAnonymously();
// Creates an anonymous session (done automatically by AuthProvider)

await client.signOut(onSuccess?);
// Signs out the current user

Purchases

const purchases = await client.getPurchases();
// Returns UserPurchases | null

UserPurchases contains:

{
  paddle: {
    customerId?: string;
    subscriptions: Array<{ id, status, items: [{ priceId, productId }] }>;
    transactions: Array<{ id, items: string[], adjustments: [...] }>;
  };
  stripe: Array<{ id, status, items: string[] }>;
  mailingList: { subscribed: boolean };
}

URL builders

// Link to the accounts login page, redirect back after auth
const loginUrl = client.getLoginUrl({
  redirectUrl: "https://myapp.uninspired.app/dashboard",
  appName: "My App",  // optional, shown on the login page
});

// Link to the hosted checkout flow
const checkoutUrl = client.getCheckoutUrl({
  priceId: "pri_01234567890",
  productId: "pro_01234567890",
  discountCode: "SAVE20",       // optional
  successUrl: "https://myapp.uninspired.app/welcome",  // optional
  quantity: 1,                  // optional, defaults to 1
});

Newsletter

await client.newsletterSubscribe("[email protected]", "my-app-group", "https://callback.url");
await client.newsletterUnsubscribe("[email protected]");

AuthProvider and useAuth (React)

AuthProvider props

| Prop | Type | Description | |---|---|---| | baseUrl | string | Auth API URL | | frontendUrl | string | Accounts frontend URL | | mailingListPublicKey | string? | Public key for mailing list API | | initialSession | Session \| null? | Pre-fetched session for SSR | | initialPurchases | UserPurchases \| null? | Pre-fetched purchases for SSR | | authClient | AuthClient? | Custom client instance | | queryClient | QueryClient? | Custom TanStack Query client |

The provider automatically:

  1. Revalidates the session on mount via get-session (with 1-minute stale time; SSR initialSession is shown immediately while revalidating)
  2. Signs in anonymously only after revalidation confirms no session exists
  3. Fetches purchases when a session is available
  4. Identifies the user in PostHog when authenticated

useAuth() return value

| Property | Type | Description | |---|---|---| | session | Session \| null | Current session | | isLoggedIn | boolean | true if user is authenticated (not anonymous) | | isSessionFetching | boolean | Session query loading state | | refetchSession | () => Promise<void> | Re-fetch session | | purchases | UserPurchases \| null | User's purchase data | | isPurchasesFetching | boolean | Purchases query loading state | | refetchPurchases | () => Promise<void> | Re-fetch purchases | | signOut | (onSuccess?) => Promise<void> | Sign out (resets PostHog) | | getLoginUrl | AuthClient["getLoginUrl"] | Build login URL | | getCheckoutUrl | AuthClient["getCheckoutUrl"] | Build checkout URL | | isPurchased | (priceIds: string[]) => boolean | Check one-time purchase | | isSubscribed | (priceIds: string[], productId: string) => boolean | Check active subscription | | newsletterSubscribe | AuthClient["newsletterSubscribe"] | Subscribe to newsletter | | newsletterUnsubscribe | AuthClient["newsletterUnsubscribe"] | Unsubscribe from newsletter |

Access checks

const { isPurchased, isSubscribed } = useAuth();

// One-time purchase: true if user bought any of these price IDs (and hasn't been refunded)
isPurchased(["pri_lifetime", "pri_bundle"]);

// Subscription: true if user has an active Paddle or Stripe subscription
isSubscribed(["pri_monthly", "pri_yearly"], "pro_product_id");

Server-side rendering

For SSR frameworks, fetch session and purchases on the server and pass them as initial data:

// server
import { AuthClient } from "@uninspired/auth-client";

const client = new AuthClient(
  process.env.AUTH_API_URL,
  process.env.ACCOUNTS_FRONTEND_URL,
  request.headers.get("cookie"),
);

const [session, purchases] = await Promise.all([
  client.getSession(),
  client.getPurchases(),
]);

// render
<AuthProvider
  baseUrl={process.env.AUTH_API_URL}
  frontendUrl={process.env.ACCOUNTS_FRONTEND_URL}
  initialSession={session}
  initialPurchases={purchases}
>
  {children}
</AuthProvider>

Forward the request's Cookie header to the constructor so the API can resolve the session server-side.

Cross-subdomain cookies

Sessions use cross-subdomain cookies scoped to the Uninspired Studio root domain (e.g. .uninspired.app). Your product app must be hosted on a subdomain of the same root domain for cookies to be shared automatically.

Make sure your app's origin is listed in the auth API's FRONTEND_URLS configuration.

Types

The package re-exports shared types:

import type { Session, UserPurchases } from "@uninspired/auth-client";

Building from source

This package is part of the US Auth monorepo. To build locally:

cd packages/auth-client
bun run build

Output goes to dist/.

Environment URLs

| Environment | API | Accounts frontend | |---|---|---| | Production | https://auth.uninspired.app | https://uninspired.app | | Development | https://auth.dev.uninspired.app | https://dev.uninspired.app | | Local | http://localhost:3000 | http://localhost:5173 |