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

@brah.ma/aham

v1.0.6

Published

Brahma OS Identity Toolkit

Downloads

585

Readme

@brah.ma/aham — SDK V3

Liquid SSO + Unified Karma + On-Chain Tokens for the Brahma ecosystem.


Table of Contents

  1. Installation
  2. Quick Start (3 Lines)
  3. Upgrading from V2
  4. BrahmaProvider
  5. Authentication (Liquid SSO)
  6. Session Management
  7. Karma System
  8. On-Chain Tokens
  9. Utilities
  10. API Reference
  11. Security

Installation

npm install @brah.ma/aham @brah.ma/sthan

Peer dependencies (required in your project):

npm install react react-dom framer-motion lucide-react clsx tailwind-merge

Quick Start

Three lines to authenticate a user on any Brahma website:

import { BrahmaProvider, AhamInitiateButton } from '@brah.ma/aham';

export default function App() {
  return (
    <BrahmaProvider config={{ ahamGatewayUrl: "https://aham.brah.ma/gateway" }}>
      <AhamInitiateButton onVerified={(user) => console.log("Welcome:", user)} />
    </BrahmaProvider>
  );
}

That's it. The button handles the entire SSO flow, session persistence, and token management.


Upgrading from V2

What Changed

| Feature | V2 (aham-auth-sdk.js) | V3 (@brah.ma/aham) | |---|---|---| | Architecture | Vanilla JS class (AhamAuth) | React hooks + Context Provider | | SSO | Popup only | Popup, Redirect, Silent (Omni-Flow) | | Karma | Single karmaPoints integer | Multi-denomination (KARMA, PUNYA, DHANA, ...) | | Web3 | Not integrated | Unified — one call for Web2 + Web3 sync | | Sessions | localStorage with manual restore | Auto-restore via BrahmaProvider | | API Calls | Manual fetch with Bearer token | useBrahmaAPI hook with auto-auth |

Migration Steps

Step 1: Replace the script tag

- <script src="https://aham.brah.ma/aham-auth-sdk.js"></script>
- <script>
-   window.ahamAuth = new AhamAuth({ authDomain: 'https://aham.brah.ma' });
- </script>
+ npm install @brah.ma/aham @brah.ma/sthan

Step 2: Wrap your app in BrahmaProvider

// _app.tsx or layout.tsx
import { BrahmaProvider } from '@brah.ma/aham';

export default function App({ children }) {
  return (
    <BrahmaProvider config={{
      ahamGatewayUrl: "https://aham.brah.ma/gateway",
      ahamApiUrl: "https://aham.brah.ma",
    }}>
      {children}
    </BrahmaProvider>
  );
}

Step 3: Replace V2 API calls

// Before (V2)
- const isLoggedIn = window.ahamAuth.isAuthenticated();
- const user = window.ahamAuth.getUser();
- await window.ahamAuth.addKarma(5, 'page_visit');

// After (V3)
+ const { isAuthenticated, user } = useBrahmaSession();
+ const { add } = useKarma();
+ await add('KARMA', 5, 'page_visit');

Step 4: Replace the login button

- <button onclick="window.ahamAuth.login()">Login</button>
+ <AhamInitiateButton
+   flow="popup"
+   onVerified={(payload) => console.log('User:', payload)}
+ />

BrahmaProvider

Wraps your entire app. Manages shared auth state, session auto-restore, and config.

import { BrahmaProvider } from '@brah.ma/aham';

<BrahmaProvider config={{
  ahamGatewayUrl: "https://aham.brah.ma/gateway",
  ahamApiUrl: "https://aham.brah.ma",
  flow: "popup",                    // Default SSO flow
  sessionMaxAge: 3600000,           // 1 hour (ms)
}}>
  <App />
</BrahmaProvider>

Config Options

| Prop | Type | Default | Description | |---|---|---|---| | ahamGatewayUrl | string | https://aham.brah.ma/gateway | URL of the SSO gateway | | ahamApiUrl | string | https://aham.brah.ma | Base URL for API calls | | flow | 'popup' \| 'redirect' \| 'silent' | 'popup' | Default authentication flow | | sessionMaxAge | number | 3600000 | Session expiry in milliseconds | | allowedOrigins | string[] | ['https://aham.brah.ma'] | Origins accepted for postMessage |


Authentication

useAham

The core SSO hook. Supports three authentication flows.

import { useAham } from '@brah.ma/aham';

function LoginPage() {
  const { initiate, intercept, isVerified, atmaSutra, error } = useAham({
    flow: 'popup',
    ahamGatewayUrl: 'https://aham.brah.ma/gateway',
    onSuccess: (payload) => {
      console.log('AtmaSutra:', payload.atmaSutra);
      console.log('MoolSthan:', payload.moolSthan);
    },
    onFailed: (err) => console.error(err),
  });

  return <button onClick={initiate}>Login to Brahma</button>;
}

