118 lines
3.7 KiB
TypeScript
118 lines
3.7 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 { createProviderFromProfile } from '$lib/server/embeddings/registry.js';
|
|
import { EmbeddingService } from '$lib/server/embeddings/embedding.service.js';
|
|
import {
|
|
EmbeddingProfileEntity,
|
|
type EmbeddingProfileEntityProps
|
|
} from '$lib/server/models/embedding-profile.js';
|
|
import { EmbeddingProfileMapper } from '$lib/server/mappers/embedding-profile.mapper.js';
|
|
import { env } from '$env/dynamic/private';
|
|
import type { Handle } from '@sveltejs/kit';
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Server initialisation — runs once on startup
|
|
// ---------------------------------------------------------------------------
|
|
|
|
try {
|
|
initializeDatabase();
|
|
} catch (err) {
|
|
console.error('[hooks.server] FATAL: database initialisation failed:', err);
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
const db = getClient();
|
|
const activeProfileRow = db
|
|
.prepare<[], EmbeddingProfileEntityProps>(
|
|
'SELECT * FROM embedding_profiles WHERE is_default = 1 AND enabled = 1 LIMIT 1'
|
|
)
|
|
.get();
|
|
|
|
let embeddingService: EmbeddingService | null = null;
|
|
|
|
if (activeProfileRow) {
|
|
const activeProfile = EmbeddingProfileMapper.fromEntity(
|
|
new EmbeddingProfileEntity(activeProfileRow)
|
|
);
|
|
const provider = createProviderFromProfile(activeProfile);
|
|
embeddingService = new EmbeddingService(db, provider, activeProfile.id);
|
|
}
|
|
|
|
// Read database path from environment
|
|
const dbPath = env.DATABASE_URL;
|
|
|
|
// Read indexing concurrency setting from database
|
|
let concurrency = 2; // default
|
|
if (dbPath) {
|
|
const concurrencyRow = db
|
|
.prepare<[], { value: string }>(
|
|
"SELECT value FROM settings WHERE key = 'indexing.concurrency' LIMIT 1"
|
|
)
|
|
.get();
|
|
if (concurrencyRow) {
|
|
try {
|
|
const parsed = JSON.parse(concurrencyRow.value);
|
|
concurrency = parsed.value ?? 2;
|
|
} catch {
|
|
// If parsing fails, use default
|
|
concurrency = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
initializePipeline(db, embeddingService, { concurrency, dbPath });
|
|
console.log('[hooks.server] Indexing pipeline initialised.');
|
|
} catch (err) {
|
|
console.error(
|
|
'[hooks.server] Failed to initialise pipeline:',
|
|
err instanceof Error ? err.message : String(err)
|
|
);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CORS headers applied to all /api/* responses
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const CORS_HEADERS = {
|
|
'Access-Control-Allow-Origin': '*',
|
|
'Access-Control-Allow-Methods': 'GET, POST, PATCH, DELETE, OPTIONS',
|
|
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
|
|
} as const;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Request handler — CORS + pass-through
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export const handle: Handle = async ({ event, resolve }) => {
|
|
const { pathname } = event.url;
|
|
|
|
// Handle CORS pre-flight for all API routes.
|
|
if (event.request.method === 'OPTIONS' && pathname.startsWith('/api/')) {
|
|
return new Response(null, {
|
|
status: 204,
|
|
headers: CORS_HEADERS
|
|
});
|
|
}
|
|
|
|
const response = await resolve(event);
|
|
|
|
// Attach CORS headers to all API responses.
|
|
if (pathname.startsWith('/api/')) {
|
|
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
response.headers.set(key, value);
|
|
}
|
|
}
|
|
|
|
return response;
|
|
};
|