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

@upvave/hds-auth

v1.1.4

Published

TypeScript auth SDK for connecting Hairdressing School apps to the central HDS Auth Server.

Readme

@upvave/hds-auth

Official TypeScript SDK for connecting Hairdressing School applications to the central HDS Auth Server.

The SDK gives each app a stable auth API while keeping Better Auth and server internals behind the central auth service.

App
-> @upvave/hds-auth
-> Central HDS Auth Server
-> Better Auth

Features

  • Browser login, logout, session refresh, silent auth, SSO exchange, invite, and password flows.
  • React session provider and hooks.
  • Server-side signed requests with HDS_APP_SECRET.
  • User, role, permission, invite, password, and app profile administration APIs.
  • Next.js middleware, route handler, server action, role guard, and permission guard helpers.
  • Clean HdsAuthError values instead of raw auth server errors.
  • ESM-only TypeScript package with generated declarations.

Installation

bun add @upvave/hds-auth
npm install @upvave/hds-auth

For production apps, pin the SDK version explicitly:

{
	"dependencies": {
		"@upvave/hds-auth": "1.0.0"
	}
}

Requirements

  • Node.js >=20.19.0, Bun >=1.3.0, or a compatible Next.js runtime.
  • A central HDS Auth Server reachable over HTTPS.
  • React >=18.2.0 only when using the React hooks/provider.

Package Entrypoints

import { createAuthClient } from '@upvave/hds-auth/client';
import { createAuthServerClient } from '@upvave/hds-auth/server';
import { createNextAuth } from '@upvave/hds-auth/next';

Published subpaths:

  • @upvave/hds-auth
  • @upvave/hds-auth/client
  • @upvave/hds-auth/server
  • @upvave/hds-auth/next
  • @upvave/hds-auth/types
  • @upvave/hds-auth/errors
  • @upvave/hds-auth/utils

Environment

Server-side apps should define:

HDS_AUTH_SERVER_URL=https://auth.example.com
HDS_APP_ID=salma
HDS_APP_SECRET=xxxx

HDS_APP_SECRET is server-only. Never pass it to browser code, React props, client components, public env variables, or bundled frontend code.

Browser Client

Use the client entrypoint in browser code. It requires only the public auth server URL and app id.

import { createAuthClient } from '@upvave/hds-auth/client';

export const auth = createAuthClient({
	authServerUrl: 'https://auth.example.com',
	appId: 'salma',
});

Login and Logout

auth.login({ returnTo: window.location.href });

await auth.logout({
	returnTo: 'https://app.example.com/login',
});

To generate a URL without redirecting:

const loginUrl = auth.login({
	mode: 'url',
	returnTo: 'https://app.example.com/dashboard',
});

Sessions

const session = await auth.getSession();
const currentUser = await auth.getCurrentUser();

await auth.refreshSession();

Silent Auth and SSO

const session = await auth.silentAuthCheck();

if (!session) {
	auth.login({ returnTo: window.location.href });
}
const result = await auth.exchangeSsoToken({
	token: 'sso_token',
	returnTo: 'https://app.example.com/dashboard',
});

console.log(result.session.user.email);

Invite and Password Flows

await auth.verifyInviteToken(token);
await auth.acceptInvite({ token, name, password });
await auth.setInvitePassword({ token, password });

await auth.createResetToken({ email });
await auth.verifyResetToken(token);
await auth.resetPassword({ token, password });
await auth.changePassword({ currentPassword, newPassword });

Email sending stays the responsibility of the app.

React Usage

Wrap the app once with AuthProvider, then read auth state with hooks.

import { AuthProvider, useSession } from '@upvave/hds-auth/client';
import { auth } from './auth';

export function AppProviders({ children }: { children: React.ReactNode }) {
	return <AuthProvider client={auth}>{children}</AuthProvider>;
}

export function AccountMenu() {
	const { user, status } = useSession();

	if (status === 'loading') return null;

	if (!user) {
		return <button onClick={() => auth.login({ returnTo: location.href })}>Login</button>;
	}

	return <button onClick={() => void auth.logout()}>Logout {user.email}</button>;
}

You can also pass a client directly:

const state = useSession(auth);
const user = useUser(auth);
const status = useAuthStatus(auth);

Server Usage

Use the server entrypoint in API routes, backend services, server actions, middleware, and other trusted environments.

import { createAuthServerClient } from '@upvave/hds-auth/server';

const auth = createAuthServerClient();

const session = await auth.requireAuth({
	headers: request.headers,
});

auth.requirePermission(session, 'users:read');

Server calls are signed with HDS_APP_SECRET. The raw secret is never sent as a request header.

User Administration

await auth.addUser(
	{
		email: '[email protected]',
		role: 'stylist',
		permissions: ['appointments:read'],
	},
	{ headers: request.headers },
);

const users = await auth.getUsers({ role: 'stylist', limit: 25 }, { headers: request.headers });
const user = await auth.getUserByEmail('[email protected]', { headers: request.headers });

await auth.updateUser('user_123', { name: 'Senior Stylist' }, { headers: request.headers });
await auth.disableUser('user_123', { headers: request.headers });
await auth.enableUser('user_123', { headers: request.headers });
await auth.removeUserFromApp('user_123', { headers: request.headers });
await auth.deleteUser('user_123', { headers: request.headers });

Roles and Permissions

await auth.updateUserRole('user_123', 'manager', { headers: request.headers });

await auth.updateUserPermissions(
	{
		userId: 'user_123',
		permissions: ['users:read', 'appointments:write'],
	},
	{ headers: request.headers },
);

const canReadUsers = auth.hasPermission(session, 'users:read');
const isOwner = auth.hasRole(session, 'owner');

