File size: 4,109 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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.10.1";

let resolvedCached = null;

/**
 * Resolves a SQLite driver through a 5-step fallback chain:
 *   1. Bundled better-sqlite3 (optionalDependency)
 *   2. Runtime-installed better-sqlite3 in ~/.omniroute/runtime/
 *   3. Lazy npm install into runtime dir
 *   4. node:sqlite (Node ≥22.5 stdlib)
 *   5. sql.js (bundled WASM, always available)
 *
 * Returns { driver, source } where source is one of:
 *   "bundled" | "runtime" | "runtime-installed-now" | "node-sqlite" | "sql-js"
 */
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(/* webpackIgnore: true */ 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 }
  );
}

/** Clears the cached resolved driver (for testing). */
export function clearRuntimeCache() {
  resolvedCached = null;
}