Split monolithic chat service into modular structure with Matrix client support, extract web server into per-resource route modules, introduce bootstrap/main-loop separation, and add comprehensive vitest coverage across services, repositories, and utilities. Adds project docs and CLAUDE.md agent instructions.
92 lines
2.6 KiB
TypeScript
92 lines
2.6 KiB
TypeScript
import Database from 'better-sqlite3';
|
|
import type { Config } from '../src/config/index.js';
|
|
import { runMigrations } from '../src/database/client.js';
|
|
import { PostsRepository, MessagesRepository, SuccessfulMessagesRepository } from '../src/database/repositories.js';
|
|
|
|
export function createTestDb(): Database.Database {
|
|
const db = new Database(':memory:');
|
|
db.pragma('journal_mode = WAL');
|
|
// Disable FK for tests - we manage referential integrity manually
|
|
db.pragma('foreign_keys = OFF');
|
|
runMigrations(db);
|
|
return db;
|
|
}
|
|
|
|
export function createTestRepositories(db?: Database.Database) {
|
|
const database = db || createTestDb();
|
|
return {
|
|
postsRepo: new PostsRepository(database),
|
|
messagesRepo: new MessagesRepository(database),
|
|
successfulMessagesRepo: new SuccessfulMessagesRepository(database),
|
|
db,
|
|
};
|
|
}
|
|
|
|
export function getTestConfig(overrides?: Partial<Config>): Config {
|
|
return {
|
|
reddit: {
|
|
subreddits: [
|
|
{ name: 'test1', type: 'image' as const },
|
|
{ name: 'test2', type: 'image' as const },
|
|
],
|
|
pollIntervalMs: 1000,
|
|
userAgent: 'TestBot/1.0',
|
|
targetGenders: ['female'],
|
|
filterSellers: true,
|
|
sellerKeywords: ['onlyfans', 'fansly'],
|
|
...overrides?.reddit,
|
|
},
|
|
openrouter: {
|
|
apiKey: 'test-key',
|
|
imageAnalysisModel: 'google/gemini-flash',
|
|
imageAnalysisFallbackModels: ['fallback-model'],
|
|
chatModel: 'chat-model',
|
|
chatFallbackModels: [],
|
|
imageAnalysisPrompt: 'Analyze this image',
|
|
messageGenerationPrompt: 'Generate a message for {analysis}',
|
|
chatOpenerPrompt: 'Chat opener for {title} {selftext} {author} {gender}',
|
|
...overrides?.openrouter,
|
|
},
|
|
rateLimit: {
|
|
minDelayBetweenMessagesMs: 1000,
|
|
maxMessagesPerHour: 10,
|
|
jitterMs: 500,
|
|
...overrides?.rateLimit,
|
|
},
|
|
browser: {
|
|
sessionDir: './data/browser-session',
|
|
headless: true,
|
|
dryRun: false,
|
|
...overrides?.browser,
|
|
},
|
|
database: {
|
|
path: './data/test.db',
|
|
...overrides?.database,
|
|
},
|
|
media: {
|
|
syncIntervalMs: 1800000,
|
|
syncEnabled: true,
|
|
},
|
|
strategies: {
|
|
explorationRate: 0.2,
|
|
minSamples: 5,
|
|
variants: [
|
|
{ id: 'variant-a', weight: 1, promptOverride: 'Be direct' },
|
|
{ id: 'variant-b', weight: 1, promptOverride: 'Be teasing' },
|
|
],
|
|
...overrides?.strategies,
|
|
},
|
|
chatStrategies: {
|
|
explorationRate: 0.2,
|
|
minSamples: 5,
|
|
variants: [],
|
|
...overrides?.chatStrategies,
|
|
},
|
|
web: {
|
|
enabled: true,
|
|
port: 3000,
|
|
...overrides?.web,
|
|
},
|
|
};
|
|
}
|