App Profiles

const profile = await auth.getAppProfile('user_123', { headers: request.headers });

await auth.updateAppProfile(
	{
		userId: 'user_123',
		data: {
			locationId: 'loc_1',
			department: 'color',
		},
	},
	{ headers: request.headers },
);

const access = await auth.getUserAppAccess('user_123', { headers: request.headers });

Invites and Passwords

const invite = await auth.createInvite(
	{
		email: '[email protected]',
		role: 'stylist',
		permissions: ['appointments:read'],
	},
	{ headers: request.headers },
);

await auth.verifyInviteToken(invite.token, { headers: request.headers });
await auth.setInvitePassword({ token: invite.token, password }, { headers: request.headers });

const reset = await auth.createResetToken({ email: '[email protected]' }, { headers: request.headers });
await auth.resetPassword({ token: reset.token, password }, { headers: request.headers });

Next.js Usage

Use @upvave/hds-auth/next in App Router middleware, route handlers, and server actions.

Middleware

import { createNextAuth } from '@upvave/hds-auth/next';

const auth = createNextAuth();

export async function middleware(request: Request) {
	return auth.middleware(request);
}

Route Handlers

import { createNextAuth } from '@upvave/hds-auth/next';

const auth = createNextAuth();

export const GET = auth.routeHandler(
	async ({ request, client }) => {
		const users = await client.getUsers({}, { headers: request.headers });
		return Response.json(users);
	},
	{ permission: 'users:read' },
);

Server Actions

'use server';

import { headers } from 'next/headers';
import { createNextAuth } from '@upvave/hds-auth/next';

const auth = createNextAuth();

const updateRoleWithAuth = auth.serverAction(
	async ({ client }, userId: string, role: string) => {
		await client.updateUserRole(userId, role, { headers: await headers() });
	},
	{ permission: 'users:write' },
);

export async function updateRole(userId: string, role: string) {
	return updateRoleWithAuth({ headers: await headers() }, userId, role);
}

Error Handling

SDK errors are normalized as HdsAuthError.

import { HdsAuthError, isHdsAuthError } from '@upvave/hds-auth/errors';

try {
	await auth.requireAuth({ headers: request.headers });
} catch (error) {
	if (isHdsAuthError(error)) {
		console.log(error.code, error.status, error.message);
	}
}

Common error codes:

  • AUTH_REQUIRED
  • INVALID_APP_SECRET
  • INVITE_TOKEN_EXPIRED
  • RESET_TOKEN_EXPIRED
  • NO_APP_ACCESS
  • PERMISSION_DENIED
  • SESSION_EXPIRED
  • INVALID_TOKEN
  • USER_NOT_FOUND
  • RATE_LIMITED
  • CONFIGURATION_ERROR
  • NETWORK_ERROR
  • AUTH_SERVER_ERROR

User Guidelines

For App Developers

  • Install only @upvave/hds-auth; do not configure Better Auth directly in apps.
  • Use @upvave/hds-auth/client only in browser code.
  • Use @upvave/hds-auth/server only in trusted server code.
  • Use @upvave/hds-auth/next for Next.js middleware, route handlers, and server actions.
  • Always pass incoming request.headers to server calls when user context matters.
  • Treat HDS_APP_SECRET as a secret. Do not expose it through NEXT_PUBLIC_*, client props, logs, or error payloads.
  • Use requireAuth, requireRole, and requirePermission at server boundaries before sensitive actions.
  • Keep email sending in the app. The SDK can create or verify tokens, but it does not send email.
  • Pin SDK versions in production apps and upgrade intentionally.

For Auth Server Developers

  • Keep endpoint contracts stable for existing SDK versions.
  • Return clean error payloads with { code, message, details } where possible.
  • Do not rely on apps sending raw app secrets. Server SDK requests are signed.
  • Add audit logs for sensitive operations such as user changes, role updates, password resets, and invite acceptance.

Security Checklist

  • Use HTTPS for HDS_AUTH_SERVER_URL outside localhost development.
  • Rotate HDS_APP_SECRET if it may have been exposed.
  • Keep permissions app-specific and least-privilege.
  • Avoid storing plain tokens longer than needed.
  • Review all route handlers and server actions for explicit auth guards.

Development

bun install
bun run lint
bun run typecheck
bun run test
bun run build
bun run check

The package is ESM-only, strict TypeScript, and targets Node.js >=20.19.0.

Publishing

Automated releases run from GitHub Actions when a stable version tag is pushed:

git tag v1.2.3
git push origin v1.2.3

The workflow updates package.json to 1.2.3, commits that version back to the default branch, verifies the package, and publishes it to npm.

For private GitHub repositories, configure an npm automation token as the GitHub Actions secret NPM_TOKEN before using the automated release workflow.

Before publishing:

bun run check
npm pack --dry-run
npm publish --access public

For a public GitHub source repository where provenance is available:

npm publish --access public --provenance

Release checklist:

  • Keep package.json version aligned with the intended release.
  • Keep public subpath exports aligned with the README entrypoints.
  • Confirm files only includes dist, README.md, and LICENSE.
  • Keep HDS_APP_SECRET server-only in examples and docs.
  • Run npm pack --dry-run and inspect the tarball before publishing.
  • Pin app installs to an exact SDK version for production apps.

Use Changesets for version bumps:

bun run changeset
bun run version

License

Public source, personal-use license. This package is not private, but it is not open source under an OSI-approved license.

Personal, educational, evaluation, and non-commercial use is allowed. Commercial, production, organization, agency, client, enterprise, hosted, SaaS, resale, or redistributed use requires separate written permission from Upvave.

See LICENSE.