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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@apso/better-auth-adapter

v2.0.2

Published

Better Auth database adapter that interfaces with Apso-generated CRUD REST endpoints

Downloads

274

Readme

Better Auth Apso Adapter

CI/CD Pipeline npm version codecov License: MIT TypeScript npm downloads

A production-ready database adapter for Better Auth that seamlessly interfaces with Apso-generated CRUD REST endpoints. This adapter enables Better Auth to work with any REST API following Apso/nestjsx/crud conventions, providing enterprise-grade authentication for modern applications.

Key Features

  • 🔒 Complete Better Auth Integration - Full compliance with Better Auth adapter interface
  • 🚀 Production-Ready - Built-in retry logic, circuit breakers, and connection pooling
  • ⚡ High Performance - Optimized for speed with caching and batch operations
  • 🔧 TypeScript First - Comprehensive type definitions and strict type checking
  • 📧 Email Normalization - Automatic email processing and validation
  • 🏗️ Multi-Tenant Support - Built-in multi-tenancy with scope isolation
  • 📊 Observability - Comprehensive metrics, tracing, and logging
  • 🛡️ Security Focused - Input validation, sanitization, and secure defaults
  • 🔄 Flexible Configuration - Extensive customization options
  • 📈 Scalable - Connection pooling and bulk operations for high throughput

Installation

npm install @apso/better-auth-adapter
yarn add @apso/better-auth-adapter
pnpm add @apso/better-auth-adapter

Quick Start

import { betterAuth } from 'better-auth';
import { apsoAdapter } from '@apso/better-auth-adapter';

export const auth = betterAuth({
  database: apsoAdapter({
    baseUrl: process.env.APSO_BASE_URL!,
    apiKey: process.env.APSO_API_KEY,
  }),
  emailAndPassword: {
    enabled: true,
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
  },
});

Environment Variables

Create a .env.local file in your project root:

APSO_BASE_URL=https://your-apso-api.com
APSO_API_KEY=your-secret-api-key

Advanced Configuration

Production Setup

import { apsoAdapter } from '@apso/better-auth-adapter';

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  apiKey: process.env.APSO_API_KEY,
  
  // Retry configuration for resilience
  retryConfig: {
    maxRetries: 3,
    initialDelayMs: 1000,
    maxDelayMs: 10000,
    retryableStatuses: [429, 500, 502, 503, 504],
  },
  
  // Performance optimization
  cacheConfig: {
    enabled: true,
    ttlMs: 300000, // 5 minutes
    maxSize: 1000,
  },
  
  // Batch operations
  batchConfig: {
    batchSize: 100,
    concurrency: 5,
    delayBetweenBatches: 100,
  },
  
  // Request timeout
  timeout: 30000, // 30 seconds
  
  // Email normalization
  emailNormalization: true,
  
  // Observability
  observability: {
    metricsEnabled: true,
    tracingEnabled: true,
    logLevel: 'info',
  },
});

Multi-Tenant Configuration

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  apiKey: process.env.APSO_API_KEY,
  
  multiTenancy: {
    enabled: true,
    scopeField: 'tenantId',
    getScopeValue: async () => {
      // Get tenant ID from context, headers, etc.
      return getCurrentTenantId();
    },
  },
});

High-Throughput Setup

import { createHighThroughputApsoAdapter } from '@apso/better-auth-adapter';

const adapter = createHighThroughputApsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  apiKey: process.env.APSO_API_KEY,
  
  // Optimized for high volume
  batchConfig: {
    batchSize: 500,
    concurrency: 10,
  },
  
  // Connection pooling
  fetchImpl: new HttpClient({
    connectionPool: {
      maxConnections: 100,
      maxConnectionsPerHost: 20,
      keepAlive: true,
    },
  }),
});

Framework Integration

Next.js App Router

// app/lib/auth.ts
import { betterAuth } from 'better-auth';
import { apsoAdapter } from '@apso/better-auth-adapter';

