openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
96 lines (95 loc) • 5.02 kB
JavaScript
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 };