import type { FastifyInstance, FastifyRequest } from 'fastify'; import { ScreenerEngine } from './ScreenerEngine'; import { CatalystCache } from '../../domains/shared'; import type { LiveAssetResult } from '../../domains/shared'; import { screenSchema } from '../../domains/shared/types/schemas'; export class ScreenerController { constructor( private readonly engine: ScreenerEngine, private readonly catalystCache: CatalystCache, ) {} register(app: FastifyInstance): void { app.post( '/api/screen', { schema: screenSchema, config: { rateLimit: { max: 10, timeWindow: '1 minute' } } }, this.screen.bind(this), ); app.get( '/api/screen/catalysts', { config: { rateLimit: { max: 10, timeWindow: '1 minute' } } }, this.catalysts.bind(this), ); } private static serializeAssets(arr: LiveAssetResult[]) { return arr.map((r) => ({ ...r, asset: { ticker: r.asset.ticker, type: r.asset.type, currentPrice: r.asset.currentPrice, metrics: r.asset.metrics, displayMetrics: r.asset.getDisplayMetrics(), }, })); } private async screen(req: FastifyRequest) { const tickers = (req.body as { tickers: string[] }).tickers.map((t) => t.toUpperCase()); const results = await this.engine.screenTickers(tickers); return { ...results, STOCK: ScreenerController.serializeAssets(results.STOCK as LiveAssetResult[]), ETF: ScreenerController.serializeAssets(results.ETF as LiveAssetResult[]), BOND: ScreenerController.serializeAssets(results.BOND as LiveAssetResult[]), }; } private async catalysts() { const { tickers, stories } = await this.catalystCache.get(); return { tickers, stories }; } }