Files
todo-app/apps/api/src/index.ts
Hammer c965fdd06f
All checks were successful
CI/CD / check (push) Successful in 51s
CI/CD / deploy (push) Successful in 1s
fix: resolve TypeScript errors for CI - add auth middleware plugin
- Create shared authMiddleware plugin with scoped derive for proper type propagation
- Each route file now uses authMiddleware instead of relying on parent derive
- Fix error handler to use instanceof Error checks for message/stack access
- Fix null vs undefined type mismatch in hammer route auth validation
- Fix invite role type assertion for enum compatibility
- Fix test type assertions to avoid impossible comparisons
2026-01-30 02:57:07 +00:00

89 lines
2.4 KiB
TypeScript

import { Elysia } from 'elysia';
import { cors } from '@elysiajs/cors';
import { auth } from './lib/auth';
import { authRoutes } from './routes/auth';
import { adminRoutes } from './routes/admin';
import { projectRoutes } from './routes/projects';
import { taskRoutes } from './routes/tasks';
import { labelRoutes } from './routes/labels';
import { commentRoutes } from './routes/comments';
import { hammerRoutes } from './routes/hammer';
const app = new Elysia()
// CORS
.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || [
'http://localhost:5173',
'https://todo.donovankelly.xyz',
],
credentials: true,
exposeHeaders: ['set-auth-token'],
}))
// Health check
.get('/health', () => ({
status: 'ok',
timestamp: new Date().toISOString(),
version: '0.1.0',
}))
// BetterAuth routes (login, register, session, etc.)
.all('/api/auth/*', async ({ request }) => {
return auth.handler(request);
})
// Public auth routes (invite acceptance)
.use(authRoutes)
// Hammer API (uses separate API key auth)
.group('/api', app => app.use(hammerRoutes))
// Authenticated API routes (auth middleware is in each route plugin)
.group('/api', app => app
.use(adminRoutes)
.use(projectRoutes)
.use(taskRoutes)
.use(labelRoutes)
.use(commentRoutes)
)
// Error handler
.onError(({ code, error, set, path }) => {
const message = error instanceof Error ? error.message : String(error);
const stack = error instanceof Error ? error.stack : undefined;
console.error(`[${new Date().toISOString()}] ERROR on ${path}:`, {
code,
message,
stack: process.env.NODE_ENV !== 'production' ? stack : undefined,
});
if (code === 'VALIDATION') {
set.status = 400;
return { error: 'Validation error', details: message };
}
if (message === 'Unauthorized') {
set.status = 401;
return { error: 'Unauthorized' };
}
if (message === 'Admin access required') {
set.status = 403;
return { error: 'Forbidden: Admin access required' };
}
if (message.includes('not found')) {
set.status = 404;
return { error: message };
}
set.status = 500;
return { error: 'Internal server error' };
})
.listen(process.env.PORT || 3001);
console.log(`🚀 Todo API running at ${app.server?.hostname}:${app.server?.port}`);
export type App = typeof app;