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

@dcimorra/authhub-sdk

v1.4.0

Published

Official TypeScript SDK for Auth Hub — self-hosted authentication, OAuth social login, webhooks, realtime subscriptions, database, schema management, and storage as a service

Readme

@dcimorra/authhub-sdk

Official TypeScript SDK for Auth Hub — self-hosted authentication, database, schema management, storage, OAuth, realtime subscriptions, and cookie-based sessions as a service.

Install

npm install @dcimorra/authhub-sdk

Or copy the sdk/ directory into your project and import from it directly.

Quick Start

import { AuthHubClient } from "@dcimorra/authhub-sdk";

const hub = new AuthHubClient({
  baseUrl: "https://auth.example.com",
  projectId: "your-project-uuid",
  apiKey: "sk_your_api_key",
});

Authentication

// Register
await hub.auth.register("[email protected]", "securePassword123");

// Login — tokens are stored automatically
const { user } = await hub.auth.login("[email protected]", "securePassword123");

// Get current user (auto-refreshes token if expired)
const me = await hub.auth.getUser();

// Change password
await hub.auth.changePassword("oldPassword", "newPassword");

// Password recovery flow
await hub.auth.recover("[email protected]");
// User receives email with token...
await hub.auth.resetPassword(tokenFromEmail, "newPassword");

// Logout — clears tokens locally and revokes on server
await hub.auth.logout();

// Check auth state
const isLoggedIn = await hub.auth.isAuthenticated();

Token Management

Tokens are automatically stored and refreshed. You can customize the storage:

// Browser (default): localStorage
const hub = new AuthHubClient({ ..., tokenStore: "localStorage" });

// Node.js (default): in-memory
const hub = new AuthHubClient({ ..., tokenStore: "memory" });

// Custom store (e.g. React Native AsyncStorage)
const hub = new AuthHubClient({
  ...,
  tokenStore: {
    get: (key) => AsyncStorage.getItem(key),
    set: (key, value) => AsyncStorage.setItem(key, value),
    remove: (key) => AsyncStorage.removeItem(key),
  },
});

// Handle session expiry (refresh token expired/revoked)
const hub = new AuthHubClient({
  ...,
  onSessionExpired: () => {
    window.location.href = "/login";
  },
});

Session (Cookie-Based SSR Auth)

For server-side apps like Next.js where you need cookie-based sessions instead of token-based auth:

// Login — returns the user and Set-Cookie headers to forward to the browser
const { user, setCookieHeaders } = await hub.session.login(email, password);
const response = NextResponse.json({ success: true });
for (const h of setCookieHeaders) response.headers.append("Set-Cookie", h);

// Validate a session by forwarding browser cookies
const cookieHeader = request.headers.get("cookie") || "";
const user = await hub.session.validate(cookieHeader); // User | null

// Logout — returns Set-Cookie headers that clear the session cookies
const setCookieHeaders = await hub.session.logout(cookieHeader);
const response = NextResponse.json({ success: true });
for (const h of setCookieHeaders) response.headers.append("Set-Cookie", h);

// Change password via session cookies
await hub.session.changePassword(cookieHeader, "oldPassword", "newPassword");

Database

Full CRUD with advanced query operators.

// Insert
const { rows } = await hub.db.create({
  table: "products",
  data: { name: "Widget", price: 29.99, active: true },
});

// Query with operators
const { rows, count } = await hub.db.read({
  table: "products",
  select: ["id", "name", "price"],
  where: {
    price: { $gte: 10, $lte: 100 },
    status: { $in: ["active", "sale"] },
    deleted_at: { $is: null },
  },
  orderBy: [
    { column: "price", order: "ASC" },
    { column: "name", order: "DESC" },
  ],
  limit: 50,
  offset: 0,
});

// Update
await hub.db.update({
  table: "products",
  data: { price: 24.99 },
  where: { id: 1 },
});

// Delete
await hub.db.delete({
  table: "products",
  where: { active: false },
});

// Convenience methods
const product = await hub.db.findById("products", 1);
const user = await hub.db.findOne("users", { email: "[email protected]" });
const total = await hub.db.count("products", { active: true });

Query Operators

| Operator | SQL | Example | |----------|-----|---------| | $eq | = | { status: { $eq: "active" } } | | $neq | != | { role: { $neq: "admin" } } | | $gt | > | { price: { $gt: 10 } } | | $gte | >= | { age: { $gte: 18 } } | | $lt | < | { stock: { $lt: 5 } } | | $lte | <= | { priority: { $lte: 3 } } | | $in | IN (...) | { status: { $in: ["a", "b"] } } | | $nin | NOT IN (...) | { id: { $nin: [1, 2, 3] } } | | $like | LIKE | { name: { $like: "%widget%" } } | | $ilike | ILIKE | { name: { $ilike: "%Widget%" } } | | $is | IS | { deleted_at: { $is: null } } | | $not | IS NOT | { email: { $not: null } } |

Schema Management (DDL)

Create and modify tables, columns, and constraints remotely via the API. Each project gets its own isolated PostgreSQL database.

// List all tables
const { tables } = await hub.schema.listTables();
// => ["articles", "comments"]

