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

@nextdevx/core

v0.2.2

Published

Core utilities, auth adapters, and configuration for @nextdevx packages

Readme

@nextdevx/core

Core utilities, authentication adapters, and configuration for the @nextdevx package ecosystem.

Features

  • Unified Auth Adapters - Consistent authentication interface for Supabase, Clerk, and NextAuth.js
  • Configuration Provider - Centralized configuration management for all @nextdevx packages
  • Multi-Tenancy Support - Built-in organization-based data isolation
  • Element Picker - Interactive DOM element selection with CSS selector and XPath generation
  • Request Utilities - IP address and user agent extraction helpers

Installation

npm install @nextdevx/core
# or
pnpm add @nextdevx/core
# or
yarn add @nextdevx/core

Quick Start

1. Create an Auth Adapter

Choose the adapter for your authentication provider:

// Supabase
import { createSupabaseAuthAdapter } from '@nextdevx/core/auth/supabase'

const authAdapter = createSupabaseAuthAdapter({
  client: supabaseClient,
  adminRoles: ['admin', 'superadmin'],
  getUserProfile: async (userId) => {
    const { data } = await supabase
      .from('profiles')
      .select('name, role, organization_id')
      .eq('id', userId)
      .single()
    return data ? {
      name: data.name,
      role: data.role,
      organizationId: data.organization_id,
    } : null
  },
})
// Clerk
import { createClerkAuthAdapter } from '@nextdevx/core/auth/clerk'

const authAdapter = createClerkAuthAdapter({
  adminRoles: ['org:admin'],
})
// NextAuth.js
import { createNextAuthAdapter } from '@nextdevx/core/auth/next-auth'

const authAdapter = createNextAuthAdapter({
  adminRoles: ['admin'],
})

2. Configure the Provider

Wrap your application with NextstackProvider:

// app/providers.tsx
'use client'

import { NextstackProvider } from '@nextdevx/core'
import { createSupabaseAuthAdapter } from '@nextdevx/core/auth/supabase'

export function Providers({ children }: { children: React.ReactNode }) {
  const authAdapter = createSupabaseAuthAdapter({
    client: supabaseClient,
  })

  return (
    <NextstackProvider
      config={{
        auth: authAdapter,
        prisma: prismaClient,
        multiTenancy: {
          enabled: true,
          getOrganizationId: async () => {
            const user = await authAdapter.getCurrentUser()
            return user?.organizationId ?? null
          },
        },
        features: {
          feedback: true,
          audit: true,
          whatsNew: true,
        },
      }}
    >
      {children}
    </NextstackProvider>
  )
}

3. Use the Hooks

import { useAuth, useNextstackConfig, usePrisma, useOrganizationId } from '@nextdevx/core'

function MyComponent() {
  // Get current authenticated user (throws if not in AuthContextProvider)
  const user = useAuth()

  // Get full configuration
  const config = useNextstackConfig()

  // Get Prisma client
  const prisma = usePrisma()

  // Get current organization ID (for multi-tenancy)
  const orgId = useOrganizationId()

  return <div>Welcome, {user.name}!</div>
}

API Reference

Auth Types

AuthUser

Represents an authenticated user across all auth providers.

interface AuthUser {
  id: string
  email: string
  name?: string
  role?: string
  organizationId?: string
  metadata?: Record<string, unknown>
}

AuthAdapter

Interface that all auth adapters must implement.

interface AuthAdapter {
  /** Get current authenticated user (returns null if not authenticated) */
  getCurrentUser(): Promise<AuthUser | null>

  /** Sign in with email/password (used by dev-login) */
  signInWithPassword(email: string, password: string): Promise<AuthUser>

  /** Sign out current user */
  signOut(): Promise<void>

  /** Check if user has a specific role */
  hasRole(user: AuthUser, role: string): boolean

  /** Get user by ID (for attribution in audit logs, feedback, etc.) */
  getUserById(id: string): Promise<AuthUser | null>

  /** Check if user is admin */
  isAdmin(user: AuthUser): boolean
}