Return Values

| Property | Type | Description | |---|---|---| | initiate() | () => Promise<void> | Triggers the configured SSO flow | | intercept(action, callback) | (string, () => void) => void | Auth-gate an action | | isInitiating | boolean | True while SSO is in progress | | isVerified | boolean | True after successful auth | | atmaSutra | string \| null | User's permanent ID | | error | string \| null | Error message if auth failed |

AhamInitiateButton

Pre-built, animated "hold-to-authenticate" button.

import { AhamInitiateButton } from '@brah.ma/aham';

<AhamInitiateButton
  flow="popup"
  ahamGatewayUrl="https://aham.brah.ma/gateway"
  theme="mystical-dark"          // "mystical-dark" | "light"
  holdDurationMs={2000}          // How long to hold (ms)
  onVerified={(payload) => {}}   // Success callback
  onFailed={(err) => {}}         // Error callback
/>

Omni-Flow Modes

popup — The Seamless Path

Opens a popup window to aham.brah.ma/gateway. On success, sends the token back via a secure postMessage. No page navigation.

useAham({ flow: 'popup' })

Best for: SPAs, dashboards, any page where you don't want to lose state.

redirect — The Traditional Path

Full page redirect to the gateway. After auth, redirects back to your page with the token.

useAham({ flow: 'redirect' })

Best for: Server-rendered pages, mobile browsers that block popups.

silent — The Invisible Path

Opens a hidden <iframe> to check if the user already has an active Aham session. If yes, auto-authenticates without any UI. Falls back to popup if blocked by ITP (Safari/Brave).

useAham({ flow: 'silent' })

Best for: Auto-login on return visits, "stay logged in" experiences.

Action Interception

Gate any action behind authentication. If the user isn't logged in, the SDK triggers auth first, then automatically resumes the action after success.

const { intercept } = useAham({ flow: 'popup' });

function handlePurchase() {
  intercept('BUY_ITEM', () => {
    // This only runs after the user is authenticated
    processPurchase();
  });
}

<button onClick={handlePurchase}>Buy Now — ₹99</button>

Redirect flow handles this too: The pending action is serialized to localStorage and replayed after the redirect returns.


Session Management

useBrahmaSession

Quick access to auth state. Reads from BrahmaProvider context.

import { useBrahmaSession } from '@brah.ma/aham';

function Header() {
  const { user, token, isAuthenticated, isLoading, logout, refresh } = useBrahmaSession();

  if (isLoading) return <Spinner />;

  return isAuthenticated ? (
    <div>
      <span>Welcome, {user.atmaSutra}</span>
      <button onClick={logout}>Sign Out</button>
    </div>
  ) : (
    <AhamInitiateButton />
  );
}

| Property | Type | Description | |---|---|---| | user | BrahmaUser \| null | { atmaSutra, moolSthan, ...any } | | token | string \| null | JWT session token | | isAuthenticated | boolean | Quick auth check | | isLoading | boolean | True during initial session restore | | logout() | () => void | Clears all session data | | refresh() | () => void | Re-validates session from storage |

useBrahmaAPI

Authenticated fetch wrapper. Auto-attaches the Bearer token. Auto-handles 401 by calling logout().

import { useBrahmaAPI } from '@brah.ma/aham';

function ProfilePage() {
  const { fetch: brahmaFetch } = useBrahmaAPI();

  async function loadProfile() {
    const res = await brahmaFetch('/api/user/profile');
    const data = await res.json();
    // Token is already attached, 401s auto-logout
  }
}

| Method | Signature | Description | |---|---|---| | fetch | (endpoint: string, options?: RequestInit) => Promise<Response> | Relative paths resolve against ahamApiUrl |


Karma System

useKarma

One function for the user. Two layers behind the scenes.

Every add() call instantly writes to Web2 (Prisma DB) AND queues an on-chain mint. The sync status is tracked per-record.

import { useKarma } from '@brah.ma/aham';

function RewardPanel() {
  const { balances, add, fetchBalances, getHistory, isLoading } = useKarma();

  // Add karma — single call handles both Web2 and Web3
  const reward = async () => {
    await add('PUNYA', 5, 'temple_visit', 'Visited morning aarti');
    await fetchBalances(); // Refresh UI
  };

  return (
    <div>
      <p>KARMA: {balances.KARMA?.web2 || 0}</p>
      <p>PUNYA: {balances.PUNYA?.web2 || 0}</p>
      <button onClick={reward}>+5 Punya</button>
    </div>
  );
}

add(denom, amount, action, description?)

| Param | Type | Description | |---|---|---| | denom | string | Token denomination: 'KARMA', 'PUNYA', 'DHANA', or any custom | | amount | number | Positive integer to add | | action | string | Machine-readable action ID (e.g. 'daily_sankalp') | | description | string? | Optional human-readable note |

Returns: { transaction, balances } — the transaction record and updated balances.

Balance Shape

