openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
91 lines (90 loc) • 4.42 kB
JavaScript
import { h as clearNodeSqliteKyselyCacheForDatabase, t as openNodeSqliteDatabase } from "./node-sqlite-BpQX3W0e.js";
import { a as prepareSqliteReadOnlyLocationSyncInProcess, i as prepareSqliteReadOnlyLocationSync } from "./sqlite-readonly-location-BC9PgENz.js";
import { o as openClawStateDatabaseCache } from "./openclaw-state-db-cache-C7ljO0xP.js";
import { o as OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db-contract-DYCYxE4w.js";
import { s as resolveOpenClawStateSqlitePath, t as assertSupportedStateSchemaVersion } from "./openclaw-state-db-schema-version-c1ZL6JGz.js";
import { statSync } from "node:fs";
import path from "node:path";
//#region src/state/openclaw-state-db-readonly.ts
/** Missing runtime tables are empty only before state grows beyond checkpoint bootstrap. */
function hasOpenClawStateTablesBeyondStartupCheckpoint(db) {
return db.prepare("SELECT 1 FROM main.sqlite_schema WHERE type = 'table' AND name NOT IN ('schema_meta', 'state_leases') LIMIT 1").get() !== void 0;
}
function resolveReadOnlyPath(options) {
return path.resolve(options.path ?? resolveOpenClawStateSqlitePath(options.env ?? process.env));
}
function existingPathOrUndefined(pathname) {
try {
statSync(pathname);
return pathname;
} catch (error) {
if (error.code === "ENOENT") return;
throw error;
}
}
function withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname) {
const opened = openClawStateDatabaseCache.getOpenClawStateDatabaseIfOpenAtPath(pathname);
if (!opened || opened.db.isTransaction) return { reused: false };
try {
assertSupportedStateSchemaVersion(opened.db, pathname);
return {
reused: true,
value: operation(opened)
};
} catch (error) {
openClawStateDatabaseCache.evictOpenClawStateDatabaseAfterCorruption(opened, error);
throw error;
}
}
function withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname, location = pathname) {
const env = options.env ?? process.env;
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
const db = openNodeSqliteDatabase(location, { readOnly: true });
try {
db.exec(`PRAGMA busy_timeout = ${OPENCLAW_SQLITE_BUSY_TIMEOUT_MS};`);
assertSupportedStateSchemaVersion(db, pathname);
return operation({
db,
path: pathname
});
} finally {
clearNodeSqliteKyselyCacheForDatabase(db);
db.close();
}
}
/**
* Read shared state without joining the writable lifecycle.
*
* CLI metadata reads can overlap a live Gateway. Keep them off schema repair,
* journal-mode setup, checkpoints, and permission mutation owned by writers.
*/
function withOpenClawStateDatabaseReadOnly(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
return withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname);
}
/** Read existing shared state while preserving non-missing filesystem failures. */
function withExistingOpenClawStateDatabaseReadOnly(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
const existingPath = existingPathOrUndefined(pathname);
return existingPath === void 0 ? void 0 : withFreshOpenClawStateDatabaseReadOnly(operation, options, existingPath);
}
/** Read existing shared state without creating or updating its SQLite sidecars. */
function withExistingOpenClawStateDatabaseArtifactPreservingReadOnly(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
const existingPath = existingPathOrUndefined(pathname);
if (existingPath === void 0) return;
const prepared = (openClawStateDatabaseCache.getOpenClawStateDatabaseIfOpenAtPath(pathname) ? prepareSqliteReadOnlyLocationSync : prepareSqliteReadOnlyLocationSyncInProcess)(existingPath);
try {
return withFreshOpenClawStateDatabaseReadOnly(operation, options, existingPath, prepared.location);
} finally {
prepared.cleanup();
}
}
//#endregion
export { withOpenClawStateDatabaseReadOnly as i, withExistingOpenClawStateDatabaseArtifactPreservingReadOnly as n, withExistingOpenClawStateDatabaseReadOnly as r, hasOpenClawStateTablesBeyondStartupCheckpoint as t };