Repository: n8n-io/n8n
File: packages/cli/src/modules/workflow-index/workflow-index.service.ts (TypeScript)

Code before:
const WORKFLOW_INDEXED_PLACEHOLDER_KEY = '__INDEXED__';

/**
 * Service for managing the workflow dependency index. The index tracks dependencies such as node types,
 * credentials, workflow calls, and webhook paths used by each workflow. The service builds the index on server start
 * and updates it in response to workflow-related events.
 *
 */
@Service()
export class WorkflowIndexService {
	constructor(
		private readonly dependencyRepository: WorkflowDependencyRepository,
		private readonly workflowRepository: WorkflowRepository,
		private readonly eventService: EventService,
		private readonly logger: Logger,
		private readonly errorReporter: ErrorReporter,
		private readonly batchSize = 100,
	) {}

	init() {
		this.eventService.on('server-started', async (): Promise<void> => {
			this.logger.info('Building workflow dependency index...');
			await this.buildIndex().catch((e) => this.errorReporter.error(e));
		});
		this.eventService.on('workflow-created', async ({ workflow }) => {
			await this.updateIndexFor(workflow, /* publishedVersionId= */ null);
		});
		this.eventService.on('workflow-saved', async ({ workflow }) => {
			await this.updateIndexFor(workflow, /* publishedVersionId= */ null);
		});
		this.eventService.on('workflow-deleted', async ({ workflowId }) => {
			await this.dependencyRepository.removeDependenciesForWorkflow(workflowId);
		});
		this.eventService.on('workflow-activated', async ({ workflow }) => {
			await this.updateIndexFor(workflow, workflow.activeVersionId);
		});
	}

	async buildIndex() {
		// Build draft index
		const draftCount = await this.buildIndexInternal(
			async (batchSize) => await this.workflowRepository.findWorkflowsNeedingIndexing(batchSize),
		);

		const publishedCount = await this.buildIndexInternal(
			async (batchSize) =>
				await this.workflowRepository.findWorkflowsNeedingPublishedVersionIndexing(batchSize),
		);

		this.logger.info(
			`Finished building workflow dependency index. Processed ${draftCount} draft workflows, ${publishedCount} published workflows.`,

Review comment (suggestion):
We could also separate this into two different methods: `updateIndexForDraft(workflow)` and `updateIndexForPublished(workflow, workflow.activeVersionId)`. Those can then call the same method then

Code after:
const WORKFLOW_INDEXED_PLACEHOLDER_KEY = '__INDEXED__';

/**
 * Service for managing the workflow dependency index. The index tracks dependencies such as node types,
 * credentials, workflow calls, and webhook paths used by each workflow. The service builds the index on server start
 * and updates it in response to workflow-related events.
 *
 */
@Service()
export class WorkflowIndexService {
	constructor(
		private readonly dependencyRepository: WorkflowDependencyRepository,
		private readonly workflowRepository: WorkflowRepository,
		private readonly eventService: EventService,
		private readonly logger: Logger,
		private readonly errorReporter: ErrorReporter,
		private readonly batchSize = 100,
	) {}

	init() {
		this.eventService.on('server-started', async (): Promise<void> => {
			this.logger.info('Building workflow dependency index...');
			await this.buildIndex().catch((e) => this.errorReporter.error(e));
		});
		this.eventService.on('workflow-created', async ({ workflow }) => {
			await this.updateIndexForDraft(workflow);
		});
		this.eventService.on('workflow-saved', async ({ workflow }) => {
			await this.updateIndexForDraft(workflow);
		});
		this.eventService.on('workflow-deleted', async ({ workflowId }) => {
			await this.dependencyRepository.removeDependenciesForWorkflow(workflowId);
		});
		this.eventService.on('workflow-activated', async ({ workflow }) => {
			if (workflow.activeVersionId === null) {
				this.logger.warn(
					`Workflow ${workflow.id} activated with null activeVersionId. Skipping index update.`,
				);
				return;
			}
			await this.updateIndexForPublished(workflow, workflow.activeVersionId);
		});
	}

	async buildIndex() {
		const draftCount = await this.buildIndexInternal(
			async (batchSize) => await this.workflowRepository.findWorkflowsNeedingIndexing(batchSize),
			'draft',
		);

		const publishedCount = await this.buildIndexInternal(