codalware-auth
Version:
Complete authentication system with enterprise security, attack protection, team workspaces, waitlist, billing, UI components, 2FA, and account recovery - production-ready in 5 minutes. Enhanced CLI with verification, rollback, and App Router scaffolding.
121 lines (101 loc) • 4.34 kB
text/typescript
import type { RegisterData, LoginCredentials } from '../types/auth';
// We import express lazily to avoid forcing consumers to install it at type-check time.
export interface ExpressAdapterOptions {
basePath?: string;
}
type ExpressRequest = {
body?: Record<string, unknown>;
headers?: Record<string, unknown>;
method?: string;
url?: string;
[key: string]: unknown;
};
type ExpressResponse = {
status: (code: number) => ExpressResponse;
json: (payload: unknown) => ExpressResponse;
end?: () => void;
[key: string]: unknown;
};
type ExpressHandler = (req: ExpressRequest, res: ExpressResponse) => unknown | Promise<unknown>;
type ExpressRouter = {
use: (...args: unknown[]) => ExpressRouter;
post: (path: string, handler: ExpressHandler) => ExpressRouter;
get: (path: string, handler: ExpressHandler) => ExpressRouter;
};
type ExpressModule = {
Router: () => ExpressRouter;
json: () => unknown;
};
let cachedExpress: ExpressModule | null = null;
async function loadExpressModule(): Promise<ExpressModule> {
if (cachedExpress) return cachedExpress;
try {
// dynamic import is lint-friendly and won't force consumers to install express at type-check time
// keep the same runtime error behavior if express isn't installed
// @ts-expect-error - Dynamic import of optional peer dependency
const mod = await import('express');
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
cachedExpress = (mod as unknown) as ExpressModule;
return cachedExpress;
} catch {
throw new Error('express is required to use createExpressAuthRouter. Please install express as a dependency in your project.');
}
}
const createForwarder = (modulePath: string): ExpressHandler => {
return async (req, res) => {
try {
const mod = await import(modulePath);
if (typeof mod.default !== 'function') {
return res.status(501).json({ message: 'handler not available' });
}
return mod.default(req, res);
} catch (error) {
console.error('express-adapter forward error for', modulePath, error);
return res.status(501).json({ message: 'handler not available' });
}
};
};
export async function createExpressAuthRouter(options: ExpressAdapterOptions = {}): Promise<ExpressRouter> {
const express = await loadExpressModule();
const router = express.Router();
// express.json() typing isn't imported here; assert and call at runtime
// @ts-expect-error express-json-typing
router.use((express.json as unknown)());
// Register Next.js API handlers via forwarders
router.post('/auth/restore-request', createForwarder('../../pages/api/auth/restore-request'));
router.post('/auth/restore', createForwarder('../../pages/api/auth/restore'));
// Register and login - call core AuthService directly to keep the adapter self-contained
router.post('/auth/register', async (req, res) => {
try {
const { AuthService } = await import('../lib/auth/logic/auth');
const result = await AuthService.register((req.body as unknown) as RegisterData);
return res.status(result.success ? 200 : 400).json(result);
} catch (error) {
console.error('express-adapter register error', error);
return res.status(500).json({ message: 'internal error' });
}
});
router.post('/auth/login', async (req, res) => {
try {
const { AuthService } = await import('../lib/auth/logic/auth');
const result = await AuthService.login((req.body as unknown) as LoginCredentials);
return res.status(result.success ? 200 : 400).json(result);
} catch (error) {
console.error('express-adapter login error', error);
return res.status(500).json({ message: 'internal error' });
}
});
router.post('/webhooks', createForwarder('../../pages/api/webhooks/index'));
router.post('/webhooks/stripe', createForwarder('../../pages/api/webhooks/stripe'));
router.get('/health', (_req, res) => {
res.json({ ok: true, version: 'authcore-express-adapter' });
return res;
});
if (options.basePath) {
const root = express.Router();
root.use(options.basePath, router);
return root;
}
return router;
}
export default createExpressAuthRouter;