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

@codeswayam/auth

v2.7.2

Published

Plug-and-play auth, subscriptions, and credits for CodeSwayam SaaS products

Readme

@codeswayam/auth

Plug-and-play authentication, SSO, subscriptions, credits, and push notifications for all CodeSwayam apps.

Version TypeScript License

@codeswayam/auth is the root authentication and identity package for every CodeSwayam application. It provides a complete auth stack: SSO login/logout, JWT management, role-based access control, credit wallet management, subscription guards, and Web Push notifications — all as composable React hooks and components that plug into any Next.js app.


Table of Contents


Overview

@codeswayam/auth covers the full identity and monetisation surface of a CodeSwayam app:

| Domain | What it provides | |---|---| | Authentication | SSO redirect, JWT storage, auto token refresh, callback handling | | User identity | useCSWUser() for current user data | | Roles | useCSWRole() with isAdmin, isModerator, hasRole() | | Subscriptions | useCSWSubscriptions(), SubscriptionGuard | | Credits | useCSWCredits(), CreditGuard, CreditBadge, BuyCreditsModal | | Push notifications | useCSWNotifications(), NotificationBell | | Middleware | withCSWAuth() — Next.js Edge middleware factory | | Entitlements | Re-exports all of @codeswayam/access |


Installation

npm install @codeswayam/auth
# or
yarn add @codeswayam/auth
# or
pnpm add @codeswayam/auth

Peer Dependencies

| Package | Version | |---|---| | react | ^18.0.0 | | react-dom | ^18.0.0 | | next | ^13.0.0 \|\| ^14.0.0 \|\| ^15.0.0 | | swr | ^2.0.0 | | @codeswayam/api-client | ^1.3.0 | | @codeswayam/access | ^1.0.0 |

npm install react react-dom next swr @codeswayam/api-client @codeswayam/access

Quick Start

1. Add middleware

// middleware.ts (project root)
import { withCSWAuth } from '@codeswayam/auth';

export default withCSWAuth({
  ssoUrl: process.env.NEXT_PUBLIC_SSO_URL!,
  callbackPath: '/auth/callback',
  publicPaths: ['/', '/pricing', '/about'],
});

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

2. Add CSWProvider to your root layout

// app/layout.tsx
import { CSWProvider } from '@codeswayam/auth';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <CSWProvider apiUrl={process.env.NEXT_PUBLIC_API_URL!}>
          {children}
        </CSWProvider>
      </body>
    </html>
  );
}

3. Guard your pages

// app/dashboard/layout.tsx
import { AuthGuard } from '@codeswayam/auth';

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return <AuthGuard>{children}</AuthGuard>;
}

API Reference

withCSWAuth — Next.js Middleware

Factory function that returns a Next.js Edge middleware. It verifies the user's JWT on every request and redirects unauthenticated users to the SSO login page.

function withCSWAuth(config: CSWAuthMiddlewareConfig): NextMiddleware

Config options:

| Option | Type | Required | Description | |---|---|---|---| | ssoUrl | string | ✅ | Base URL of the CodeSwayam auth service | | callbackPath | string | ✅ | Path in your app that handles the SSO callback (e.g. /auth/callback) | | publicPaths | string[] | ✅ | Array of paths that are accessible without authentication |

// middleware.ts
import { withCSWAuth } from '@codeswayam/auth';

export default withCSWAuth({
  ssoUrl: 'https://auth.codeswayam.com',
  callbackPath: '/auth/callback',
  publicPaths: ['/', '/pricing', '/blog', '/about'],
});

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

CSWProvider — Root Provider

The root React context provider for the entire @codeswayam/auth stack. Must be placed above all auth hooks and guard components.

import { CSWProvider } from '@codeswayam/auth';

<CSWProvider apiUrl="https://api.codeswayam.com">
  {children}
</CSWProvider>

Props:

| Prop | Type | Required | Description | |---|---|---|---| | apiUrl | string | ✅ | Base URL for the CodeSwayam API | | children | React.ReactNode | ✅ | Child components |

