import 'reflect-metadata'; import { NestFactory } from '@nestjs/core'; import { ValidationPipe } from '@nestjs/common'; import { AppModule } from './app.module.js'; import { APP_ROOT } from './common/app-root.js'; // Read-only Ops Console API (Plan-13 Track 1). Binds loopback by default and refuses a // non-loopback bind under CASAN_PROFILE=prod / CASAN_CP_STRICT=1 — same posture as // dashboard-server.py. Management/auth are out of scope (future tracks). async function bootstrap() { const app = await NestFactory.create(AppModule, { cors: true }); app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true })); const port = Number(process.env.CP_PORT ?? 3010); let host = process.env.CP_BIND ?? '127.0.0.1'; const strict = process.env.CASAN_PROFILE === 'prod' || process.env.CASAN_CP_STRICT === '1'; if (strict && host !== '127.0.0.1' && host !== 'localhost') { // read-only console must not expose telemetry off-loopback without the prod hardening // (TLS/OIDC) that is Track 4 — fail closed. // eslint-disable-next-line no-console console.error(`CP_REFUSE_NONLOOPBACK host=${host} (set up TLS/OIDC per Plan-13 Track 4 first)`); process.exit(2); } await app.listen(port, host); // eslint-disable-next-line no-console console.log(`CASAN Ops Console API (read-only) http://${host}:${port}/api/v1 app_root=${APP_ROOT}`); } bootstrap();