import { existsSync } from "node:fs"; import { getLoadablePath } from "sqlite-vec"; const HOMEBREW_SQLITE_LIBRARY_PATHS = [ "/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib", "/usr/local/opt/sqlite/lib/libsqlite3.dylib", ] as const; type LocalSqliteVectorConfig = | { mode: "native"; source: "explicit-env" | "autodetect-homebrew"; sqliteLibPath: string; vectorExtensionPath: string; } | { mode: "fallback"; reason: "non-macos" | "sqlite-lib-missing" | "vector-extension-missing"; }; type ResolveLocalSqliteVectorConfigOptions = { env?: Record; fileExists?: (path: string) => boolean; platform?: NodeJS.Platform; resolveVectorExtensionPath?: () => string; }; function trim(value: string | undefined) { const candidate = value?.trim(); return candidate ? candidate : undefined; } function defaultResolveVectorExtensionPath() { return getLoadablePath(); } function resolveVectorExtensionPath( env: Record, resolvePath: () => string, fileExists: (path: string) => boolean, ) { const explicitPath = trim(env.SQLITE_VEC_EXTENSION_PATH); if (explicitPath) { return fileExists(explicitPath) ? explicitPath : null; } try { const packagePath = resolvePath(); return fileExists(packagePath) ? packagePath : null; } catch { return null; } } export function resolveLocalSqliteVectorConfig( options: ResolveLocalSqliteVectorConfigOptions = {}, ): LocalSqliteVectorConfig { const env = options.env ?? process.env; const platform = options.platform ?? process.platform; const fileExists = options.fileExists ?? existsSync; const resolvePath = options.resolveVectorExtensionPath ?? defaultResolveVectorExtensionPath; if (platform !== "darwin") { return { mode: "fallback", reason: "non-macos", }; } const vectorExtensionPath = resolveVectorExtensionPath( env, resolvePath, fileExists, ); if (!vectorExtensionPath) { return { mode: "fallback", reason: "vector-extension-missing", }; } const explicitSqliteLibPath = trim(env.SQLITE_CUSTOM_LIB_PATH); if (explicitSqliteLibPath) { if (!fileExists(explicitSqliteLibPath)) { return { mode: "fallback", reason: "sqlite-lib-missing", }; } return { mode: "native", source: "explicit-env", sqliteLibPath: explicitSqliteLibPath, vectorExtensionPath, }; } for (const sqliteLibPath of HOMEBREW_SQLITE_LIBRARY_PATHS) { if (!fileExists(sqliteLibPath)) { continue; } return { mode: "native", source: "autodetect-homebrew", sqliteLibPath, vectorExtensionPath, }; } return { mode: "fallback", reason: "sqlite-lib-missing", }; } export function applyLocalSqliteVectorEnv< T extends Record, >(env: T, options: ResolveLocalSqliteVectorConfigOptions = {}) { const config = resolveLocalSqliteVectorConfig({ ...options, env }); if (config.mode !== "native") { return { config, env, }; } return { config, env: { ...env, SQLITE_CUSTOM_LIB_PATH: env.SQLITE_CUSTOM_LIB_PATH?.trim() || config.sqliteLibPath, SQLITE_VEC_EXTENSION_PATH: env.SQLITE_VEC_EXTENSION_PATH?.trim() || config.vectorExtensionPath, } as T & { SQLITE_CUSTOM_LIB_PATH: string; SQLITE_VEC_EXTENSION_PATH: string; }, }; }