CSWProvider internally mounts AccessProvider (from @codeswayam/access), so you only need one provider at the root.


useCSWUser

Returns the currently authenticated user's data.

function useCSWUser(): {
  user: CSWUser | null;
  isLoaded: boolean;
  isSignedIn: boolean;
}

Return values:

| Property | Type | Description | |---|---|---| | user | CSWUser \| null | User object when signed in, null otherwise | | isLoaded | boolean | true once the initial user fetch completes | | isSignedIn | boolean | true when a valid session exists |

CSWUser shape:

interface CSWUser {
  id: string;
  email: string;
  name: string;
  avatarUrl?: string;
  role: string;
  createdAt: string;
}

useCSWRole

Provides role-based permission helpers for the current user.

function useCSWRole(): {
  role: string | null;
  isAdmin: boolean;
  isModerator: boolean;
  hasRole: (role: string) => boolean;
}

Return values:

| Property | Type | Description | |---|---|---| | role | string \| null | Raw role string for the current user | | isAdmin | boolean | Shorthand for hasRole('admin') | | isModerator | boolean | Shorthand for hasRole('moderator') | | hasRole(r) | (role: string) => boolean | Generic role check |


useCSWCredits

Provides access to the user's credit wallet, feature costs, and credit operations.

function useCSWCredits(): {
  balance: number;
  featureCosts: Record<string, number>;
  useCredits: (feature: string) => Promise<void>;
  purchase: (packId: string) => Promise<void>;
}

Return values:

| Property | Type | Description | |---|---|---| | balance | number | Current credit balance | | featureCosts | Record<string, number> | Per-feature credit costs (e.g. { ai_chat: 5 }) | | useCredits(feature) | (feature: string) => Promise<void> | Deduct credits for a feature use | | purchase(packId) | (packId: string) => Promise<void> | Purchase a credit pack by ID |


useCSWSubscriptions

Provides the user's active subscriptions and helpers for checking plan status.

function useCSWSubscriptions(): {
  subscriptions: UserSubscription[];
  hasActivePlan: boolean;
  getActivePlan: (appId: string) => UserSubscription | null;
}

Return values:

| Property | Type | Description | |---|---|---| | subscriptions | UserSubscription[] | All subscriptions for the user | | hasActivePlan | boolean | true if any subscription is currently active | | getActivePlan(appId) | (appId: string) => UserSubscription \| null | Returns the active plan for a specific app |


AuthGuard

Redirects unauthenticated users to the SSO login page. Renders children only when the user is signed in.

import { AuthGuard } from '@codeswayam/auth';

<AuthGuard>
  <ProtectedPage />
</AuthGuard>

// With a custom loading state
<AuthGuard fallback={<FullPageSpinner />}>
  <ProtectedPage />
</AuthGuard>

Props:

| Prop | Type | Description | |---|---|---| | children | React.ReactNode | Content to render when authenticated | | fallback | React.ReactNode | Content to render while loading (defaults to null) |


SubscriptionGuard

Renders children only when the user has an active subscription meeting the minimum plan requirement for a given app.

import { SubscriptionGuard } from '@codeswayam/auth';

<SubscriptionGuard
  appId="auraflow"
  minPlan="pro"
  fallback={<UpgradePage />}
>
  <ProFeatureContent />
</SubscriptionGuard>

Props:

| Prop | Type | Required | Description | |---|---|---|---| | appId | string | ✅ | The CodeSwayam app identifier | | minPlan | string | ✅ | Minimum plan type required | | fallback | React.ReactNode | — | Content rendered when guard fails | | children | React.ReactNode | ✅ | Protected content |


CreditGuard

Renders children only when the user has sufficient credits for a given feature. Shows fallback (e.g. purchase prompt) otherwise.

import { CreditGuard } from '@codeswayam/auth';

<CreditGuard
  feature="smart_ai"
  cost={10}
  fallback={<BuyCreditsPrompt />}
>
  <AiFeatureComponent />
</CreditGuard>

Props:

