pulse/modules/formatter/formatter.ts
Edo Limburg 78a2b27f6d feat: implement orchestrator module with feed source management
Add FeedOrchestrator that coordinates fetch→parse→dedup→store pipeline:
- FeedSource type for managing RSS/Atom feed configurations
- Feed source CRUD operations in IStorage interface
- Database schema migration for feed_sources table
- Exponential backoff retry with configurable delays
- Per-feed poll intervals with health tracking
- Concurrency-limited parallel feed processing
- ProcessResult and FeedHealth interfaces for status monitoring

Files added:
- orchestrator/orchestrator.ts - main orchestrator class
- orchestrator/scheduler.ts - backoff calculation utilities
- orchestrator/index.ts - module exports
- orchestrator/orchestrator.test.ts - comprehensive test suite

Files modified:
- interfaces/feed.types.ts - add FeedSource type
- interfaces/storage.interface.ts - extend with feed source methods
- infrastructure/db/database.ts - add FeedSourceTable interface
- infrastructure/db/schema.ts - add feed_sources table migration
- modules/storage/storage.ts - implement feed source CRUD
- modules/storage/storage.test.ts - add feed source tests
2026-05-05 22:17:16 +02:00

50 lines
1.6 KiB
TypeScript

import type { IFormatter, FormatterError, OutputFormat } from '../../interfaces/formatter.interface.js';
import type { FeedItem } from '../../interfaces/feed.types.js';
import { TerminalFormatter } from './terminal.formatter.js';
import { JsonFormatter } from './json.formatter.js';
export class Formatter implements IFormatter {
private terminalFormatter: TerminalFormatter;
private jsonFormatter: JsonFormatter;
constructor() {
this.terminalFormatter = new TerminalFormatter();
this.jsonFormatter = new JsonFormatter();
}
async format(items: FeedItem[], format: OutputFormat): Promise<string> {
try {
switch (format) {
case 'terminal':
return this.terminalFormatter.format(items);
case 'json':
return this.jsonFormatter.format(items);
case 'html':
// HTML not implemented yet per requirements
throw this.createError('UNKNOWN', 'HTML format not implemented');
default:
throw this.createError('SERIALIZE_ERROR', `Unknown format: ${format}`);
}
} catch (error) {
if (this.isFormatterError(error)) {
throw error;
}
throw this.createError('UNKNOWN', error instanceof Error ? error.message : 'Unknown error during formatting');
}
}
private createError(code: FormatterError['code'], message: string): FormatterError {
return { code, message };
}
private isFormatterError(error: unknown): error is FormatterError {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
'message' in error &&
(error as FormatterError).code !== undefined
);
}
}