// Create a table (comes with `id SERIAL PRIMARY KEY` and `created_at TIMESTAMP`)
await hub.schema.createTable("articles");

// Get table details (columns + constraints)
const info = await hub.schema.getTable("articles");
console.log(info.columns);     // SchemaColumn[]
console.log(info.constraints); // SchemaConstraint[]

// Add columns
await hub.schema.addColumn("articles", {
  column: "title",
  type: "TEXT",
  nullable: false,
});

await hub.schema.addColumn("articles", {
  column: "status",
  type: "TEXT",
  nullable: false,
  default: "draft",
});

await hub.schema.addColumn("articles", {
  column: "updated_at",
  type: "TIMESTAMP",
  default: "CURRENT_TIMESTAMP",
});

// Rename a column
await hub.schema.renameColumn("articles", {
  column: "title",
  newName: "headline",
});

// Drop a column (cannot drop system columns: id, created_at, updated_at)
await hub.schema.dropColumn("articles", "old_field");

// Add a unique constraint
await hub.schema.addConstraint("articles", {
  constraintType: "unique",
  columns: ["slug"],
  name: "uq_articles_slug", // optional, auto-generated if omitted
});

// Add a foreign key
await hub.schema.addConstraint("comments", {
  constraintType: "foreign_key",
  columns: ["article_id"],
  referencedTable: "articles",
  referencedColumns: ["id"],
  onDelete: "CASCADE",
  onUpdate: "NO ACTION",
});

// Drop a constraint
await hub.schema.dropConstraint("articles", "uq_articles_slug");

// Drop a table (CASCADE)
await hub.schema.dropTable("old_table");

Supported Column Types

TEXT, INTEGER, BIGINT, SMALLINT, REAL, DOUBLE PRECISION, BOOLEAN, DATE, TIME, TIMESTAMP, NUMERIC, DECIMAL, VARCHAR, CHAR

Supported Foreign Key Actions

NO ACTION, RESTRICT, CASCADE, SET NULL, SET DEFAULT

Storage

File upload, download, and bucket management.

// Create a bucket
await hub.storage.createBucket({
  name: "avatars",
  isPublic: true,
  maxFileSize: 5 * 1024 * 1024, // 5MB
});

// Upload a file (browser)
const fileInput = document.querySelector<HTMLInputElement>("#file");
await hub.storage.upload({
  bucket: "avatars",
  key: "users/user1.jpg",
  file: fileInput.files[0],
});

// Upload from Node.js
import { readFileSync } from "fs";
await hub.storage.upload({
  bucket: "avatars",
  key: "users/user1.jpg",
  file: readFileSync("photo.jpg"),
  contentType: "image/jpeg",
});

// Download
const response = await hub.storage.download("avatars", "users/user1.jpg");
const blob = await response.blob(); // browser
// or
const buffer = await hub.storage.downloadBuffer("avatars", "users/user1.jpg");

// Public URL (for <img src=...> etc.)
const url = hub.storage.getPublicUrl("avatars", "users/user1.jpg");

// List files
const { objects, count } = await hub.storage.list({
  bucket: "avatars",
  prefix: "users/",
  limit: 50,
});

// Delete
await hub.storage.deleteObject("avatars", "users/user1.jpg");

// Bucket management
const buckets = await hub.storage.listBuckets();
await hub.storage.deleteBucket("old-bucket");

OAuth

Social login with Google and GitHub.

// Get the OAuth URL and redirect the user
const url = hub.oauth.getAuthUrl("google", "/dashboard");
window.location.href = url;

// Or use the convenience method (browser only)
hub.oauth.signInWithProvider("github", "/dashboard");

// After the redirect, parse tokens from the URL hash
const result = await hub.oauth.handleCallback();
if (result) {
  console.log(result.provider);     // "google" | "github"
  console.log(result.access_token); // tokens are also stored automatically
}

Realtime

Subscribe to database mutations via WebSocket.

// Create a realtime client
const realtime = hub.realtime("wss://auth.example.com");

// Connect and authenticate
const accessToken = await hub.auth.getAccessToken();
await realtime.connect(accessToken);

// Subscribe to table changes
realtime.on("table:users", (event, data) => {
  console.log(event); // "INSERT" | "UPDATE" | "DELETE"
  console.log(data);  // { table, operation, id, timestamp }
});

// Subscribe with confirmation
await realtime.subscribe("table:orders", (event, data) => {
  console.log("Order changed:", event, data);
});

// Unsubscribe
realtime.unsubscribe("table:users");

// Remove a specific handler
realtime.off("table:orders", myHandler);

// Check connection state
console.log(realtime.isConnected());

// Close when done
realtime.close();

Error Handling

All methods throw AuthHubError on failure:

import { AuthHubError } from "@dcimorra/authhub-sdk";

try {
  await hub.auth.login("[email protected]", "wrong-password");
} catch (err) {
  if (err instanceof AuthHubError) {
    console.log(err.message); // "Invalid credentials"
    console.log(err.status);  // 401
    console.log(err.code);    // optional error code
  }
}

Build from Source

cd sdk
npm install
npm run build

This produces dist/ with CJS, ESM, and type declarations.