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

@idhub/identity-adapter-nextjs

v0.1.0

Published

Next.js App Router adapter for @idhub/identity-core: Edge-safe middleware that guarantees the canonical anonymous id cookie, plus an <IdentityProvider> client component and useIdentity() hook.

Readme

@idhub/identity-adapter-nextjs

Next.js App Router adapter for @idhub/identity-core. Thin by design: it owns no vendor knowledge and no cookie logic — every id is created and persisted by identity-core.

Three entry points, deliberately separate so a Server Component or Edge middleware never pulls React (or a "use client" boundary) into its bundle:

| Import | Runtime | Purpose | | --- | --- | --- | | @idhub/identity-adapter-nextjs/middleware | Edge | Guarantee the anonymous-id cookie on every request | | @idhub/identity-adapter-nextjs/server | Server Components / Route Handlers | Read the anonymous id | | @idhub/identity-adapter-nextjs | Client Components | <IdentityProvider> + useIdentity() |

1. Middleware

Apps with no middleware of their own:

// middleware.ts
import { identityMiddleware } from '@idhub/identity-adapter-nextjs/middleware'

export const middleware = identityMiddleware()
export const config = { matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'] }

Apps that already have middleware logic compose with withIdentity, which returns the pieces instead of wrapping your handler — so you keep control flow (redirects, rewrites, 401s) and still get the cookie guarantee on every path:

// middleware.ts
import { withIdentity, applyAnonymousIdCookie } from '@idhub/identity-adapter-nextjs/middleware'
import { NextResponse, type NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const { response, anonymousId, setCookieHeader } = withIdentity(request)

  if (!isAuthorized(request)) {
    // Your own response still gets the cookie.
    return applyAnonymousIdCookie(NextResponse.redirect(new URL('/login', request.url)), setCookieHeader)
  }

  response.headers.set('x-anon-id', anonymousId)
  return response
}

withIdentity also writes the id back onto the incoming request when it had to generate one. That is what makes the id visible to Server Components on the first request, rather than only from the second page load onwards.

Everything in this entry point's import graph is Edge-safe: only Request/Response/Headers and crypto.randomUUID, via identity-core.

2. Provider (App Router layout.tsx)

// app/layout.tsx — a Server Component
import { getAnonymousIdFromCookies } from '@idhub/identity-adapter-nextjs/server'
import { cookies } from 'next/headers'
import { Providers } from './providers'

export default async function RootLayout({ children }: { children: React.ReactNode }) {
  const anonymousId = getAnonymousIdFromCookies(await cookies())
  return (
    <html lang="en">
      <body>
        <Providers initialAnonymousId={anonymousId}>{children}</Providers>
      </body>
    </html>
  )
}
// app/providers.tsx
'use client'
import { IdentityProvider } from '@idhub/identity-adapter-nextjs'

export function Providers({ initialAnonymousId, children }) {
  return (
    <IdentityProvider providers={[segment(), launchDarkly()]} initialAnonymousId={initialAnonymousId}>
      {children}
    </IdentityProvider>
  )
}

Why initialAnonymousId is an explicit prop from the server

<IdentityProvider> is a Client Component, but Next.js still server-renders it. On the server there is no document, so deriving the initial state from document.cookie would fall back to a freshly generated id that disagrees with the one the browser actually holds — a hydration mismatch on every cold load. Passing the server-read value down makes the SSR pass and the hydration pass render the same id. After hydration the IdentityClient (which reads the cookie) becomes the source of truth.

The IdentityClient itself is constructed once, in an effect, browser-side only — never during render, because constructing it fans onAnonymous out to every vendor SDK.

3. useIdentity()

'use client'
import { useIdentity } from '@idhub/identity-adapter-nextjs'

export function LoginButton() {
  const { state, identify, reset, track, page } = useIdentity()
  return <button onClick={() => identify('user-123', { plan: 'pro' })}>{state.status}</button>
}

Throws a descriptive error outside <IdentityProvider> rather than returning a silent no-op, because a missing provider means every vendor call is being dropped on the floor.

The vendor-facing IdentityProvider interface is not re-exported here — this package already exports a React component by that name. Import it from @idhub/identity-core.

Testing

test-app/ is a throwaway App Router app (one page, a login button, a logout button) driven by the Playwright suite in e2e/. It uses a test-double provider that records every fan-out call on window.__identityCalls, so the specs can assert what the vendors would have been handed.

pnpm --filter @idhub/identity-adapter-nextjs test:e2e

Covers: cold load with no cookie → Set-Cookie on the response; login → onIdentify with the right userId and the canonical anonymous id; logout → a new anonymous id that is never the pre-logout one.