UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

125 lines (124 loc) • 5.88 kB
import { l as isSupportedOpenClawNodeVersion, r as SUPPORTED_NODE_VERSION_RANGE } from "./node-version-Dq_scYWR.mjs"; //#region node-sqlite.mjs function probeSqlite(DatabaseSync) { const result = { available: false, version: null, text: false, blob: false, json: false }; let database; try { database = new DatabaseSync(":memory:"); result.available = true; const version = database.prepare("SELECT sqlite_version() AS version").get()?.version; result.version = typeof version === "string" ? version : null; const text = "a\0b\0"; const bytes = Buffer.from(text, "utf8"); const json = JSON.stringify({ value: text }); database.exec("CREATE TABLE probe (text_value TEXT, blob_value BLOB, json_value TEXT)"); database.prepare("INSERT INTO probe VALUES (?, ?, ?)").run(text, bytes, json); const row = database.prepare("SELECT text_value, blob_value, json_value FROM probe").get(); result.text = typeof row?.text_value === "string" && row.text_value.length === 4 && Buffer.from(row.text_value, "utf8").equals(bytes); result.blob = row?.blob_value instanceof Uint8Array && Buffer.from(row.blob_value).equals(bytes); result.json = row?.json_value === json && JSON.parse(row.json_value).value === text; } catch (error) { result.error = error instanceof Error ? error.message : String(error); } finally { database?.close(); } return result; } const capabilityCacheKey = Symbol.for("openclaw.sqliteCapabilities"); function unavailableSqliteCapabilities(error) { return { available: false, version: null, text: false, blob: false, json: false, error: error instanceof Error ? error.message : String(error) }; } function isSqliteCapabilities(value) { return value !== null && typeof value === "object" && typeof value.available === "boolean" && (value.version === null || typeof value.version === "string") && typeof value.text === "boolean" && typeof value.blob === "boolean" && typeof value.json === "boolean" && (value.error === void 0 || typeof value.error === "string"); } async function probeCurrentSqlite() { let worker; try { const DatabaseSync = process.getBuiltinModule?.("node:sqlite")?.DatabaseSync; if (typeof DatabaseSync !== "function") return unavailableSqliteCapabilities(/* @__PURE__ */ new Error("node:sqlite is unavailable")); if (!process.versions.bun && process.permission?.has("worker") === false) return probeSqlite(DatabaseSync); const env = Object.fromEntries(Object.entries(process.env).filter(([name]) => !/^(NODE_OPTIONS|BUN_OPTIONS)$/i.test(name))); env.NODE_NO_WARNINGS = "1"; const execArgv = !process.versions.bun && process.allowedNodeEnvironmentFlags?.has("--experimental-sqlite") ? ["--experimental-sqlite"] : []; const { Worker } = await import("node:worker_threads"); worker = new Worker(`const { parentPort } = require("node:worker_threads"); parentPort.postMessage(${SQLITE_CAPABILITY_PROBE}); parentPort.close();`, { eval: true, env, execArgv }); } catch (error) { return unavailableSqliteCapabilities(error); } return new Promise((resolve) => { let result; let failure; let retirement; const fail = (error) => { failure ??= { error }; retirement ??= Promise.resolve().then(() => worker.terminate()).catch((error) => { failure ??= { error }; }); }; const onMessage = (value) => { if (result !== void 0 || !isSqliteCapabilities(value)) { fail(/* @__PURE__ */ new Error("SQLite capability worker returned an invalid result")); return; } result = value; }; const onExit = (code) => { worker.off("message", onMessage); worker.off("error", fail); worker.off("messageerror", fail); if (failure) resolve(unavailableSqliteCapabilities(failure.error)); else if (code !== 0 || result === void 0) resolve(unavailableSqliteCapabilities(/* @__PURE__ */ new Error(`SQLite capability worker exited without a complete result (code ${code})`))); else resolve(result); }; worker.on("message", onMessage); worker.on("error", fail); worker.on("messageerror", fail); worker.once("exit", onExit); }); } function detectCurrentSqliteCapabilities() { globalThis[capabilityCacheKey] ??= Promise.resolve().then(probeCurrentSqlite); return Promise.resolve(globalThis[capabilityCacheKey]); } function isSqliteWalResetSafeVersion(value) { const match = /^(\d+)\.(\d+)\.(\d+)$/u.exec(value.trim()); if (!match) return false; const [major, minor, patch] = match.slice(1).map(Number); if (![ major, minor, patch ].every(Number.isSafeInteger)) return false; return major > 3 || major === 3 && (minor > 51 || minor === 51 && patch >= 3 || minor === 50 && patch >= 7 || minor === 44 && patch >= 6); } function nodeRuntimeFailure(version, probe) { const label = `Node ${version ?? "unknown"}`; if (!probe.available) return `${label}: node:sqlite is unavailable; use 24.22.1+/26.12.1+ or a build with the fix.`; if (!probe.text && !probe.error) return `${label}: node:sqlite truncates TEXT at embedded NUL (nodejs/node#61954); use 24.22.1+/26.12.1+ or a build with the fix`; if (probe.error || !probe.text || !probe.blob || !probe.json) return `${label}: node:sqlite NUL round-trip capability check failed; use 24.22.1+/26.12.1+ or a build with the fix.`; if (!probe.version || !isSqliteWalResetSafeVersion(probe.version)) return `${label}: SQLite ${probe.version ?? "unknown"} is not WAL-reset-safe; use SQLite 3.51.3+, 3.50.7+, or 3.44.6+ on its patched release line.`; if (!isSupportedOpenClawNodeVersion(version)) return `${label}: openclaw requires Node ${SUPPORTED_NODE_VERSION_RANGE.replace(" || ", ", or ")}.`; return null; } const SQLITE_CAPABILITY_PROBE = `(${probeSqlite.toString()})(require("node:sqlite").DatabaseSync)`; //#endregion export { nodeRuntimeFailure as i, detectCurrentSqliteCapabilities as n, isSqliteWalResetSafeVersion as r, SQLITE_CAPABILITY_PROBE as t };