Configuration Types

NextstackConfig

Main configuration object for @nextdevx packages.

interface NextstackConfig {
  /** Auth adapter instance */
  auth: AuthAdapter
  /** Prisma client instance */
  prisma: PrismaClient
  /** Multi-tenancy configuration */
  multiTenancy: MultiTenancyConfig
  /** Optional feature flags */
  features?: FeatureFlags
}

MultiTenancyConfig

interface MultiTenancyConfig {
  /** Whether multi-tenancy is enabled */
  enabled: boolean
  /** Function to get current organization ID */
  getOrganizationId: () => Promise<string | null>
}

FeatureFlags

interface FeatureFlags {
  feedback?: boolean
  audit?: boolean
  whatsNew?: boolean
  devtools?: boolean
}

Auth Adapters

Supabase Adapter

import { createSupabaseAuthAdapter } from '@nextdevx/core/auth/supabase'

interface SupabaseAuthAdapterOptions {
  client: SupabaseClient
  adminRoles?: string[]  // Default: ['admin', 'superadmin']
  getUserProfile?: (userId: string) => Promise<{
    name?: string
    role?: string
    organizationId?: string
  } | null>
}

const adapter = createSupabaseAuthAdapter(options)

Clerk Adapter

import { createClerkAuthAdapter } from '@nextdevx/core/auth/clerk'

interface ClerkAuthAdapterOptions {
  adminRoles?: string[]  // Default: ['org:admin']
}

const adapter = createClerkAuthAdapter(options)

NextAuth.js Adapter

import { createNextAuthAdapter } from '@nextdevx/core/auth/next-auth'

interface NextAuthAdapterOptions {
  adminRoles?: string[]  // Default: ['admin']
}

const adapter = createNextAuthAdapter(options)

Hooks

useAuth()

Get the current authenticated user. Throws an error if used outside of AuthContextProvider or if the user is not authenticated.

const user = useAuth()
// user is guaranteed to be AuthUser (not null)

useAuthOptional()

Get the current authenticated user, or null if not authenticated. Safe to use in components that may render without authentication.

const user = useAuthOptional()
// user is AuthUser | null

useNextstackConfig()

Access the full configuration object.

const config = useNextstackConfig()
// config.auth, config.prisma, config.multiTenancy, config.features

usePrisma()

Get the Prisma client instance from configuration.

const prisma = usePrisma()
const users = await prisma.user.findMany()

useOrganizationId()

Get the current organization ID for multi-tenancy filtering. Returns null if multi-tenancy is disabled.

const orgId = useOrganizationId()

useMultiTenancy()

Check if multi-tenancy is enabled.

const isMultiTenant = useMultiTenancy()

Element Picker

Interactive component for selecting DOM elements and generating selectors.

import { ElementPicker } from '@nextdevx/core/element-picker'

interface ElementPickerProps {
  /** Whether the picker is active */
  isOpen: boolean
  /** Callback when an element is selected */
  onSelect: (elementInfo: ElementInfo) => void
  /** Callback when selection is cancelled */
  onCancel: () => void
  /** Custom instruction text */
  instructionText?: string
  /** Data attribute for excluding picker elements */
  excludeAttribute?: string  // Default: 'data-element-picker'
}

interface ElementInfo {
  /** Human-readable element name */
  friendlyName: string
  /** CSS selector for the element */
  cssSelector: string
  /** XPath to the element */
  xpath: string
  /** HTML tag name (lowercase) */
  tagName: string
}

Element Picker Usage

import { useState } from 'react'
import { ElementPicker } from '@nextdevx/core/element-picker'
import type { ElementInfo } from '@nextdevx/core'