| Prop | Type | Required | Description | |---|---|---|---| | feature | string | ✅ | Feature key to check credits for | | cost | number | ✅ | Credit cost required to use this feature | | fallback | React.ReactNode | — | Rendered when insufficient credits | | children | React.ReactNode | ✅ | Protected content |


CreditBadge

Renders a pill showing the user's current credit balance. Intended for placement in navigation or header areas.

import { CreditBadge } from '@codeswayam/auth';

// In your navbar:
<nav>
  <CreditBadge />
  <UserMenu />
</nav>

Props: None. Reads balance from useCSWCredits() internally.


BuyCreditsModal

A complete modal for browsing and purchasing credit packs. Uses Razorpay under the hood for payment processing.

import { BuyCreditsModal } from '@codeswayam/auth';
import { useState } from 'react';

export function Header() {
  const [open, setOpen] = useState(false);

  return (
    <>
      <button onClick={() => setOpen(true)}>Buy Credits</button>
      <BuyCreditsModal open={open} onClose={() => setOpen(false)} />
    </>
  );
}

Props:

| Prop | Type | Required | Description | |---|---|---|---| | open | boolean | ✅ | Controls modal visibility | | onClose | () => void | ✅ | Called when the modal is dismissed |


SSO Utilities

Low-level SSO functions exported from sso.ts. Typically you won't use these directly — withCSWAuth and AuthGuard handle the auth flow. Use these for custom auth flows.

import {
  redirectToSSO,
  useSSOCallback,
  getStoredToken,
  saveToken,
  clearToken,
  isTokenValid,
  decodeJwtPayload,
  CSW_TOKEN_KEY,
} from '@codeswayam/auth';

| Export | Signature | Description | |---|---|---| | redirectToSSO | (authUrl: string, currentUrl: string) => void | Redirects to the SSO login page with a return URL | | useSSOCallback | () => { isProcessing, error } | Hook for the SSO callback page — exchanges the ticket for a JWT | | getStoredToken | () => string \| null | Reads the JWT from localStorage | | saveToken | (token: string) => void | Persists a JWT to localStorage | | clearToken | () => void | Removes the JWT from localStorage | | isTokenValid | (token: string) => boolean | Checks if a JWT is non-expired | | decodeJwtPayload | <T>(token: string) => T | Decodes the JWT payload without verification | | CSW_TOKEN_KEY | string | The localStorage key used to store the token |


Notifications

Web Push notification management with a ready-made bell UI component.

import { useCSWNotifications, NotificationBell } from '@codeswayam/auth';

useCSWNotifications

function useCSWNotifications(): {
  isSupported: boolean;
  permission: NotificationPermission;
  isSubscribed: boolean;
  subscribe: () => Promise<void>;
  unsubscribe: () => Promise<void>;
}

| Property | Type | Description | |---|---|---| | isSupported | boolean | Whether the browser supports Web Push | | permission | NotificationPermission | 'default', 'granted', or 'denied' | | isSubscribed | boolean | Whether the user has an active push subscription | | subscribe() | () => Promise<void> | Request permission and register push subscription | | unsubscribe() | () => Promise<void> | Unregister push subscription |

NotificationBell

import { NotificationBell } from '@codeswayam/auth';

// Drop into your navigation bar
<NotificationBell />

Props: None. Handles permission requests and subscription state internally.


Re-exports

From @codeswayam/access

Everything from the access package is re-exported for convenience — you don't need to install it separately when using @codeswayam/auth.

import {
  AccessProvider,
  FeatureGate,
  TierBadge,
  UsageMeter,
  useAppAccess,
  useFeatureGate,
  useUsageTracker,
} from '@codeswayam/auth';

From @codeswayam/api-client

All API client functions for subscriptions, credits, referrals, and notifications are re-exported:

import {
  // Subscriptions
  fetchUserSubscriptions,
  fetchSubscriptionById,
  fetchPublicPlans,
  changeSubscriptionPlan,
  cancelUserSubscription,
  // Credits
  fetchMyWallet,
  useCredits,
  fetchCreditPacks,
  fetchFeatureCosts,
  createCreditPurchaseOrder,
  verifyCreditPurchase,
  // Referrals
  fetchReferralStats,
  redeemReferralCode,
  redeemCouponCode,
  // Notifications
  registerPushSubscription,
  unregisterPushSubscription,
  fetchVapidPublicKey,
} from '@codeswayam/auth';

