195 lines
7.6 KiB
TypeScript
195 lines
7.6 KiB
TypeScript
import express from "express";
|
|
import cors from "cors";
|
|
import helmet from "helmet";
|
|
import rateLimit from "express-rate-limit";
|
|
import { join } from "path";
|
|
import { cfg } from "./config";
|
|
import { authRouter } from "./routes/auth";
|
|
import { requireAuth } from "./middleware/require-auth";
|
|
import { transceiverRouter } from "./routes/transceivers";
|
|
import { switchRouter } from "./routes/switches";
|
|
import { vendorRouter } from "./routes/vendors";
|
|
import { standardRouter } from "./routes/standards";
|
|
import { healthRouter } from "./routes/health";
|
|
import { hypeCycleRouter } from "./routes/hype-cycle";
|
|
import { searchRouter } from "./routes/search";
|
|
import { documentRouter } from "./routes/documents";
|
|
import { blogRouter } from "./routes/blog";
|
|
import { blogSllRouter } from "./routes/blog-sll";
|
|
import { scraperRouter } from "./routes/scrapers";
|
|
import { finderRouter } from "./routes/finder";
|
|
import { competitorRouter } from "./routes/competitor-alerts";
|
|
import { forecastRouter } from "./routes/forecast";
|
|
import { transportRouter } from "./routes/transport";
|
|
import { datasheetRouter } from "./routes/datasheets";
|
|
import { hotTopicsRouter } from "./routes/hot-topics";
|
|
import { adoptionRouter } from "./routes/adoption";
|
|
import { procurementRouter } from "./routes/procurement";
|
|
import { changelogRouter } from "./routes/changelog";
|
|
import { newsRouter } from "./routes/news";
|
|
import { proxyRouter } from "./routes/proxy";
|
|
import { reviewRouter } from "./routes/review";
|
|
import { stockRouter } from "./routes/stock";
|
|
import { priceComparisonRouter } from "./routes/price-comparison";
|
|
import { selflearningRouter } from "./routes/selflearning";
|
|
import { internalDemandRouter } from "./routes/internal-demand";
|
|
import { formFactorsRouter } from "./routes/form-factors";
|
|
import { tipLlmRouter } from "./routes/tip-llm";
|
|
import { equivalencesRouter } from "./routes/equivalences";
|
|
import { priceHistoryRouter } from "./routes/price-history";
|
|
import { kbRouter } from "./routes/kb";
|
|
import { bulkPriceRouter } from "./routes/bulk-price";
|
|
import { vendorReliabilityRouter } from "./routes/vendor-reliability";
|
|
import { priceForecastRouter } from "./routes/price-forecast";
|
|
import { priceMatrixRouter } from "./routes/price-matrix";
|
|
import { trainingRouter } from "./routes/training";
|
|
import { rfqRouter } from "./routes/rfq";
|
|
import { priceAlertsRouter } from "./routes/price-alerts";
|
|
import { winLossRouter } from "./routes/win-loss";
|
|
import { apiKeysRouter } from "./routes/api-keys";
|
|
import { roiRouter } from "./routes/roi";
|
|
|
|
const app = express();
|
|
|
|
// Trust Cloudflare proxy (required for express-rate-limit with X-Forwarded-For)
|
|
app.set("trust proxy", 1);
|
|
|
|
// Middleware
|
|
app.use(helmet({ contentSecurityPolicy: false }));
|
|
app.use(cors());
|
|
app.use(express.json({ limit: "30mb" })); // 30MB to support base64-encoded PDF uploads
|
|
app.use(
|
|
rateLimit({
|
|
windowMs: 60 * 1000,
|
|
max: 200,
|
|
standardHeaders: true,
|
|
legacyHeaders: false,
|
|
})
|
|
);
|
|
|
|
// Auth (public — no requireAuth here)
|
|
app.use("/api/auth", authRouter);
|
|
|
|
// Proxy public endpoints (register + heartbeat + stats + next — no auth)
|
|
app.use("/api/proxy", proxyRouter);
|
|
|
|
// All other API routes require a valid token
|
|
app.use("/api", (req, res, next) => {
|
|
// Always allow: health check, auth endpoints, proxy public routes, hot-topics (public market data)
|
|
if (req.path.startsWith("/health") || req.path.startsWith("/auth")) return next();
|
|
if (req.path.startsWith("/proxy")) return next();
|
|
if (req.path.startsWith("/hot-topics")) return next();
|
|
if (req.path.startsWith("/price-comparison")) return next();
|
|
if (req.path.startsWith("/training")) return next();
|
|
requireAuth(req, res, next);
|
|
});
|
|
|
|
// Routes
|
|
app.use("/api/transceivers", transceiverRouter);
|
|
app.use("/api/switches", switchRouter);
|
|
app.use("/api/vendors", vendorRouter);
|
|
app.use("/api/standards", standardRouter);
|
|
app.use("/api/health", healthRouter);
|
|
app.use("/api/hype-cycle", hypeCycleRouter);
|
|
app.use("/api/search", searchRouter);
|
|
app.use("/api/documents", documentRouter);
|
|
app.use("/api/blog", blogSllRouter);
|
|
app.use("/api/blog", blogRouter);
|
|
app.use("/api/scrapers", scraperRouter);
|
|
app.use("/api/finder", finderRouter);
|
|
app.use("/api/competitor-alerts", competitorRouter);
|
|
app.use("/api/forecast", forecastRouter);
|
|
app.use("/api/transport", transportRouter);
|
|
app.use("/api/datasheets", datasheetRouter);
|
|
app.use("/api/adoption", adoptionRouter);
|
|
app.use("/api/hot-topics", hotTopicsRouter);
|
|
app.use("/api/procurement", procurementRouter);
|
|
app.use("/api/changelog", changelogRouter);
|
|
app.use("/api/news", newsRouter);
|
|
app.use("/api/review", reviewRouter);
|
|
app.use("/api/stock", stockRouter);
|
|
app.use("/api/price-comparison", priceComparisonRouter);
|
|
app.use("/api/selflearning", selflearningRouter);
|
|
// Form Factors reference
|
|
app.use("/api/form-factors", formFactorsRouter);
|
|
// Internal-only — restricted to localhost / LAN by the router itself
|
|
app.use("/api/internal/demand", internalDemandRouter);
|
|
// tip-llm-v1 guided inference
|
|
app.use("/api/tip-llm", tipLlmRouter);
|
|
// Equivalences (cross-brand alternatives)
|
|
app.use("/api/equivalences", equivalencesRouter);
|
|
// Price history charts
|
|
app.use("/api/price-history", priceHistoryRouter);
|
|
app.use("/api/kb", kbRouter);
|
|
// Bulk price lookup (G)
|
|
app.use("/api/bulk-price", bulkPriceRouter);
|
|
// Vendor reliability scores (I)
|
|
app.use("/api/vendors/reliability", vendorReliabilityRouter);
|
|
// Price forecast (O)
|
|
app.use("/api/price-forecast", priceForecastRouter);
|
|
// Price matrix / heat map (J)
|
|
app.use("/api/price-matrix", priceMatrixRouter);
|
|
// Transceiver Academy — public training content (no auth required)
|
|
app.use("/api/training", trainingRouter);
|
|
// RFQ Analyzer — quote vs market comparison
|
|
app.use("/api/rfq", rfqRouter);
|
|
// Price Alert Subscriptions
|
|
app.use("/api/price-alerts", priceAlertsRouter);
|
|
// Win/Loss Intelligence
|
|
app.use("/api/win-loss", winLossRouter);
|
|
// Customer API Key Management
|
|
app.use("/api/api-keys", apiKeysRouter);
|
|
// ROI Calculator
|
|
app.use("/api/roi", roiRouter);
|
|
|
|
// Dashboard (static HTML)
|
|
app.use("/dashboard", express.static(join(__dirname, "..", "..", "dashboard")));
|
|
|
|
// Root — redirect to dashboard
|
|
app.get("/", (_req, res) => {
|
|
res.redirect("/dashboard/");
|
|
});
|
|
|
|
// API info
|
|
app.get("/api", (_req, res) => {
|
|
res.json({
|
|
name: "Transceiver Intelligence Platform",
|
|
version: "0.3.0",
|
|
endpoints: [
|
|
"GET /api/transceivers?q=&form_factor=&speed=&category=&fiber_type=&wdm_type=&coherent=",
|
|
"GET /api/transceivers/:id",
|
|
"GET /api/switches?q=&category=",
|
|
"GET /api/switches/:id",
|
|
"GET /api/switches/:id/compatibility",
|
|
"GET /api/vendors?type=",
|
|
"GET /api/standards?speed=",
|
|
"GET /api/health",
|
|
"GET /api/hype-cycle",
|
|
"GET /api/hype-cycle/:tech",
|
|
"GET /api/search?q=&collection=&limit=",
|
|
"GET /api/search/products?q=&form_factor=&speed_gbps=&fiber_type=",
|
|
"GET /api/search/documents?q=&doc_type=&vendor=&collection=",
|
|
"GET /api/search/news?q=&source=",
|
|
"GET /api/search/stats",
|
|
"POST /api/documents/process {url, title?, doc_type?, vendor?, collection?}",
|
|
"GET /api/documents",
|
|
"GET /api/documents/:id",
|
|
"POST /api/blog/generate {topic, speed?, form_factor?, use_case?}",
|
|
"GET /api/blog",
|
|
"GET /api/blog/:id",
|
|
"PUT /api/blog/:id/status {status: draft|review|approved|published}",
|
|
"GET /api/selflearning/status",
|
|
"POST /api/selflearning/build",
|
|
"POST /api/selflearning/publish-hf",
|
|
"POST /api/selflearning/train {lane, provider, seed_only?, max_steps?}",
|
|
],
|
|
});
|
|
});
|
|
|
|
// Start
|
|
app.listen(cfg.port, () => {
|
|
console.log(`\n TIP API running on http://localhost:${cfg.port}`);
|
|
console.log(` Environment: ${cfg.nodeEnv}`);
|
|
console.log(` Database: ${cfg.db.host}:${cfg.db.port}/${cfg.db.database}\n`);
|
|
});
|