export type CoordinateSpace = "pixels" | "normalized_1000"; export function readCoordinateSpace(value = "pixels"): CoordinateSpace { if (value !== "pixels" && value !== "normalized_1000") { throw new Error("DESKTOP_COORDINATE_SPACE must be pixels or normalized_1000."); } return value; } export interface Config { llamaCppOrigin: string; modelId: string; databasePath: string; coordinateSpace: CoordinateSpace; } export function readConfig(environment: NodeJS.ProcessEnv = process.env): Config { const origin = environment.LLAMA_CPP_ORIGIN?.trim(); const modelId = environment.LLAMA_CPP_MODEL_ID?.trim(); if (!origin || !modelId) { throw new Error("Set LLAMA_CPP_ORIGIN and LLAMA_CPP_MODEL_ID in .env (see .env.example)."); } const url = new URL(origin); if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.pathname !== "/" || url.search || url.hash) { throw new Error("LLAMA_CPP_ORIGIN must be an HTTP(S) origin without credentials, path, query, or fragment."); } return { coordinateSpace: readCoordinateSpace(environment.DESKTOP_COORDINATE_SPACE), llamaCppOrigin: url.origin, modelId, databasePath: environment.DATABASE_PATH?.trim() || "./data/token.sqlite", }; }