TypeScript Interfaces

interface CSWUser {
  id: string;
  email: string;
  name: string;
  avatarUrl?: string;
  role: string;
  createdAt: string;
}

interface CSWAuthMiddlewareConfig {
  ssoUrl: string;
  callbackPath: string;
  publicPaths: string[];
}

interface CSWProviderProps {
  apiUrl: string;
  children: React.ReactNode;
}

interface AuthGuardProps {
  children: React.ReactNode;
  fallback?: React.ReactNode;
}

interface SubscriptionGuardProps {
  appId: string;
  minPlan: string;
  fallback?: React.ReactNode;
  children: React.ReactNode;
}

interface CreditGuardProps {
  feature: string;
  cost: number;
  fallback?: React.ReactNode;
  children: React.ReactNode;
}

interface BuyCreditsModalProps {
  open: boolean;
  onClose: () => void;
}

Code Examples

1. Next.js App Setup with CSWProvider

// app/layout.tsx
import { CSWProvider } from '@codeswayam/auth';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {/*
          CSWProvider initializes the entire auth + access stack.
          It internally includes AccessProvider — no need to add it separately.
        */}
        <CSWProvider apiUrl={process.env.NEXT_PUBLIC_API_URL!}>
          {children}
        </CSWProvider>
      </body>
    </html>
  );
}

2. withCSWAuth Middleware

// middleware.ts  (place at the project root, next to package.json)
import { withCSWAuth } from '@codeswayam/auth';

export default withCSWAuth({
  ssoUrl: process.env.NEXT_PUBLIC_SSO_URL!,
  callbackPath: '/auth/callback',
  publicPaths: [
    '/',
    '/pricing',
    '/blog',
    '/about',
    '/auth/callback', // must always be public
  ],
});

// Run on all routes except static assets
export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};

3. AuthGuard Usage

// app/dashboard/layout.tsx
import { AuthGuard } from '@codeswayam/auth';

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    // Unauthenticated users are automatically redirected to SSO
    <AuthGuard fallback={<div>Loading...</div>}>
      {children}
    </AuthGuard>
  );
}

4. useCSWUser Hook

'use client';
import { useCSWUser } from '@codeswayam/auth';

export function UserGreeting() {
  const { user, isLoaded, isSignedIn } = useCSWUser();

  if (!isLoaded) return <span>Loading...</span>;

  if (!isSignedIn) return <a href="/login">Sign in</a>;

  return (
    <div className="flex items-center gap-3">
      {user?.avatarUrl && (
        <img src={user.avatarUrl} alt={user.name} className="w-8 h-8 rounded-full" />
      )}
      <span>Hello, {user?.name}</span>
    </div>
  );
}

5. useCSWRole — Admin Check

'use client';
import { useCSWRole } from '@codeswayam/auth';

export function AdminPanel() {
  const { isAdmin, isModerator, hasRole } = useCSWRole();

  if (!isAdmin) {
    return <p>Access denied. Admins only.</p>;
  }

  return (
    <div>
      <h1>Admin Panel</h1>
      {isModerator && <ModerationTools />}
      {hasRole('billing_admin') && <BillingSettings />}
    </div>
  );
}

6. useCSWCredits — Deducting Credits

'use client';
import { useCSWCredits } from '@codeswayam/auth';
import { useState } from 'react';

export function AiGenerateButton() {
  const { balance, featureCosts, useCredits } = useCSWCredits();
  const [loading, setLoading] = useState(false);

  const cost = featureCosts['ai_generate'] ?? 10;
  const canAfford = balance >= cost;

  async function handleGenerate() {
    if (!canAfford) return;
    setLoading(true);
    try {
      // Deduct credits first
      await useCredits('ai_generate');
      // Then run the AI feature
      await runAiGeneration();
    } finally {
      setLoading(false);
    }
  }

  return (
    <button
      onClick={handleGenerate}
      disabled={!canAfford || loading}
      className="btn-primary"
    >
      {loading ? 'Generating...' : `Generate (${cost} credits)`}
    </button>
  );
}

