fix: use useFactory returning array + Array.isArray guard for RESULT_PROJECTORS
Some checks failed
Deploy API Server / build-and-unit (push) Successful in 35s
Deploy API Server / current-integration (push) Successful in 30s
Deploy API Server / backward-compat (push) Successful in 0s
Deploy API Server / m-ai-03-synthetic-e2e (push) Failing after 10s
Deploy API Server / deploy (push) Has been skipped

Two changes to fix 'projectors is not iterable' TypeError:

1. ai-job.module.ts: Replace useClass+multi:true with useFactory that
   explicitly returns [p] — avoids NestJS multi-provider array-wrapping
   ambiguity. SyntheticResultProjector back as standalone provider.

2. projection-executor.service.ts: Replace truthiness check with
   Array.isArray() guard for defense-in-depth.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
wangdl 2026-06-21 12:16:40 +08:00
parent 5b0d105788
commit bbac2e358c
2 changed files with 4 additions and 4 deletions

View File

@ -30,7 +30,8 @@ import { SyntheticRegistrationService } from './synthetic-registration.service';
AiJobExecutionEngineImpl, AiJobExecutionEngineImpl,
ProjectionExecutor, ProjectionExecutor,
SyntheticRegistrationService, SyntheticRegistrationService,
{ provide: RESULT_PROJECTORS, useClass: SyntheticResultProjector, multi: true } as any, SyntheticResultProjector,
{ provide: RESULT_PROJECTORS, useFactory: (p: SyntheticResultProjector) => [p], inject: [SyntheticResultProjector] } as any,
{ provide: AI_JOB_EXECUTION_ENGINE, useExisting: AiJobExecutionEngineImpl }, { provide: AI_JOB_EXECUTION_ENGINE, useExisting: AiJobExecutionEngineImpl },
], ],
exports: [ exports: [

View File

@ -28,14 +28,13 @@ export class ProjectionExecutor {
@Inject(RESULT_PROJECTORS) @Inject(RESULT_PROJECTORS)
projectors?: ResultProjector[], projectors?: ResultProjector[],
) { ) {
if (projectors) { const projectorList = Array.isArray(projectors) ? projectors : [];
for (const p of projectors) { for (const p of projectorList) {
if (this.projectorMap.has(p.key)) { if (this.projectorMap.has(p.key)) {
this.logger.warn(`Duplicate projector key "${p.key}" — overwriting`); this.logger.warn(`Duplicate projector key "${p.key}" — overwriting`);
} }
this.projectorMap.set(p.key, p); this.projectorMap.set(p.key, p);
} }
}
this.logger.log( this.logger.log(
`ProjectionExecutor initialized with ${this.projectorMap.size} projector(s): ` + `ProjectionExecutor initialized with ${this.projectorMap.size} projector(s): ` +
`[${Array.from(this.projectorMap.keys()).join(', ') || 'none'}]`, `[${Array.from(this.projectorMap.keys()).join(', ') || 'none'}]`,