77dd5bac82
NestJS 11 runs Express 5, whose default 'simple' query parser ignores nested params like ?metadata[key]=value — so GET /v1/threads silently dropped the metadata filter, causing e.g. an app's "reuse existing thread for this customer" check to match ANY thread. Set the qs-based 'extended' parser. Verified: filtering by a non-existent metadata value now returns 0 (was returning all); the be-crm support smoke goes 12/12 (was 10/12 once a prior thread existed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.7 KiB
TypeScript
38 lines
1.7 KiB
TypeScript
import 'dotenv/config';
|
|
import 'reflect-metadata';
|
|
import { NestFactory } from '@nestjs/core';
|
|
import { ValidationPipe } from '@nestjs/common';
|
|
import { AppModule } from './app.module';
|
|
import { traceMiddleware } from './observability/trace.middleware';
|
|
import { RedisIoAdapter } from './realtime/redis-io.adapter';
|
|
import { PolicyDeniedFilter } from './platform/policy-denied.filter';
|
|
|
|
async function bootstrap(): Promise<void> {
|
|
const app = await NestFactory.create(AppModule, { rawBody: true });
|
|
// Express 5 defaults to the 'simple' query parser, which ignores nested params like
|
|
// ?metadata[key]=value — so generic metadata filters would be silently dropped. Use the
|
|
// qs-based 'extended' parser so those parse into a nested object.
|
|
app.getHttpAdapter().getInstance().set('query parser', 'extended');
|
|
app.use(traceMiddleware); // request-scoped trace context + x-trace-id header (P9)
|
|
app.useGlobalPipes(
|
|
new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true, transform: true }),
|
|
);
|
|
app.useGlobalFilters(new PolicyDeniedFilter()); // fail-closed policy denials → 403
|
|
app.enableCors({ origin: true, credentials: true });
|
|
|
|
// Multi-replica realtime: fan socket.io room emits across instances via Redis.
|
|
// Opt-in — without REDIS_URL the default in-memory adapter is used (single instance).
|
|
if (process.env.REDIS_URL) {
|
|
const redisAdapter = new RedisIoAdapter(app, process.env.REDIS_URL);
|
|
await redisAdapter.connect();
|
|
app.useWebSocketAdapter(redisAdapter);
|
|
}
|
|
|
|
const port = Number(process.env.PORT ?? 3200);
|
|
await app.listen(port);
|
|
// eslint-disable-next-line no-console
|
|
console.log(`iios-service listening on :${port}`);
|
|
}
|
|
|
|
void bootstrap();
|