7. BuyCreditsModal

'use client';
import { BuyCreditsModal, CreditBadge } from '@codeswayam/auth';
import { useState } from 'react';

export function Navbar() {
  const [buyOpen, setBuyOpen] = useState(false);

  return (
    <header className="navbar">
      <Logo />
      <nav>
        <CreditBadge />
        <button
          onClick={() => setBuyOpen(true)}
          className="btn-outline text-sm"
        >
          + Buy Credits
        </button>
      </nav>

      <BuyCreditsModal
        open={buyOpen}
        onClose={() => setBuyOpen(false)}
      />
    </header>
  );
}

8. useSSOCallback on the Callback Page

// app/auth/callback/page.tsx
'use client';
import { useSSOCallback } from '@codeswayam/auth';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

export default function AuthCallbackPage() {
  const router = useRouter();
  const { isProcessing, error } = useSSOCallback();

  useEffect(() => {
    if (!isProcessing && !error) {
      // Token saved — redirect to the app
      router.replace('/dashboard');
    }
  }, [isProcessing, error, router]);

  if (error) {
    return (
      <div className="flex flex-col items-center justify-center min-h-screen">
        <p className="text-red-500">Authentication failed: {error}</p>
        <a href="/">Return home</a>
      </div>
    );
  }

  return (
    <div className="flex items-center justify-center min-h-screen">
      <p>Signing you in...</p>
    </div>
  );
}

9. NotificationBell

'use client';
import { NotificationBell } from '@codeswayam/auth';

// Drop this anywhere in your navigation
export function AppHeader() {
  return (
    <header>
      <Logo />
      <div className="flex items-center gap-4">
        <NotificationBell />
        <UserMenu />
      </div>
    </header>
  );
}

Using the underlying hook for custom UIs:

'use client';
import { useCSWNotifications } from '@codeswayam/auth';

export function NotificationSettings() {
  const { isSupported, permission, isSubscribed, subscribe, unsubscribe } =
    useCSWNotifications();

  if (!isSupported) {
    return <p>Your browser does not support push notifications.</p>;
  }

  return (
    <div>
      <p>Status: {permission}</p>
      {isSubscribed ? (
        <button onClick={unsubscribe}>Disable Notifications</button>
      ) : (
        <button onClick={subscribe}>Enable Notifications</button>
      )}
    </div>
  );
}

Integration Guide (Next.js)

Recommended File Structure

src/
├── app/
│   ├── layout.tsx              ← CSWProvider here
│   ├── middleware.ts            ← withCSWAuth here (project root)
│   ├── auth/
│   │   └── callback/
│   │       └── page.tsx        ← useSSOCallback here
│   ├── dashboard/
│   │   ├── layout.tsx          ← AuthGuard here
│   │   └── page.tsx
│   └── admin/
│       ├── layout.tsx          ← AuthGuard + role check here
│       └── page.tsx
└── components/
    └── Navbar.tsx              ← CreditBadge + NotificationBell

Environment Variables

# .env.local
NEXT_PUBLIC_API_URL=https://api.codeswayam.com
NEXT_PUBLIC_SSO_URL=https://auth.codeswayam.com

Complete App Router Setup

middleware.ts (project root)

import { withCSWAuth } from '@codeswayam/auth';

export default withCSWAuth({
  ssoUrl: process.env.NEXT_PUBLIC_SSO_URL!,
  callbackPath: '/auth/callback',
  publicPaths: ['/', '/pricing', '/about', '/auth/callback'],
});

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

app/layout.tsx

import { CSWProvider } from '@codeswayam/auth';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <CSWProvider apiUrl={process.env.NEXT_PUBLIC_API_URL!}>
          {children}
        </CSWProvider>
      </body>
    </html>
  );
}

