import express from "express"; import helmet from "helmet"; import path from "path"; import { fileURLToPath } from "url"; import rateLimit from "express-rate-limit"; import { convertRouter } from "./routes/convert.js"; import { templatesRouter } from "./routes/templates.js"; import { healthRouter } from "./routes/health.js"; import { signupRouter } from "./routes/signup.js"; import { billingRouter } from "./routes/billing.js"; import { authMiddleware } from "./middleware/auth.js"; import { usageMiddleware } from "./middleware/usage.js"; import { getUsageStats } from "./middleware/usage.js"; import { initBrowser, closeBrowser } from "./services/browser.js"; import { loadKeys, getAllKeys } from "./services/keys.js"; const app = express(); const PORT = parseInt(process.env.PORT || "3100", 10); // Load API keys from persistent store loadKeys(); app.use(helmet()); // Raw body for Stripe webhook signature verification app.use("/v1/billing/webhook", express.raw({ type: "application/json" })); app.use(express.json({ limit: "2mb" })); app.use(express.text({ limit: "2mb", type: "text/*" })); // Rate limiting const limiter = rateLimit({ windowMs: 60_000, max: 100, standardHeaders: true, legacyHeaders: false, }); app.use(limiter); // Public routes app.use("/health", healthRouter); app.use("/v1/signup", signupRouter); app.use("/v1/billing", billingRouter); // Authenticated routes app.use("/v1/convert", authMiddleware, usageMiddleware, convertRouter); app.use("/v1/templates", authMiddleware, usageMiddleware, templatesRouter); // Admin: usage stats app.get("/v1/usage", authMiddleware, (_req, res) => { res.json(getUsageStats()); }); // Landing page const __dirname = path.dirname(fileURLToPath(import.meta.url)); app.use(express.static(path.join(__dirname, "../public"))); // API root app.get("/api", (_req, res) => { res.json({ name: "DocFast API", version: "0.2.0", endpoints: [ "POST /v1/signup/free — Get a free API key", "POST /v1/convert/html", "POST /v1/convert/markdown", "POST /v1/convert/url", "POST /v1/templates/:id/render", "GET /v1/templates", "POST /v1/billing/checkout — Start Pro subscription", ], }); }); async function start() { await initBrowser(); console.log(`Loaded ${getAllKeys().length} API keys`); app.listen(PORT, () => console.log(`DocFast API running on :${PORT}`)); const shutdown = async () => { console.log("Shutting down..."); await closeBrowser(); process.exit(0); }; process.on("SIGTERM", shutdown); process.on("SIGINT", shutdown); } start().catch((err) => { console.error("Failed to start:", err); process.exit(1); }); export { app };