import express from "express"; import ViteExpress from "vite-express"; import cors from "cors"; import dotenv from "dotenv"; import apiRoutes from "./server/api/index.js"; import { pouchApp, PouchDB } from "./server/services/databaseService.js"; import { dbAuthMiddleware } from "./server/middleware/dbAuth.js"; // Load .env.local first, then fall back to .env dotenv.config({ path: '.env.local' }); dotenv.config(); const app = express(); // CORS configuration for split deployment // In combined mode, same-origin requests don't need CORS const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(",") || []; if (allowedOrigins.length > 0) { app.use(cors({ origin: allowedOrigins, credentials: true, })); } // Parse JSON for all routes EXCEPT /pouchdb (express-pouchdb handles its own body parsing) app.use((req, res, next) => { if (req.path.startsWith('/pouchdb')) { return next(); } express.json()(req, res, next); }); // API routes app.use("/api", apiRoutes); // Test endpoint to verify PouchDB is working app.get("/pouchdb-test/:dbname", async (req, res) => { try { const dbName = req.params.dbname; console.log(`[Test] Creating database: ${dbName}`); const db = new PouchDB(dbName); const info = await db.info(); console.log(`[Test] Database info:`, info); // Try to add a test doc const result = await db.put({ _id: 'test-doc', hello: 'world' }); console.log(`[Test] Added doc:`, result); // Read it back const doc = await db.get('test-doc'); console.log(`[Test] Got doc:`, doc); res.json({ success: true, info, doc }); } catch (err) { console.error(`[Test] Error:`, err); res.status(500).json({ error: err.message, stack: err.stack }); } }); // PouchDB database sync endpoint with auth middleware // Public databases (/pouchdb/public-*) are accessible without auth // Private databases (/pouchdb/private-*) require authentication // Patch req.query for Express 5 compatibility with express-pouchdb app.use("/pouchdb", dbAuthMiddleware, (req, res, next) => { // Express 5 makes req.query read-only, but express-pouchdb needs to write to it // Redefine as writable property Object.defineProperty(req, 'query', { value: { ...req.query }, writable: true, configurable: true }); next(); }, pouchApp, (err, req, res, next) => { // Error handler for express-pouchdb console.error('[PouchDB Error]', err); res.status(500).json({ error: err.message, stack: err.stack }); }); // Check if running in API-only mode (split deployment) const apiOnly = process.env.API_ONLY === "true"; if (apiOnly) { // API-only mode: no static file serving app.listen(process.env.PORT || 3000, () => { console.log(`API server running on port ${process.env.PORT || 3000}`); }); } else { // Combined mode: Vite handles static files + SPA ViteExpress.listen(app, process.env.PORT || 3001, () => { console.log(`Server running on port ${process.env.PORT || 3001}`); }); }