From 4c37162b55ee48d53f1802768904949dbb4f240d Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Sat, 14 Mar 2026 20:51:28 -0500 Subject: [PATCH] fix(gateway): add missing @Inject() decorators causing silent startup hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tsx/esbuild doesn't support emitDecoratorMetadata, so NestJS can't infer constructor parameter types at runtime. Three services were missing explicit @Inject() decorators: - SummarizationService: EmbeddingService parameter - CronService: SummarizationService parameter - SkillsController: SkillsService parameter Without these, NestJS DI hangs forever during onModuleInit resolution with no error output — the process silently exits (or hangs with a keepAlive). Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/gateway/src/agent/provider.service.ts | 2 +- apps/gateway/src/log/cron.service.ts | 10 ++++++++-- apps/gateway/src/log/summarization.service.ts | 2 +- apps/gateway/src/main.ts | 3 ++- apps/gateway/src/skills/skills.controller.ts | 3 ++- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apps/gateway/src/agent/provider.service.ts b/apps/gateway/src/agent/provider.service.ts index 9e61f24..336f775 100644 --- a/apps/gateway/src/agent/provider.service.ts +++ b/apps/gateway/src/agent/provider.service.ts @@ -8,7 +8,7 @@ export class ProviderService implements OnModuleInit { private readonly logger = new Logger(ProviderService.name); private registry!: ModelRegistry; - async onModuleInit(): Promise { + onModuleInit(): void { const authStorage = AuthStorage.inMemory(); this.registry = new ModelRegistry(authStorage); diff --git a/apps/gateway/src/log/cron.service.ts b/apps/gateway/src/log/cron.service.ts index 536e396..5757131 100644 --- a/apps/gateway/src/log/cron.service.ts +++ b/apps/gateway/src/log/cron.service.ts @@ -1,4 +1,10 @@ -import { Injectable, Logger, type OnModuleInit, type OnModuleDestroy } from '@nestjs/common'; +import { + Inject, + Injectable, + Logger, + type OnModuleInit, + type OnModuleDestroy, +} from '@nestjs/common'; import cron from 'node-cron'; import { SummarizationService } from './summarization.service.js'; @@ -7,7 +13,7 @@ export class CronService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(CronService.name); private readonly tasks: cron.ScheduledTask[] = []; - constructor(private readonly summarization: SummarizationService) {} + constructor(@Inject(SummarizationService) private readonly summarization: SummarizationService) {} onModuleInit(): void { const summarizationSchedule = process.env['SUMMARIZATION_CRON'] ?? '0 */6 * * *'; // every 6 hours diff --git a/apps/gateway/src/log/summarization.service.ts b/apps/gateway/src/log/summarization.service.ts index cd511c9..4cfa02b 100644 --- a/apps/gateway/src/log/summarization.service.ts +++ b/apps/gateway/src/log/summarization.service.ts @@ -29,7 +29,7 @@ export class SummarizationService { constructor( @Inject(LOG_SERVICE) private readonly logService: LogService, @Inject(MEMORY) private readonly memory: Memory, - private readonly embeddings: EmbeddingService, + @Inject(EmbeddingService) private readonly embeddings: EmbeddingService, @Inject(DB) private readonly db: Db, ) { this.apiKey = process.env['OPENAI_API_KEY']; diff --git a/apps/gateway/src/main.ts b/apps/gateway/src/main.ts index b40fd39..a7df855 100644 --- a/apps/gateway/src/main.ts +++ b/apps/gateway/src/main.ts @@ -15,6 +15,8 @@ import { AppModule } from './app.module.js'; import { mountAuthHandler } from './auth/auth.controller.js'; async function bootstrap(): Promise { + const logger = new Logger('Bootstrap'); + if (!process.env['BETTER_AUTH_SECRET']) { throw new Error('BETTER_AUTH_SECRET is required'); } @@ -28,7 +30,6 @@ async function bootstrap(): Promise { ); } - const logger = new Logger('Bootstrap'); const app = await NestFactory.create( AppModule, new FastifyAdapter({ bodyLimit: 1_048_576 }), diff --git a/apps/gateway/src/skills/skills.controller.ts b/apps/gateway/src/skills/skills.controller.ts index 8661db6..48d2b2f 100644 --- a/apps/gateway/src/skills/skills.controller.ts +++ b/apps/gateway/src/skills/skills.controller.ts @@ -5,6 +5,7 @@ import { Get, HttpCode, HttpStatus, + Inject, NotFoundException, Param, Patch, @@ -18,7 +19,7 @@ import type { CreateSkillDto, UpdateSkillDto } from './skills.dto.js'; @Controller('api/skills') @UseGuards(AuthGuard) export class SkillsController { - constructor(private readonly skills: SkillsService) {} + constructor(@Inject(SkillsService) private readonly skills: SkillsService) {} @Get() async list() {