UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

96 lines (95 loc) • 5.02 kB
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs"; import { t as hasErrnoCode } from "./errno-FR4CRyya.mjs"; import { s as normalizeDatabasePath } from "./sqlite-worker-identity-BRNRpRyc.mjs"; import { t as isPromiseLike } from "./promise-like-D7-l5Fsp.mjs"; import { r as resolveDatabasePath } from "./openclaw-state-db.paths-CmKkMYdo.mjs"; import { realpathSync } from "node:fs"; import { AsyncLocalStorage } from "node:async_hooks"; //#region src/state/openclaw-state-db-schema-policy.ts const schemaPolicies = resolveGlobalSingleton(Symbol.for("openclaw.stateDatabaseSchemaPolicies"), () => ({ scopes: new AsyncLocalStorage(), existingDatabases: /* @__PURE__ */ new WeakMap() })); function canonicalPath(pathname) { const resolved = resolveDatabasePath({ path: pathname }); try { return normalizeDatabasePath(realpathSync.native(resolved)); } catch (error) { if (hasErrnoCode(error, "ENOENT")) return resolved; throw error; } } function withExistingOpenClawStateSchema(options, run) { getExistingOpenClawStateSchemaPath(); const parent = schemaPolicies.scopes.getStore(); const scope = { path: resolveDatabasePath(options), canonicalPath: canonicalPath(options.path), active: true }; if (parent && parent.canonicalPath !== scope.canonicalPath) throw new Error("Existing shared-state schema admission cannot change its database path."); try { const result = schemaPolicies.scopes.run(scope, run); if (isPromiseLike(result)) return Promise.resolve(result).finally(() => { scope.active = false; }); scope.active = false; return result; } catch (error) { scope.active = false; throw error; } } function assertSchemaScopeActive(scope) { if (scope && !scope.active) throw new Error("Existing shared-state schema admission has ended."); } function getExistingOpenClawStateSchemaPath() { const scope = schemaPolicies.scopes.getStore(); assertSchemaScopeActive(scope); return scope?.path; } /** Admit this source once; retained reads only need the original scope's live lifetime. */ function captureOpenClawStateSchemaReadAdmission(pathname) { const scope = schemaPolicies.scopes.getStore(); if (!scope) return; isExistingOpenClawStateSchema(pathname); return { path: scope.path, assertCurrent: () => assertSchemaScopeActive(scope) }; } /** Check supplied and cached handles before exposing them to another admission policy. */ function isExistingOpenClawStateSchema(pathname, database) { const scopedPath = getExistingOpenClawStateSchemaPath(); const scope = schemaPolicies.scopes.getStore(); const admittedPath = database && schemaPolicies.existingDatabases.get(database); const resolvedPath = resolveDatabasePath({ path: pathname }); const existing = scopedPath !== void 0 && (scopedPath === resolvedPath || scope?.canonicalPath === resolvedPath || scope?.canonicalPath === canonicalPath(resolvedPath)); if (scopedPath && !existing) throw new Error(`Existing shared-state schema admission is bound to ${scopedPath}, not ${pathname}.`); if (admittedPath && (!existing || admittedPath !== scope?.canonicalPath)) throw new Error(`Shared-state database ${pathname} was admitted without schema repair; close its existing handle before ordinary admission.`); return existing; } function recordExistingOpenClawStateSchemaDatabase(database, pathname) { const scope = schemaPolicies.scopes.getStore(); if (!scope || !isExistingOpenClawStateSchema(pathname, database)) throw new Error("Existing shared-state schema admission requires its active path scope."); schemaPolicies.existingDatabases.set(database, scope.canonicalPath); } /** The cache owns the handle inventory, including owners retained after failed cleanup. */ function assertExistingOpenClawStateSchemaCacheAdmission(pathname, cache) { const scopedPath = getExistingOpenClawStateSchemaPath(); const scope = schemaPolicies.scopes.getStore(); const requested = resolveDatabasePath({ path: pathname }); let resolved = scope && (scopedPath === requested || scope.canonicalPath === requested) ? scope.canonicalPath : void 0; for (const databases of [cache.cachedDatabases, cache.retainedDatabaseHandles]) for (const { db } of databases.values()) { const admittedPath = schemaPolicies.existingDatabases.get(db); if (admittedPath && db.isOpen) { resolved ??= canonicalPath(pathname); if (admittedPath === resolved) isExistingOpenClawStateSchema(pathname, db); } } } function assertOpenClawStateSchemaRepairAllowed(pathname) { if (isExistingOpenClawStateSchema(pathname)) throw new Error(`Shared-state schema repair is owned by the existing installation at ${pathname}; update that installation before retrying the managed node.`); } //#endregion export { isExistingOpenClawStateSchema as a, getExistingOpenClawStateSchemaPath as i, assertOpenClawStateSchemaRepairAllowed as n, recordExistingOpenClawStateSchemaDatabase as o, captureOpenClawStateSchemaReadAdmission as r, withExistingOpenClawStateSchema as s, assertExistingOpenClawStateSchemaCacheAdmission as t };