export const auth = betterAuth({
  database: apsoAdapter({
    baseUrl: process.env.APSO_BASE_URL!,
    apiKey: process.env.APSO_API_KEY,
  }),
  emailAndPassword: {
    enabled: true,
  },
  trustedOrigins: [process.env.NEXT_PUBLIC_APP_URL!],
});
// app/api/auth/[...auth]/route.ts
import { auth } from '@/lib/auth';

export const { GET, POST } = auth.handler;

Express.js

// server.ts
import express from 'express';
import { betterAuth } from 'better-auth';
import { apsoAdapter } from '@apso/better-auth-adapter';

const app = express();

const auth = betterAuth({
  database: apsoAdapter({
    baseUrl: process.env.APSO_BASE_URL!,
    apiKey: process.env.APSO_API_KEY,
  }),
  emailAndPassword: {
    enabled: true,
  },
});

app.use('/api/auth/*', auth.handler);

API Reference

apsoAdapter(config: ApsoAdapterConfig)

Creates a Better Auth adapter that interfaces with Apso CRUD APIs.

Parameters

| Parameter | Type | Required | Description | |-----------|------|----------|-------------| | baseUrl | string | ✅ | Base URL of your Apso API | | apiKey | string | ❌ | API key for authentication | | timeout | number | ❌ | Request timeout in milliseconds (default: 10000) | | retryConfig | RetryConfig | ❌ | Retry configuration for failed requests | | cacheConfig | CacheConfig | ❌ | Response caching configuration | | batchConfig | BatchConfig | ❌ | Batch operations configuration | | multiTenancy | MultiTenancyConfig | ❌ | Multi-tenancy settings | | observability | ObservabilityConfig | ❌ | Metrics and tracing configuration | | emailNormalization | boolean | ❌ | Enable email normalization (default: true) | | debugMode | boolean | ❌ | Enable debug logging (default: false) |

Specialized Adapters

// Reliable adapter with enhanced retry logic
const reliableAdapter = createReliableApsoAdapter(config);

// High-throughput adapter optimized for performance
const fastAdapter = createHighThroughputApsoAdapter(config);

Health Monitoring

// Check adapter health
const isHealthy = await checkAdapterHealth(adapter);

// Get adapter metrics
const metrics = adapter.getMetrics();
console.log(`Success rate: ${metrics.successfulRequests / metrics.totalRequests * 100}%`);

// Close all adapters (useful for graceful shutdown)
await closeAllAdapters();

Authentication Flows

Email/Password Sign Up

import { auth } from './lib/auth';

// Sign up new user
const result = await auth.api.signUpEmail({
  body: {
    email: '[email protected]',
    password: 'securePassword123',
    name: 'John Doe',
  },
});

if (result.data?.user) {
  console.log('User created:', result.data.user.id);
}

Email/Password Sign In

// Sign in user
const result = await auth.api.signInEmail({
  body: {
    email: '[email protected]',
    password: 'securePassword123',
  },
});

if (result.data?.session) {
  console.log('Session created:', result.data.session.token);
}

Password Reset Flow

// Request password reset
await auth.api.forgetPassword({
  body: {
    email: '[email protected]',
    redirectTo: 'https://yourdomain.com/reset-password',
  },
});

// Reset password with token
await auth.api.resetPassword({
  body: {
    token: 'reset-token',
    password: 'newSecurePassword123',
  },
});

Error Handling

The adapter provides comprehensive error handling with specific error codes:

import { AdapterError, AdapterErrorCode } from '@apso/better-auth-adapter';

