UNPKG

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
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;