| import { existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs";
|
| import { join, resolve } from "node:path";
|
| import { homedir } from "node:os";
|
| import { execSync } from "node:child_process";
|
| import { pathToFileURL } from "node:url";
|
| import { validateBinaryMagic, platformBinaryLabel } from "./magicBytes.mjs";
|
|
|
| const RUNTIME_DIR = join(homedir(), ".omniroute", "runtime");
|
| const BETTER_SQLITE3_VERSION = "better-sqlite3@^12.6.2";
|
|
|
| let resolvedCached = null;
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| export async function loadSqliteRuntime() {
|
| if (resolvedCached) return resolvedCached;
|
|
|
| const bundled = await tryLoadBundled();
|
| if (bundled) {
|
| resolvedCached = { driver: bundled, source: "bundled" };
|
| return resolvedCached;
|
| }
|
|
|
| const runtimeInstalled = await tryLoadRuntimeInstalled();
|
| if (runtimeInstalled) {
|
| resolvedCached = { driver: runtimeInstalled, source: "runtime" };
|
| return resolvedCached;
|
| }
|
|
|
| try {
|
| await installRuntime();
|
| const after = await tryLoadRuntimeInstalled();
|
| if (after) {
|
| resolvedCached = { driver: after, source: "runtime-installed-now" };
|
| return resolvedCached;
|
| }
|
| } catch (err) {
|
| console.warn(`[omniroute] runtime install failed: ${err.message}`);
|
| }
|
|
|
| try {
|
| const nodeSqlite = await import("node:sqlite");
|
| resolvedCached = {
|
| driver: { kind: "node-sqlite", DatabaseSync: nodeSqlite.DatabaseSync },
|
| source: "node-sqlite",
|
| };
|
| return resolvedCached;
|
| } catch {}
|
|
|
| const sqljs = await import("sql.js");
|
| resolvedCached = {
|
| driver: { kind: "sql-js", initSqlJs: sqljs.default ?? sqljs.initSqlJs },
|
| source: "sql-js",
|
| };
|
| return resolvedCached;
|
| }
|
|
|
| async function tryLoadBundled() {
|
| try {
|
| const mod = await import("better-sqlite3");
|
| return { kind: "better-sqlite3", Database: mod.default ?? mod };
|
| } catch {
|
| return null;
|
| }
|
| }
|
|
|
| async function tryLoadRuntimeInstalled() {
|
| const runtimeNodeModules = resolve(RUNTIME_DIR, "node_modules");
|
| const pkgRoot = resolve(runtimeNodeModules, "better-sqlite3");
|
| if (!pkgRoot.startsWith(`${runtimeNodeModules}/`)) return null;
|
| if (!existsSync(join(pkgRoot, "package.json"))) return null;
|
|
|
| const buildDir = join(pkgRoot, "build", "Release");
|
| if (existsSync(buildDir)) {
|
| const nodeFile = readdirSync(buildDir).find((f) => f.endsWith(".node"));
|
| if (nodeFile) {
|
| const magic = validateBinaryMagic(join(buildDir, nodeFile));
|
| const expected = platformBinaryLabel();
|
| if (!magic || (magic !== expected && magic !== "macho-le" && magic !== "macho-fat")) {
|
| console.warn(
|
| `[omniroute] runtime sqlite binary magic mismatch (${magic} ≠ ${expected}) — skipping`
|
| );
|
| return null;
|
| }
|
| }
|
| }
|
|
|
| try {
|
| const mod = await import( pathToFileURL(pkgRoot).href);
|
| return { kind: "better-sqlite3", Database: mod.default ?? mod };
|
| } catch {
|
| return null;
|
| }
|
| }
|
|
|
| function ensureRuntimeDir() {
|
| if (!existsSync(RUNTIME_DIR)) mkdirSync(RUNTIME_DIR, { recursive: true });
|
| const pkg = join(RUNTIME_DIR, "package.json");
|
| if (!existsSync(pkg)) {
|
| writeFileSync(
|
| pkg,
|
| JSON.stringify({ name: "omniroute-runtime", private: true, type: "commonjs" }),
|
| "utf-8"
|
| );
|
| }
|
| }
|
|
|
| async function installRuntime() {
|
| ensureRuntimeDir();
|
| const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
| execSync(
|
| `${npm} install --prefix "${RUNTIME_DIR}" ${BETTER_SQLITE3_VERSION} --no-audit --no-fund --silent`,
|
| { stdio: ["ignore", "ignore", "pipe"], timeout: 180_000 }
|
| );
|
| }
|
|
|
|
|
| export function clearRuntimeCache() {
|
| resolvedCached = null;
|
| }
|
|
|