UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

140 lines (139 loc) 4.53 kB
import { n as normalizeAgentId } from "./agent-id-CeT3w4ap.js"; import "./session-key-BnWWjqNc.js"; import { h as clearNodeSqliteKyselyCacheForDatabase, t as openNodeSqliteDatabase } from "./node-sqlite-BpQX3W0e.js"; import "./kysely-sync-COmh4HWh.js"; import { o as OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db-contract-DYCYxE4w.js"; import { D as isIncognitoOpenClawAgentSqlitePath, k as resolveOpenClawAgentSqlitePath } from "./openclaw-agent-db-lease-Djvd6LWN.js"; import { C as assertExistingAgentSchemaOwner, E as readExistingAgentSchemaMeta, S as assertCanonicalAgentPersistenceVersion, T as assertSupportedAgentSchemaVersion } from "./openclaw-agent-db-maintenance-wTIy-jt-.js"; import { c as getOpenClawAgentDatabaseIfOpen } from "./openclaw-agent-db-CWtDoRbC.js"; import fs from "node:fs"; //#region src/state/openclaw-agent-db-readonly.ts /** * Look up a process-held handle without adopting writer-side failures. * * Read-only reads are meant to survive a latched open failure or an ownership * mismatch that only the writable lifecycle cares about; those callers fall * back to a fresh connection, which reports the precise reason. */ function findOpenAgentDatabase(options) { try { return getOpenClawAgentDatabaseIfOpen(options); } catch { return; } } /** Open one existing agent database without creating, registering, migrating, or adopting it. */ function openOpenClawAgentDatabaseReadOnly(options, behavior = {}) { const agentId = normalizeAgentId(options.agentId); const pathname = resolveOpenClawAgentSqlitePath({ ...options, agentId }); if (isIncognitoOpenClawAgentSqlitePath(pathname, { agentId, env: options.env })) return { found: false, reason: "database-missing" }; if (!fs.existsSync(pathname)) return { found: false, reason: "database-missing" }; const db = openNodeSqliteDatabase(pathname, { readOnly: true, ...behavior.allowExtension ? { allowExtension: true } : {} }); let closed = false; const close = () => { if (closed) return; closed = true; clearNodeSqliteKyselyCacheForDatabase(db); db.close(); }; try { db.exec(`PRAGMA busy_timeout = ${OPENCLAW_SQLITE_BUSY_TIMEOUT_MS};`); const userVersion = assertSupportedAgentSchemaVersion(db, pathname); assertCanonicalAgentPersistenceVersion(db, pathname, userVersion); const schemaMeta = readExistingAgentSchemaMeta(db); if (!schemaMeta) { close(); return { found: false, reason: "schema-missing" }; } assertExistingAgentSchemaOwner(schemaMeta, agentId, pathname); return { found: true, database: { agentId, db, path: pathname, close } }; } catch (error) { close(); throw error; } } /** Read agent state without creating, registering, migrating, or joining its writable lifecycle. */ function withOpenClawAgentDatabaseReadOnly(operation, options, behavior = {}) { const agentId = normalizeAgentId(options.agentId); const pathname = resolveOpenClawAgentSqlitePath({ ...options, agentId }); if (isIncognitoOpenClawAgentSqlitePath(pathname, { agentId, env: options.env })) { const database = getOpenClawAgentDatabaseIfOpen({ ...options, agentId }); if (database && behavior.allowExtension) throw new Error("Extension-capable read-only access is unavailable for incognito databases."); return database ? { found: true, value: operation(database) } : { found: false, reason: "database-missing" }; } const processOpened = behavior.allowExtension ? void 0 : findOpenAgentDatabase({ ...options, agentId }); const reusable = processOpened && !processOpened.db.isTransaction ? processOpened : void 0; const fresh = reusable ? void 0 : openOpenClawAgentDatabaseReadOnly({ ...options, agentId }, behavior); if (fresh && !fresh.found) return fresh; const database = reusable ?? fresh.database; const { db } = database; try { if (reusable) { const userVersion = assertSupportedAgentSchemaVersion(db, pathname); assertCanonicalAgentPersistenceVersion(db, pathname, userVersion); } try { return { found: true, value: operation(database) }; } catch (error) { if (error instanceof Error && error.code === "ERR_SQLITE_ERROR" && /\bno such table:/iu.test(error.message) && !behavior.throwOnMissingTable) return { found: false, reason: "table-missing" }; throw error; } } finally { if (fresh?.found) fresh.database.close(); } } //#endregion export { withOpenClawAgentDatabaseReadOnly as n, openOpenClawAgentDatabaseReadOnly as t };