import type { Express, Request, Response } from "express"; import { createServer } from "node:http"; import type { Server } from "node:http"; import session from "express-session"; import MemoryStore from "memorystore"; import { SYMBOLS, computeExpirations as mockExpirations, computeGexProfile as mockGexProfile, computeScreener as mockScreener, computeSummary as mockSummary, } from "./marketData"; import { oratsClient } from "./oratsClient"; import { registerAuthRoutes } from "./authRoutes"; import { initDb } from "./db"; const SessionMemoryStore = MemoryStore(session); const KNOWN_TICKERS = new Set(SYMBOLS.map((s) => s.ticker)); function withTicker(req: Request, res: Response, fn: (ticker: string) => unknown) { const raw = String(req.params.symbol || "").toUpperCase(); if (!KNOWN_TICKERS.has(raw)) { res.status(404).json({ error: `Unknown symbol: ${raw}` }); return; } try { res.json(fn(raw)); } catch (err) { res.status(500).json({ error: (err as Error).message }); } } export async function registerRoutes(httpServer: Server, app: Express): Promise { // Initialize database await initDb(); // Session middleware app.use(session({ store: new SessionMemoryStore({ checkPeriod: 86400000 }), secret: process.env.SESSION_SECRET || "gammadesk-dev-secret-change-me", resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === "production", maxAge: 24 * 60 * 60 * 1000, }, })); // Auth routes registerAuthRoutes(app); app.get("/api/symbols", (_req, res) => { res.json(SYMBOLS); }); app.get("/api/orats/status", (_req, res) => { res.json({ configured: oratsClient.isConfigured(), baseUrl: oratsClient.baseUrl, apiKey: oratsClient.apiKey.slice(0, 8) + "...", }); }); // Market data routes - use ORATS when configured, fall back to mocks app.get("/api/market/:symbol/summary", async (req, res) => { const ticker = String(req.params.symbol || "").toUpperCase(); if (!KNOWN_TICKERS.has(ticker)) { return res.status(404).json({ error: `Unknown symbol: ${ticker}` }); } try { const summary = oratsClient.isConfigured() ? await oratsClient.computeSummary(ticker) : mockSummary(ticker); res.json(summary); } catch (err) { console.error(`ORATS summary error for ${ticker}:`, err); res.json(mockSummary(ticker)); // Fallback to mock } }); app.get("/api/market/:symbol/gex", async (req, res) => { const ticker = String(req.params.symbol || "").toUpperCase(); if (!KNOWN_TICKERS.has(ticker)) { return res.status(404).json({ error: `Unknown symbol: ${ticker}` }); } try { const gex = oratsClient.isConfigured() ? await oratsClient.computeGexProfile(ticker) : mockGexProfile(ticker); res.json(gex); } catch (err) { console.error(`ORATS GEX error for ${ticker}:`, err); res.json(mockGexProfile(ticker)); // Fallback to mock } }); app.get("/api/market/:symbol/expirations", async (req, res) => { const ticker = String(req.params.symbol || "").toUpperCase(); if (!KNOWN_TICKERS.has(ticker)) { return res.status(404).json({ error: `Unknown symbol: ${ticker}` }); } try { const exp = oratsClient.isConfigured() ? await oratsClient.computeExpirations(ticker) : mockExpirations(ticker); res.json(exp); } catch (err) { console.error(`ORATS expirations error for ${ticker}:`, err); res.json(mockExpirations(ticker)); // Fallback to mock } }); app.get("/api/screener", async (_req, res) => { try { if (oratsClient.isConfigured()) { // Fetch real data for all symbols const summaries = await Promise.all( SYMBOLS.map(s => oratsClient.computeSummary(s.ticker)) ); const screenerData = summaries.map((summary, i) => { const symbol = SYMBOLS[i]; return { ticker: symbol.ticker, name: symbol.name, spot: summary.spot, spotChangePct: summary.spotChangePct, netGex: summary.netGex, gammaRegime: summary.gammaRegime, ivRank: summary.ivRank, ivx: summary.ivx, callWall: summary.callWall, putWall: summary.putWall, distanceToCallWall: ((summary.callWall - summary.spot) / summary.spot) * 100, distanceToPutWall: ((summary.putWall - summary.spot) / summary.spot) * 100, expectedMovePct: summary.expectedMovePct, skew: summary.skew, zeroDteNetGex: summary.netGex, // Simplified for now }; }); res.json(screenerData); } else { res.json(mockScreener()); } } catch (err) { console.error("ORATS screener error:", err); res.json(mockScreener()); // Fallback to mock } }); return httpServer; }