Files
trueref-legacy/src/hooks.server.ts
Giancarmine Salucci 956b2a3a62 feat(TRUEREF-0009): implement indexing pipeline and job queue
Implements the end-to-end indexing pipeline with a SQLite-backed job
queue, startup recovery, and REST API endpoints for job status.

- IndexingPipeline: orchestrates crawl → parse → atomic replace → embed
  → repo stats update with progress tracking at each stage
- JobQueue: sequential SQLite-backed queue (no external broker), deduplicates
  active jobs per repository, drains queued jobs on startup
- startup.ts: stale job recovery (running→failed), repo state reset, singleton
  initialization wired from hooks.server.ts
- GET /api/v1/jobs with repositoryId/status/limit filtering
- GET /api/v1/jobs/[id] single job lookup
- hooks.server.ts: initializes DB and pipeline on server start
- 18 unit tests covering queue, pipeline stages, recovery, and atomicity

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:22:20 +01:00

73 lines
2.5 KiB
TypeScript

/**
* SvelteKit server hooks (TRUEREF-0009).
*
* Runs once when the Node.js server process starts. Initialises the database
* and kicks off the indexing pipeline + job queue so queued jobs resume
* automatically after a restart.
*/
import { initializeDatabase } from '$lib/server/db/index.js';
import { getClient } from '$lib/server/db/client.js';
import { initializePipeline } from '$lib/server/pipeline/startup.js';
import { EMBEDDING_CONFIG_KEY, createProviderFromConfig, defaultEmbeddingConfig } from '$lib/server/embeddings/factory.js';
import { EmbeddingService } from '$lib/server/embeddings/embedding.service.js';
import type { EmbeddingConfig } from '$lib/server/embeddings/factory.js';
import type { Handle } from '@sveltejs/kit';
// ---------------------------------------------------------------------------
// Server initialisation — runs once on startup
// ---------------------------------------------------------------------------
try {
initializeDatabase();
const db = getClient();
// Load persisted embedding configuration (if any).
const configRow = db
.prepare<[string], { value: string }>(`SELECT value FROM settings WHERE key = ?`)
.get(EMBEDDING_CONFIG_KEY);
let embeddingService: EmbeddingService | null = null;
if (configRow) {
try {
const config: EmbeddingConfig =
typeof configRow.value === 'string'
? JSON.parse(configRow.value)
: (configRow.value as EmbeddingConfig);
if (config.provider !== 'none') {
const provider = createProviderFromConfig(config);
embeddingService = new EmbeddingService(db, provider);
}
} catch (err) {
console.warn(
`[hooks.server] Could not load embedding config: ${err instanceof Error ? err.message : String(err)}`
);
}
} else {
// Use the default (noop) config so the pipeline is still wired up.
const config = defaultEmbeddingConfig();
if (config.provider !== 'none') {
const provider = createProviderFromConfig(config);
embeddingService = new EmbeddingService(db, provider);
}
}
initializePipeline(db, embeddingService);
console.log('[hooks.server] Indexing pipeline initialised.');
} catch (err) {
console.error(
`[hooks.server] Failed to initialise server: ${err instanceof Error ? err.message : String(err)}`
);
}
// ---------------------------------------------------------------------------
// Request handler (pass-through)
// ---------------------------------------------------------------------------
export const handle: Handle = async ({ event, resolve }) => {
return resolve(event);
};