// services/api/src/main-ov.ts —— ov-app 部署入口(P2 Task 2 骨架)。与 main-cn // 同库双入口:同一 services/api 代码库按部署角色装配(见 app-ov.module.ts)。 // 复用 configureApp(全局 v1 前缀 / x-powered-by 隐藏 / CORS)——契约「路径前缀 // 不变,部署域名区分」,ov 观众端(viewer :5175,P2 Task 10 切换 VITE_API_BASE // 指向本入口)与 cn viewer 共用 CORS_ORIGINS env,无需 ov 专属配置。env 一律 // 来自进程环境(根 dotenv-cli 注入)。 // Task 7 起:WS 网关与 HTTP **同端口**(契约执行注意:WS 与 HTTP 同端口 // 8081)——ContractWsAdapter 按 realtime.ts 契约帧 {type,...} 分发,网关挂载 // /v1/realtime(REALTIME_WS_PATH),upgrade 请求经适配器路由到 noServer 的 // ws Server,普通 HTTP 路由不受影响。 import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import { type NestExpressApplication } from '@nestjs/platform-express'; import { Logger } from 'nestjs-pino'; import { AppOvModule } from './app-ov.module'; import { ContractWsAdapter } from './realtime/contract-ws.adapter'; import { configureApp } from './shared/configure-app'; async function bootstrap(): Promise { const app = await NestFactory.create(AppOvModule, { bufferLogs: true, // 内部 sync 端点(content-batches)HMAC 验签需要「原始请求体字节」: // rawBody 让 body-parser 在 JSON 解析前把 Buffer 挂到 req.rawBody // (InternalSyncGuard 读取)。发送器对同一字符串只签一次、原样发送。 rawBody: true, }); app.useLogger(app.get(Logger)); // WS 与 HTTP 同端口:网关(@WebSocketGateway 无 port)挂到本应用 HTTP 服务。 app.useWebSocketAdapter(new ContractWsAdapter(app)); configureApp(app); const port = Number.parseInt(process.env.PORT_OV ?? '', 10) || 8081; await app.listen(port); app.get(Logger).log(`api-ov listening on port ${port}`); } void bootstrap();