app/dashboard/layout.tsx

import { AuthGuard, SubscriptionGuard } from '@codeswayam/auth';

export default function DashboardLayout({ children }: { children: React.ReactNode }) {
  return (
    <AuthGuard>
      <SubscriptionGuard appId="auraflow" minPlan="free" fallback={<NoSubscriptionPage />}>
        {children}
      </SubscriptionGuard>
    </AuthGuard>
  );
}

app/auth/callback/page.tsx

'use client';
import { useSSOCallback } from '@codeswayam/auth';
import { useRouter } from 'next/navigation';
import { useEffect } from 'react';

export default function CallbackPage() {
  const router = useRouter();
  const { isProcessing, error } = useSSOCallback();

  useEffect(() => {
    if (!isProcessing && !error) router.replace('/dashboard');
  }, [isProcessing, error, router]);

  if (error) return <div>Auth error: {error}</div>;
  return <div>Signing in...</div>;
}

Source Structure

packages/auth-client/src/
├── index.ts                    — Main barrel exports
├── sso.ts                      — SSO utilities and JWT helpers
├── middleware.ts               — withCSWAuth() Next.js middleware factory
├── CSWProvider.tsx             — Root React provider
├── users.ts                    — User utility functions
├── hooks/
│   ├── useCSWUser.ts           — Current user data hook
│   ├── useCSWRole.ts           — Role checking hook
│   ├── useCSWCredits.ts        — Credit wallet hook
│   ├── useCSWSubscriptions.ts  — Subscriptions hook
│   └── useCSWTokenRefresh.ts   — Auto token refresh hook
├── components/
│   ├── AuthGuard.tsx           — Authentication guard component
│   ├── SubscriptionGuard.tsx   — Subscription-based guard component
│   ├── CreditGuard.tsx         — Credit-based guard component
│   ├── CreditBadge.tsx         — Credit balance display
│   └── BuyCreditsModal.tsx     — Credit purchase modal (Razorpay)
└── notifications/
    ├── useCSWNotifications.ts  — Web Push management hook
    ├── NotificationBell.tsx    — Bell UI component
    └── index.ts                — Notifications barrel exports

Changelog

v2.7.2

  • SSO Performance: Dynamic origin detection and fast-path redirect eliminating domain verification flash latency.
  • Cross-App Grants: Unified cross-app grant resolution exported via @codeswayam/access.
  • Dependencies: Bumped @codeswayam/api-client to ^1.3.4 and @codeswayam/access to ^1.0.3.

v2.7.1

  • Domain-wide cookie synchronisation for seamless cross-subdomain sessions.

v2.7.0

  • Bugfix: Fixed data.find is not a function in useCSWFeatureCost when backend returns dictionary objects (Record<string, number>), arrays, or nested data wrappers.
  • SSO Context Retention: Added appName option to withCSWAuth and redirectToSSO to preserve calling app identity and return trail during central login.
  • URL Normalization: Automatic /sso path resolution in resolveSsoUrl so passing root base URLs (e.g. https://auth.codeswayam.com) seamlessly hits the SSO ticket endpoint.

v2.6.0

  • Multi-currency support (INR/USD) in subscription helpers
  • Added domain-wide cookie retention for cross-app currency preferences
  • Fixed token refresh race condition on concurrent requests
  • Improved BuyCreditsModal error state handling

v2.5.0

  • Added NotificationBell component
  • Added useCSWNotifications hook with full Web Push support
  • CSWProvider now internally mounts AccessProvider

v2.4.0

  • Added CreditGuard component
  • Added SubscriptionGuard component
  • useCSWCredits now exposes featureCosts

v2.3.0

  • Added re-exports from @codeswayam/access
  • Added re-exports from @codeswayam/api-client

v2.0.0

  • Replaced cookie-only auth with JWT + cookie hybrid approach
  • withCSWAuth rewritten as an Edge-compatible middleware factory
  • Added useCSWTokenRefresh for background token renewal

Part of the CodeSwayam platform. For support, open an issue in the monorepo.