function MyComponent() {
  const [isPickerOpen, setIsPickerOpen] = useState(false)
  const [selectedElement, setSelectedElement] = useState<ElementInfo | null>(null)

  return (
    <>
      <button onClick={() => setIsPickerOpen(true)}>
        Select Element
      </button>

      <ElementPicker
        isOpen={isPickerOpen}
        onSelect={(elementInfo) => {
          setSelectedElement(elementInfo)
          setIsPickerOpen(false)
          console.log('Selected:', elementInfo.friendlyName)
          console.log('CSS Selector:', elementInfo.cssSelector)
        }}
        onCancel={() => setIsPickerOpen(false)}
        instructionText="Click an element to select it"
      />

      {selectedElement && (
        <div>
          <p>Selected: {selectedElement.friendlyName}</p>
          <code>{selectedElement.cssSelector}</code>
        </div>
      )}
    </>
  )
}

Element Picker Utilities

import {
  getElementInfo,
  generateCssSelector,
  generateXPath,
  generateFriendlyName,
  getElementLabel,
  findElementBySelector,
  shouldExcludeElement,
  getElementBounds,
  isTailwindClass,
  filterTailwindClasses,
  clearNameCaches,
  getNameGenerationMetrics,
  resetNameGenerationMetrics,
} from '@nextdevx/core/element-picker'

// Get complete element information
const info = getElementInfo(element)

// Generate individual selectors
const cssSelector = generateCssSelector(element)
const xpath = generateXPath(element)
const friendlyName = generateFriendlyName(element)

// Find element by selector
const element = findElementBySelector(cssSelector)

// Check if element should be excluded from picker
const shouldExclude = shouldExcludeElement(element, 'data-element-picker')

// Get element bounding rect
const bounds = getElementBounds(element)

// Tailwind class utilities
const isTailwind = isTailwindClass('text-blue-500')  // true
const filteredClasses = filterTailwindClasses(['text-blue-500', 'my-custom-class'])

Request Utilities

Helpers for extracting request metadata (useful for audit logging).

import { getIpAddress, getUserAgent, getRequestMetadata } from '@nextdevx/core'

// In a Next.js API route or Server Action
export async function POST(request: Request) {
  const ip = getIpAddress(request.headers)
  const userAgent = getUserAgent(request.headers)

  // Or get both at once
  const { ipAddress, userAgent } = getRequestMetadata(request.headers)

  // Use for audit logging, rate limiting, etc.
}

Creating a Custom Auth Adapter

If you're using a custom authentication solution, implement the AuthAdapter interface:

import type { AuthAdapter, AuthUser } from '@nextdevx/core'

export function createCustomAuthAdapter(): AuthAdapter {
  return {
    async getCurrentUser(): Promise<AuthUser | null> {
      // Your implementation
      const session = await getSession()
      if (!session) return null

      return {
        id: session.userId,
        email: session.email,
        name: session.name,
        role: session.role,
      }
    },

    async signInWithPassword(email: string, password: string): Promise<AuthUser> {
      // Your implementation
      const user = await authenticate(email, password)
      return user
    },

    async signOut(): Promise<void> {
      // Your implementation
      await clearSession()
    },

    hasRole(user: AuthUser, role: string): boolean {
      return user.role === role
    },

    async getUserById(id: string): Promise<AuthUser | null> {
      // Your implementation
      const user = await fetchUser(id)
      return user
    },

    isAdmin(user: AuthUser): boolean {
      return user.role === 'admin'
    },
  }
}

Peer Dependencies

| Package | Version | Required | |---------|---------|----------| | react | >=18.0.0 | Yes | | react-dom | >=18.0.0 | Yes | | @prisma/client | >=5.0.0 | Yes | | lucide-react | >=0.300.0 | Optional | | @supabase/supabase-js | * | Optional (for Supabase adapter) | | @clerk/nextjs | * | Optional (for Clerk adapter) | | next-auth | * | Optional (for NextAuth adapter) |

TypeScript

This package is written in TypeScript and includes full type definitions. All exports are fully typed.

import type {
  AuthUser,
  AuthAdapter,
  AuthProvider,
  NextstackConfig,
  MultiTenancyConfig,
  FeatureFlags,
  ElementInfo,
  ElementPickerProps,
  HighlightPosition,
  TooltipPosition,
} from '@nextdevx/core'

License

MIT