balances = {
  KARMA: { web2: 42, onChain: 35, pending: 7 },
  PUNYA: { web2: 10, onChain: 10, pending: 0 },
  DHANA: { web2: 0,  onChain: 0,  pending: 0 },
}

| Field | Meaning | |---|---| | web2 | Total accumulated in the database (instant) | | onChain | Confirmed on the Brahman blockchain | | pending | Queued for chain mint (web2 − onChain) |

Multi-Denomination Support

Denominations are open strings, not enums. You can create any denomination without a schema migration:

add('KARMA', 11, 'daily_sankalp');     // Standard karma
add('PUNYA', 5,  'temple_visit');      // Merit points
add('DHANA', 100, 'donation');         // Wealth tokens
add('SHAKTI', 1, 'meditation');        // Custom — works immediately!

Chain Sync Lifecycle

add('KARMA', 5, 'action')
    │
    ├── INSTANT → KarmaBalance.KARMA += 5 (DB)
    ├── INSTANT → KarmaTransaction { chainStatus: 'pending' }
    │
    └── BACKGROUND (cron) → /api/karma/v3/sync
        ├── Reads all pending transactions
        ├── Batches per user per denom
        ├── Mints ukarma on Brahman chain via Treasury
        └── Updates chainStatus: 'minted', stores txHash

The cron/sync is a backend concern. Partners never need to think about it — add() is fire-and-forget from their perspective.


On-Chain Tokens

useTokens

Live query of the Brahman blockchain for all token denominations.

import { useTokens } from '@brah.ma/aham';

function WalletView() {
  const { balances, refreshBalances, isLoading } = useTokens();

  useEffect(() => { refreshBalances(); }, []);

  return (
    <div>
      {Object.entries(balances).map(([denom, amount]) => (
        <p key={denom}>{denom}: {amount}</p>
      ))}
     {/* Output: KARMA: 11, PUNYA: 10, DHANA: 0 */}
    </div>
  );
}

New denominations minted on the chain auto-appear — no SDK update needed.


Utilities

Token Inspection (Client-Side)

import { decodeToken, isTokenExpired, getTokenClaims } from '@brah.ma/aham';

const claims = decodeToken(jwt);
// { atmaSutra, moolSthan, exp, iat, iss, aud }

if (isTokenExpired(jwt)) {
  // Trigger re-auth
}

const valid = getTokenClaims(jwt); // null if expired

Note: These decode the JWT payload without verifying the signature. Signature verification must happen server-side.

Session Persistence (Low-Level)

import { saveSession, getSession, clearSession, isSessionValid } from '@brah.ma/aham';

saveSession(token, { atmaSutra: '...', moolSthan: '...' });
const session = getSession();   // { token, user, createdAt }
const valid = isSessionValid(); // true if < 1 hour old
clearSession();                 // Wipes everything

You normally don't need these — BrahmaProvider handles persistence automatically. These are for edge cases only.


API Reference

Backend Routes (Aham Server)

| Method | Route | Auth | Description | |---|---|---|---| | POST | /api/karma/v3/add | Bearer JWT | Add karma (any denom). Writes DB + queues chain. | | GET | /api/karma/v3/balance | Bearer JWT | Get all denom balances with sync status. ?history=true&limit=20 for tx log. | | POST | /api/karma/v3/sync | x-cron-secret | Admin: batch-mint pending karma on-chain. | | GET | /api/tokens/balance | Bearer JWT | Query live on-chain balances for all denoms. | | POST | /api/tokens/distribute | x-cron-secret | Admin: mint specific token amounts to a user. Body: { userId, amounts: { KARMA: 5 } } |


Security

PostMessage Origin Validation

All popup and silent flows use strict origin whitelisting. Only domains matching *.brah.ma and explicitly allowed origins can communicate via postMessage. Wildcard (*) is never used.

JWT Tokens

Session tokens are short-lived JWTs (10 min). They contain atmaSutra and moolSthan claims. Raw private keys or mnemonics are never exposed to the client.

ITP Fallback

Safari and Brave block third-party cookies/iframes. The silent flow auto-degrades to popup when ITP is detected, ensuring auth always works.

Session Storage

Sessions are stored in localStorage with timestamps. BrahmaProvider auto-validates session age on mount and clears expired data.


Full Export Surface

// SSO
useAham, AhamInitiateButton

// Context
BrahmaProvider, useBrahmaContext

// Session & Auth
useBrahmaSession, useBrahmaAPI

// Karma & Tokens
useKarma, useTokens

// Utilities
saveSession, getSession, clearSession, isSessionValid
decodeToken, isTokenExpired, getTokenClaims

// Types
BrahmaConfig, BrahmaContextValue, BrahmaUser, BrahmaSession
BrahmaTokenClaims, AhamFlow, AhamConfig, AhamState
KarmaBalances, KarmaDenomBalance, KarmaHistoryEntry, TokenBalances