try {
  await auth.api.signInEmail({
    body: { email: 'invalid', password: 'wrong' }
  });
} catch (error) {
  if (error instanceof AdapterError) {
    switch (error.code) {
      case AdapterErrorCode.VALIDATION_ERROR:
        console.error('Invalid input:', error.details);
        break;
      case AdapterErrorCode.NOT_FOUND:
        console.error('User not found');
        break;
      case AdapterErrorCode.UNAUTHORIZED:
        console.error('Invalid credentials');
        break;
      case AdapterErrorCode.RATE_LIMIT:
        console.error('Too many requests, retry after:', error.details.retryAfter);
        break;
      default:
        console.error('Unexpected error:', error.message);
    }
  }
}

Performance Optimization

Caching Strategy

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  cacheConfig: {
    enabled: true,
    ttlMs: 600000, // 10 minutes
    maxSize: 2000,
  },
});

// Clear cache when needed
adapter.clearCache();

Batch Operations

// Batch create users
const users = await adapter.createMany({
  model: 'user',
  data: [
    { email: '[email protected]', name: 'User 1' },
    { email: '[email protected]', name: 'User 2' },
    { email: '[email protected]', name: 'User 3' },
  ],
});

Connection Pooling

import { HttpClient } from '@apso/better-auth-adapter';

const httpClient = new HttpClient({
  connectionPool: {
    maxConnections: 50,
    maxConnectionsPerHost: 10,
    keepAlive: true,
    keepAliveTimeout: 30000,
  },
});

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  fetchImpl: httpClient,
});

Security Best Practices

Environment Variables

Never hardcode sensitive values. Always use environment variables:

// ✅ Good
const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  apiKey: process.env.APSO_API_KEY,
});

// ❌ Bad
const adapter = apsoAdapter({
  baseUrl: 'https://api.example.com',
  apiKey: 'secret-key-123',
});

Input Validation

The adapter automatically validates and sanitizes all inputs:

// Email normalization is enabled by default
const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  emailNormalization: true, // Converts emails to lowercase, trims whitespace
});

HTTPS Only

Always use HTTPS endpoints in production:

// ✅ Good
const adapter = apsoAdapter({
  baseUrl: 'https://api.example.com',
});

// ❌ Bad (HTTP in production)
const adapter = apsoAdapter({
  baseUrl: 'http://api.example.com',
});

Monitoring and Observability

Metrics Collection

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  observability: {
    metricsEnabled: true,
    tracingEnabled: true,
    logLevel: 'info',
  },
});

// Get detailed metrics
const metrics = adapter.getMetrics();
console.log({
  totalRequests: metrics.totalRequests,
  successRate: metrics.successfulRequests / metrics.totalRequests,
  averageLatency: metrics.averageLatency,
  p95Latency: metrics.p95Latency,
  cacheHitRate: metrics.cacheHitRate,
});

Custom Logger

import { Logger } from '@apso/better-auth-adapter';

const customLogger: Logger = {
  debug: (message, meta) => console.debug(message, meta),
  info: (message, meta) => console.info(message, meta),
  warn: (message, meta) => console.warn(message, meta),
  error: (message, meta) => console.error(message, meta),
};

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  logger: customLogger,
});

Migration Guide

See our comprehensive Migration Guide for detailed instructions on:

  • Migrating from AWS Cognito
  • Migrating from Prisma adapter
  • Migrating from Drizzle adapter
  • Data export and import procedures

Troubleshooting

Common issues and solutions can be found in our Troubleshooting Guide.

Quick Fixes

Connection timeout errors:

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  timeout: 30000, // Increase timeout to 30 seconds
});

Rate limiting issues:

const adapter = apsoAdapter({
  baseUrl: process.env.APSO_BASE_URL!,
  retryConfig: {
    maxRetries: 5,
    initialDelayMs: 2000,
    maxDelayMs: 30000,
  },
});

Examples

For complete working examples, see:

Contributing

We welcome contributions! Please see our Contributing Guide for details on:

  • Setting up the development environment
  • Running tests and code quality checks
  • Submitting pull requests
  • Code style guidelines

Changelog

See CHANGELOG.md for a detailed history of changes.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Related Projects


Made with ❤️ by the Mavric Team