SPB Git

spb/vquant Public MIT

VibeQuant — AI-powered institutional-grade financial intelligence platform.

TypeScript 84.3% Python 11.7% JavaScript 1.6% CSS 1.5% HTML 0.7%
3.1 KB · 114 lines typescript
Raw Blame History
1/*2 * =============================================================================3 *  VibeQuant (vquant) — AI-Powered Financial Intelligence Platform4 * -----------------------------------------------------------------------------5 *  File:      server/vite.ts6 *7 *  Author:    Simon-Pierre Boucher8 *  Contact:   contact@spboucher.ai9 *  Website:   https://www.spboucher.ai10 *  Demo:      https://www.vquant.ai11 *  License:   MIT (see LICENSE)12 *13 *  Copyright © 2026 Simon-Pierre Boucher. All rights reserved.14 * =============================================================================15 */1617import express, { type Express } from "express";18import fs from "fs";19import path from "path";20import { createServer as createViteServer, createLogger } from "vite";21import { type Server } from "http";22import viteConfig from "../vite.config";23import { nanoid } from "nanoid";2425const viteLogger = createLogger();2627export function log(message: string, source = "express") {28  const formattedTime = new Date().toLocaleTimeString("en-US", {29    hour: "numeric",30    minute: "2-digit",31    second: "2-digit",32    hour12: true,33  });3435  console.log(`${formattedTime} [${source}] ${message}`);36}3738export async function setupVite(app: Express, server: Server) {39  const serverOptions = {40    middlewareMode: true,41    hmr: { server },42    allowedHosts: true as const,43  };4445  const vite = await createViteServer({46    ...viteConfig,47    configFile: false,48    customLogger: {49      ...viteLogger,50      error: (msg, options) => {51        viteLogger.error(msg, options);52        process.exit(1);53      },54    },55    server: serverOptions,56    appType: "custom",57  });5859  app.use(vite.middlewares);60  app.use("*", async (req, res, next) => {61    const url = req.originalUrl;6263    // Filter out system files and hidden files64    if (url.includes('.DS_Store') || /\/\.[\w-]+/.test(url)) {65      return res.status(404).end();66    }6768    // Validate URL encoding to prevent URIError69    try {70      decodeURIComponent(url);71    } catch (e) {72      return res.status(400).send('Invalid URL encoding');73    }7475    try {76      const clientTemplate = path.resolve(77        import.meta.dirname,78        "..",79        "client",80        "index.html",81      );8283      // always reload the index.html file from disk incase it changes84      let template = await fs.promises.readFile(clientTemplate, "utf-8");85      template = template.replace(86        `src="/src/main.tsx"`,87        `src="/src/main.tsx?v=${nanoid()}"`,88      );89      const page = await vite.transformIndexHtml(url, template);90      res.status(200).set({ "Content-Type": "text/html" }).end(page);91    } catch (e) {92      vite.ssrFixStacktrace(e as Error);93      next(e);94    }95  });96}9798export function serveStatic(app: Express) {99  const distPath = path.resolve(import.meta.dirname, "public");100101  if (!fs.existsSync(distPath)) {102    throw new Error(103      `Could not find the build directory: ${distPath}, make sure to build the client first`,104    );105  }106107  app.use(express.static(distPath));108109  // fall through to index.html if the file doesn't exist110  app.use("*", (_req, res) => {111    res.sendFile(path.resolve(distPath, "index.html"));112  });113}114