mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-24 16:12:23 +03:00
check:pack-artifact and check:pack-boot have been self-contradictory since 05/08, blocking the v3.8.50 publish in ci.yml (build:cli job) and npm-publish.yml: - check:pack-artifact FAILS any tarball path containing a node_modules segment (PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS; files[] also excludes "!**/node_modules/**"). - check:pack-boot REQUIRED sql.js under the vendored dist/node_modules/sql.js location — a path the tarball can never carry, so both gates could never be green at once. The packaging model is now dependency-based: sql.js and node-machine-id are declared `dependencies` (a clean install places them under <packageRoot>/node_modules/), and better-sqlite3 is an optionalDependency installed natively per platform (^13.0.2 — which also covers the darwin-arm64 prebuild gap from #11242 by construction). The runtime already resolves the WASM at <cwd>/node_modules/sql.js/dist/sql-wasm.wasm (src/lib/db/adapters/sqljsAdapter.ts). Changes: - scripts/check/check-pack-boot.mjs: REQUIRED_SQLJS_RUNTIME_FILES now points at node_modules/sql.js/{package.json,dist/sql-wasm.js, dist/sql-wasm.wasm} — the dependency-installed location the clean-prefix install actually produces. REQUIRED_MACHINE_TOKEN_RUNTIME_FILES was already correct and is unchanged. - bin/cli/runtime/sqliteRuntime.mjs: BETTER_SQLITE3_VERSION bumped ^12.10.1 -> ^13.0.2 to match optionalDependencies (the lazy runtime install was pulling the wrong major), and exported for the guard. - tests/unit/pack-boot-runtime-paths.test.ts (new, TDD: RED -> GREEN): pins that (a) no pack-boot required path references a never-publishable vendored dist/<segment> location (driven by PACK_ARTIFACT_NEVER_ALLOWED_SEGMENTS), (b) sql.js/node-machine-id stay declared dependencies, (c) the lazy-install spec stays on the declared optionalDependency major. - tests/unit/check-pack-boot.test.ts: the sql.js contract test pinned the old vendored path; updated to node_modules/sql.js/dist/sql-wasm.wasm. This is alignment to the real new contract (vendoring ended), not masking — the same test still asserts the find-missing behavior. Electron is unaffected: the vendored dist/node_modules bundle still exists for Electron packaging (postinstall.mjs and assembleStandalone.mjs untouched). Refs #11242 Refs #10296
132 lines
4.2 KiB
JavaScript
132 lines
4.2 KiB
JavaScript
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");
|
|
// Exported so the packaging coherence guard (tests/unit/pack-boot-runtime-paths.test.ts)
|
|
// can assert this stays on the same major as optionalDependencies.better-sqlite3 (#11242).
|
|
export const BETTER_SQLITE3_VERSION = "better-sqlite3@^13.0.2";
|
|
|
|
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;
|
|
}
|