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

@digibuffer/cone-auth

v0.1.8

Published

ConeID OAuth flow utilities and React components for Cone ecosystem apps.

Readme

@digibuffer/cone-auth

ConeID OAuth flow utilities and React components for Cone ecosystem apps (StorageCone, ConeMotion, ConeFrame, etc.).

Handles the common problem where email verification in a new tab causes a PKCE mismatch on the original tab, resulting in an AccessDenied or OAuthCallbackError. The package auto-retries the sign-in silently so users never see the error.


Installation

npm install @digibuffer/cone-auth

Peer dependencies — already in your app, no extra install needed:

  • next-auth (any version)
  • react ^18 or ^19

Setup (3 steps)

1. Before calling signIn() — mark the flow as started

Call startConeOAuthFlow() right before signIn() on your login and signup pages.

// app/(auth)/login/page.tsx
import { startConeOAuthFlow } from "@digibuffer/cone-auth/ui"
import { signIn } from "next-auth/react"

function handleSignIn() {
  startConeOAuthFlow()   // ← sets a timestamp flag in sessionStorage
  signIn("coneid", { callbackUrl: "/dashboard" })
}
// app/(auth)/signup/page.tsx
import { startConeOAuthFlow } from "@digibuffer/cone-auth/ui"
import { signIn } from "next-auth/react"

function handleSignUp() {
  startConeOAuthFlow()
  signIn("coneid", { callbackUrl: "/dashboard" }, { prompt: "create" })
}

2. On the login page — use the retry hook

useConeOAuthRetry automatically retries sign-in (up to 2 times) when the user lands back on the login page mid-flow — whether there's an error param in the URL or not.

// app/(auth)/login/page.tsx
"use client"

import { useSearchParams } from "next/navigation"
import { signIn } from "next-auth/react"
import { useConeOAuthRetry, startConeOAuthFlow } from "@digibuffer/cone-auth/ui"

function LoginPage() {
  const searchParams = useSearchParams()
  const callbackUrl = searchParams.get("callbackUrl") || "/dashboard"
  const errorParam = searchParams.get("error")

  const { isRetrying, showRetryBanner, retry } = useConeOAuthRetry({
    providerId: "coneid",   // your next-auth provider id
    callbackUrl,
    errorParam,             // pass the raw error from the URL
  })

  const handleSignIn = () => {
    startConeOAuthFlow()
    signIn("coneid", { callbackUrl })
  }

  // Show spinner while auto-retry is in flight
  if (isRetrying) {
    return <Spinner />
  }

  return (
    <div>
      {/* Show a banner when retries are exhausted */}
      {showRetryBanner && (
        <p>Sign-in session expired. Please try again.</p>
      )}

      <button onClick={showRetryBanner ? retry : handleSignIn}>
        Sign in with Cone ID
      </button>
    </div>
  )
}

Hook options

| Option | Type | Default | Description | |---|---|---|---| | providerId | string | "coneid" | The next-auth provider id | | callbackUrl | string | "/dashboard" | Where to redirect after sign-in | | errorParam | string \| null | — | Value of ?error= from the URL |

Hook return values

| Value | Type | Description | |---|---|---| | isRetrying | boolean | true while auto-retry is in flight — show a spinner | | showRetryBanner | boolean | true when retries are exhausted — show a manual retry UI | | retry | () => void | Call this when the user manually clicks "Try again" |


3. In the authenticated area — clear the flags

Mount <ConeAuthFlowCleanup /> anywhere in your dashboard/authenticated layout. It clears the sessionStorage flags so logging out doesn't accidentally trigger an auto-retry on the next visit to the login page.

// app/dashboard/layout.tsx
import { ConeAuthFlowCleanup } from "@digibuffer/cone-auth/ui"

export default function DashboardLayout({ children }) {
  return (
    <div>
      <ConeAuthFlowCleanup />  {/* ← clears flags on mount */}
      {children}
    </div>
  )
}

Or call clearConeOAuthFlow() directly if you have a client component that already mounts in the authenticated area:

import { clearConeOAuthFlow } from "@digibuffer/cone-auth"

useEffect(() => {
  clearConeOAuthFlow()
}, [])

How it works

  1. startConeOAuthFlow() stores a timestamp in sessionStorage before the OAuth redirect.
  2. When the user returns to the login page (with or without an error param), useConeOAuthRetry checks:
    • Is there a known retryable OAuth error in the URL? (AccessDenied, OAuthCallbackError, etc.)
    • Or is there a recent flow timestamp in sessionStorage (within 15 minutes)?
  3. If either is true and retries haven't been exhausted (max 2), it silently calls signIn() again — the user sees only a spinner.
  4. On the second try the PKCE/state cookies are fresh, so it succeeds.
  5. Once the user reaches the dashboard, clearConeOAuthFlow() removes the flags.

Exports

@digibuffer/cone-auth (logic only, no React)

import {
  startConeOAuthFlow,   // call before signIn()
  clearConeOAuthFlow,   // call on dashboard mount
  isConeOAuthInProgress,  // returns true if a flow is active
  checkConeOAuthRetry,    // returns 'retry' | 'banner' | 'none'
  CONE_RETRYABLE_ERRORS,  // Set of retryable error codes
  CONE_AUTH_FLOW_KEY,     // sessionStorage key name
  CONE_AUTH_RETRY_KEY,    // sessionStorage retry count key
  CONE_AUTH_MAX_RETRIES,  // 2
  CONE_AUTH_FLOW_TTL_MS,  // 15 minutes in ms
} from "@digibuffer/cone-auth"

@digibuffer/cone-auth/ui (React, requires next-auth peer dep)

import {
  useConeOAuthRetry,      // hook for the login page
  startConeOAuthFlow,     // re-exported for convenience
  ConeSignInButton,       // ready-made sign-in button component
  ConeAuthFlowCleanup,    // component to mount in dashboard layout
} from "@digibuffer/cone-auth/ui"

<ConeSignInButton /> props

| Prop | Type | Default | Description | |---|---|---|---| | providerId | string | "coneid" | next-auth provider id | | callbackUrl | string | "/dashboard" | Redirect after sign-in | | label | string | "Sign in with Cone ID" | Button text | | loadingLabel | string | "Redirecting to Cone ID…" | Text while loading | | className | string | — | CSS class for the button | | onSignIn | () => void | — | Called after sign-in is triggered |


License

UNLICENSED — published publicly for transparency. Use is permitted only within applications authorized by Cone.