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%
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