Download node-sqlite.mjs from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 6.83 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/node-sqlite.mjs
- Command line
-
hf download hf://SaylorTwift/openclaw/node-sqlite.mjs
-
curl -L -o node-sqlite.mjs https://huggingface.co/SaylorTwift/openclaw/resolve/main/node-sqlite.mjs
6.83 kB
| import { isSupportedOpenClawNodeVersion, parseNodeReleaseVersion } from "./node-version.mjs"; | |
| // Self-contained so a different runtime can execute exactly the same probe with -e. | |
| 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\u0000b\u0000"; | |
| 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 === text.length && | |
| 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; | |
| } | |
| // The launcher and bundled runtime chunks must share one process-local 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 === undefined || typeof value.error === "string") | |
| ); | |
| } | |
| async function probeCurrentSqliteInWorker() { | |
| let worker; | |
| try { | |
| if (typeof process.getBuiltinModule?.("node:sqlite")?.DatabaseSync !== "function") { | |
| return unavailableSqliteCapabilities(new Error("node:sqlite is unavailable")); | |
| } | |
| const env = Object.fromEntries( | |
| Object.entries(process.env).filter(([name]) => !/^(NODE_OPTIONS|BUN_OPTIONS)$/i.test(name)), | |
| ); | |
| env.NODE_NO_WARNINGS = "1"; | |
| // Older diagnostic runtimes need SQLite enabled, but must not replay entry preloads. | |
| 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 !== undefined || !isSqliteCapabilities(value)) { | |
| fail(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 === undefined) { | |
| resolve( | |
| unavailableSqliteCapabilities( | |
| new Error(`SQLite capability worker exited without a complete result (code ${code})`), | |
| ), | |
| ); | |
| } else { | |
| // The scratch database and worker must both close before startup is admitted. | |
| resolve(result); | |
| } | |
| }; | |
| worker.on("message", onMessage); | |
| worker.on("error", fail); | |
| worker.on("messageerror", fail); | |
| worker.once("exit", onExit); | |
| }); | |
| } | |
| export function detectCurrentSqliteCapabilities() { | |
| // Publish the Promise before Worker construction can notify another startup caller. | |
| globalThis[capabilityCacheKey] ??= Promise.resolve().then(probeCurrentSqliteInWorker); | |
| return Promise.resolve(globalThis[capabilityCacheKey]); | |
| } | |
| export 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))) | |
| ); | |
| } | |
| export function nodeRuntimeFailure(version, probe) { | |
| const label = `Node ${version ?? "unknown"}`; | |
| if (!probe.available) { | |
| return `${label}: node:sqlite is unavailable; use 24.16+/26.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.16+/26.1+ or a build with the fix`; | |
| } | |
| if (probe.error || !probe.text || !probe.blob || !probe.json) { | |
| return `${label}: node:sqlite NUL round-trip capability probe failed; use 24.16+/26.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.`; | |
| } | |
| // Node 22/23 remain excluded until their separate compatibility work is complete. | |
| const release = parseNodeReleaseVersion(version); | |
| if (!release || release.major < 24) { | |
| return `${label}: openclaw requires Node >=24.16.0 <25, or >=26.1.0.`; | |
| } | |
| return null; | |
| } | |
| export function nodeRuntimeNote(version, probe) { | |
| return !nodeRuntimeFailure(version, probe) && !isSupportedOpenClawNodeVersion(version) | |
| ? `Node ${version}: unsupported version, capability probe passed. Supported releases: 24.16+/26.1+.` | |
| : null; | |
| } | |
| export const SQLITE_CAPABILITY_PROBE = `(${probeSqlite.toString()})(require("node:sqlite").DatabaseSync)`; | |