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

@nominalso/vibe-auth

v0.4.0

Published

Silent Supabase OIDC login for Nominal Vibe Apps — a configurable, cross-document-safe auth gate (Web-Lock-serialised silent SSO, identity-switch rebinding, popup fallback) that replaces a hand-copied per-app implementation.

Readme

@nominalso/vibe-auth

Silent Supabase OIDC login for Nominal Vibe Apps — a configurable, cross-document-safe auth gate that replaces a hand-copied per-app implementation of the silent-supabase-oidc-login skill. If your app authenticates through Supabase federated with the Nominal host's IdP (Descope), this package IS that flow — written once, fixed once, and configurable per app.

For AI agents / Lovable: see AGENTS.md for the condensed integration guide (including the SSR root-wiring recipe). To replace a hand-written silentAuth.ts/AuthGate.tsx pair, follow the silent-supabase-oidc-login skill Step 1b.

Why this exists

Six generated apps each carried a hand-copied version of this login flow. Five rounds of bug fixes had to be re-applied per app, and the copies drifted: one app grew a React hydration crash in its root route, three ended up mounting bridge providers inside the auth callback document, and all of them still carried a production bug where a stale session's failed boot-time refresh briefly flashed the sign-in screen. This package is that logic, fixed and written once.

Install

npm install @nominalso/vibe-auth

Peer dependencies: react >=18, @supabase/supabase-js ^2.

Quickstart

// src/lib/auth.ts — called synchronously, at module scope, imported eagerly.
import { createVibeAuth } from '@nominalso/vibe-auth'
import { supabase } from './supabaseClient' // YOUR existing client — this package never creates one

export const auth = createVibeAuth({
  supabase,
  provider: 'custom:supabase-fedapp', // from your Supabase Auth → Providers config
})
// the callback route — mount ONLY this, ungated, at the callback path
// (default '/silent-callback'; see AGENTS.md for the SSR-safe recipe)
import { auth } from '@/lib/auth'
export default auth.SilentCallback
// wrap the whole app — it never renders until authenticated
import { auth } from '@/lib/auth'

function Root() {
  return (
    <auth.AuthGate>
      <App />
    </auth.AuthGate>
  )
}
// Start the Nominal host handshake at module scope, before React mounts.
import { VibeAppBridge, type ContextPayload } from '@nominalso/vibe-bridge'
import { auth } from '@/lib/auth'

export const bridge = new VibeAppBridge()

export const { hostContext, hostOutcome, getHostContext, subscribeHostContext } =
  auth.wireVibeApp<ContextPayload>(bridge)

One call does the whole handshake, in the one correct order: context subscriber and host auth registered before connect(), the host principal seeded before context is published, the handshake skipped in the callback document, and null rather than a rejection when there is no host. Pass onContextChange, onDataReset and onSubrouteRequest as options in the same call.

Telling "not embedded" from "the host broke". hostContext resolves null for both, which is why apps either showed an error banner on every standalone dev load or showed none at all. hostOutcome carries the distinction:

const { hostContext, hostOutcome } = auth.wireVibeApp<ContextPayload>(bridge)

const outcome = await hostOutcome // never rejects, settles with hostContext
// { kind: 'connected' }
// { kind: 'standalone' }          — nothing was ever going to answer; expected
// { kind: 'failed', error }       — embedded, and the host stayed silent

See AGENTS.md for SSR root wiring and the full ordering rules. Timeouts live on VibeAuthTimeouts in the package .d.ts.

Why a client you own, not one this package creates

Your client.ts is often Lovable-generated (marked "do not edit"), carries your generated Database types, and may have its own storage adapter (e.g. for Lovable preview brokering). This package only requires it: at createVibeAuth(), it best-effort-checks auth.flowType === 'pkce' and logs a loud console.error if it isn't — PKCE is a security control, not a preference (the .d.ts on VibeAuthConfig explains why).

What you get

  • ensureSession() / rebindSession({ userId, tenant }) — the cross-document-safe core (Web Lock serialised, terminal-capped, sibling-adopting). Most apps never call these directly; the gate and wireVibeApp do.
  • AuthGate / DefaultSignInScreen / SilentCallback — the three React pieces. Override signInScreen/loader props on AuthGate for branding.
  • wireVibeApp(bridge, options?) — the Nominal-host integration in one call (handshake, host context store, logout and identity/tenant switch). Call it at module scope from a parent of AuthGate. The pre-0.2.3 hand-wiring (wireHostAuth / seedLastUserId) was removed in 0.4.0; an app still calling it fails to typecheck until it moves to wireVibeApp.
  • Fully configurable timeouts (VibeAuthTimeouts in the .d.ts) — every value defaults to what shipped after this flow's production incidents.

Security boundary

signOut() calls made by this package (on host logout, on a failed identity-switch rebind) are client-side, best-effort UX: they stop rendering the app and drop the local session, but a persisted Supabase access token stays technically valid until it expires, and only this browser is affected. Enforced logout must happen server-side — OIDC back-channel logout revoking the Supabase refresh tokens (Supabase Admin API, per project). That back-channel receiver is infrastructure outside this package.