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

@nyuro/app-switcher

v0.3.0

Published

The shared Apps switcher and not-entitled view (spec A4 §6): React, no framework CSS, themed by --nyuro-switcher-* custom properties.

Readme

@nyuro/app-switcher

The shared Apps switcher and the not-entitled view (spec A4 §6). React 18 or 19, no framework CSS: one plain stylesheet themed by --nyuro-switcher-* custom properties. Both components render from props only; they never call an API.

import { AppSwitcher, NotEntitledView, type SwitcherProduct } from '@nyuro/app-switcher'
import '@nyuro/app-switcher/styles.css'

Product data

Components take products as SwitcherProduct values:

interface SwitcherProduct {
    slug: string                    // as in the token's `products` claim
    name: string                    // "AI App Builder"
    url: string                     // where the app opens
    pricingUrl: string              // https://nyuro.ai/pricing?product=<slug>
    status: 'live' | 'early_access' | 'coming_later'
    icon: 'router' | 'flow' | 'employees' | 'biab'
}

Apps map their @nyuro/products catalog entries to SwitcherProduct (one small function in the app). This package does not depend on the catalog, so a catalog release never forces a switcher release.

<AppSwitcher>

<AppSwitcher current="router" owned={claims.products} products={switcherProducts} />
<AppSwitcher current="router" owned={claims.products} products={switcherProducts} variant="compact" />
  • owned is the app's own verified products claim. Owned apps are links under "Your apps"; the current one has aria-current="page", and one on another origin shows an "opens " mark.
  • "Add more" lists the rest: Live shows Add and Early access shows Early access, both linking to pricingUrl; Coming later shows Later and is not a link.
  • variant="sidebar" (default) is the desktop side nav (40 px rows); variant="compact" is the phone menu drawer (48 px rows). It renders <nav aria-label="Apps">; tab order follows the list.

<NotEntitledView>

Render it inside the page's <main> when /exchange?aud=<product> refuses. It holds the <h1>.

<NotEntitledView
    product="flow"
    reason={refusal.code}                 // not_entitled | org_required | no_seat | entitlements_unavailable
    canActivate={refusal.activate}        // from the not_entitled body
    isOwner={member.role === 'owner'}
    owned={claims.products}
    products={switcherProducts}
    orgName={org.name}
    userEmail={user.email}
    onActivate={startFree}                // or activateAction="<form POST target>"
/>

| Reason / status | Primary action | Also | |---|---|---| | not_entitled, Live, owner with canActivate | Start free | See plans | | not_entitled, Early access, owner | Request early access (Start free once granted) | See plans | | not_entitled as non-owner, Coming later, org_required, no_seat | none | See plans | | entitlements_unavailable | Try again (onRetry, else reloads the product URL) | nothing else: never an upsell |

Every case shows the "Your apps" row and, with orgName, "Only an owner of can add apps" (owner only, decision F2).

Theming

Override any --nyuro-switcher-* property on an ancestor. Fonts are inherited from the host app. Public and auth pages that use the "Mix A" display type set:

.auth-page {
    --nyuro-switcher-display-font: 'Syncopate', sans-serif;
    --nyuro-switcher-display-transform: uppercase;
    --nyuro-switcher-display-tracking: 0.04em;
    --nyuro-switcher-button-font: 'Michroma', sans-serif;
    --nyuro-switcher-button-transform: uppercase;
    --nyuro-switcher-button-tracking: 0.14em;
}