import 'dotenv/config'; import express, { NextFunction, Request, Response } from "express"; import cors from "cors"; // import bodyParser from "body-parser"; import multer from "multer"; import path from "path"; import fs from "fs"; import { db } from './src/db/db_index'; import { staffUsers, userDetails } from './src/db/schema'; import { eq } from 'drizzle-orm'; import mainRouter from './src/main-router'; import initFunc from './src/lib/init'; import { createExpressMiddleware } from '@trpc/server/adapters/express'; import { appRouter } from './src/trpc/router'; import { TRPCError } from '@trpc/server'; import jwt from 'jsonwebtoken' import signedUrlCache from 'src/lib/signed-url-cache'; import { seed } from 'src/db/seed'; import './src/jobs/jobs-index'; import { startAutomatedJobs } from './src/lib/automatedJobs'; seed() initFunc() startAutomatedJobs() const app = express(); app.use(cors({ origin: 'http://localhost:5174' })); signedUrlCache.loadFromDisk(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Middleware to log all request URLs app.use((req, res, next) => { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] ${req.method} ${req.url}`); next(); }); //cors middleware export function corsMiddleware(req: Request, res: Response, next: NextFunction) { // Allow requests from any origin (for production, replace * with your domain) res.header('Access-Control-Allow-Origin', '*'); // Allow specific headers clients can send res.header( 'Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization' ); // Allow specific HTTP methods res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS'); // Allow credentials if needed (optional) // res.header('Access-Control-Allow-Credentials', 'true'); // Handle preflight (OPTIONS) requests quickly if (req.method === 'OPTIONS') { return res.sendStatus(204); } next(); } app.use('/api/trpc', createExpressMiddleware({ router: appRouter, createContext: async ({ req, res }) => { let user = null; let staffUser = null; const authHeader = req.headers.authorization; if (authHeader?.startsWith('Bearer ')) { const token = authHeader.substring(7); try { const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key') as any; // Check if this is a staff token (has staffId) if (decoded.staffId) { // This is a staff token, verify staff exists const staff = await db.query.staffUsers.findFirst({ where: eq(staffUsers.id, decoded.staffId), }); if (staff) { user=staffUser staffUser = { id: staff.id, name: staff.name, }; } } else { // This is a regular user token user = decoded; // Check if user is suspended const details = await db.query.userDetails.findFirst({ where: eq(userDetails.userId, user.userId), }); if (details?.isSuspended) { throw new TRPCError({ code: 'FORBIDDEN', message: 'Account suspended', }); } } } catch (err) { // Invalid token, both user and staffUser remain null } } return { req, res, user, staffUser }; }, onError({ error, path, type, ctx }) { console.error('🚨 tRPC Error :', { path, type, code: error.code, message: error.message, userId: ctx?.user?.userId, stack: error.stack, }); }, })); app.use('/api', mainRouter) const fallbackUiDirCandidates = [ path.resolve(__dirname, '../fallback-ui/dist'), path.resolve(__dirname, '../../fallback-ui/dist'), path.resolve(process.cwd(), '../fallback-ui/dist'), path.resolve(process.cwd(), './apps/fallback-ui/dist') ] const fallbackUiDir = fallbackUiDirCandidates.find((candidate) => fs.existsSync(candidate)) ?? fallbackUiDirCandidates[0] const fallbackUiIndex = path.join(fallbackUiDir, 'index.html') // const fallbackUiMountPath = '/admin-web' const fallbackUiMountPath = '/'; if (fs.existsSync(fallbackUiIndex)) { app.use(fallbackUiMountPath, express.static(fallbackUiDir)) app.use('/mf'+fallbackUiMountPath, express.static(fallbackUiDir)) const fallbackUiRegex = new RegExp( `^${fallbackUiMountPath.replace(/\//g, '\\/')}(?:\\/.*)?$` ) app.get([fallbackUiMountPath, fallbackUiRegex], (req, res) => { res.sendFile(fallbackUiIndex) }) app.get(/.*/, (req,res) => { res.sendFile(fallbackUiIndex) }) } else { console.warn(`Fallback UI build not found at ${fallbackUiIndex}`) } // Global error handler app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => { console.error(err); const status = err.statusCode || err.status || 500; const message = err.message || 'Internal Server Error'; res.status(status).json({ message }); }); app.listen(4000, () => { console.log("Server is running on http://localhost:4000/api/mobile/"); });