openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
148 lines (147 loc) • 7.16 kB
JavaScript
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { d as readDatabasePathIdentitySync, n as assertDatabasePathIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { s as throwSqliteLifecycleErrors } from "./sqlite-lifecycle-errors-DuOygjcn.mjs";
import { u as withAgentDatabaseCloseFence } from "./openclaw-agent-db-resources-Cm-sH7kg.mjs";
import { h as invalidateOpenClawAgentDatabaseValidation } from "./openclaw-agent-db-validation-cache-CHrtutWN.mjs";
import { o as isSameOpenClawAgentDatabasePath } from "./openclaw-agent-db.paths-BbmZlEP5.mjs";
import { a as observeSqliteWorkerCommittedFacts } from "./sqlite-worker-operation-admission-C5lBzzTk.mjs";
import { r as captureOpenClawStateWorkerContext } from "./openclaw-state-worker-context-BvvgY6-t.mjs";
import { l as prepareOpenClawAgentDatabaseRegistrySnapshotRead, r as captureOpenClawAgentDatabaseRegistration } from "./openclaw-agent-db-registry-listing-DIA5wIwi.mjs";
import { T as revokePendingAgentDatabaseOpen, a as closeOpenClawAgentDatabaseByPathAsync, t as cache } from "./openclaw-agent-db-lifecycle-C9dal1XJ.mjs";
import { n as createSqliteWorkerWriteAdmission } from "./sqlite-worker-store-C0QRqven.mjs";
import { o as runOpenClawStateWorkerOperation } from "./openclaw-state-worker-store-BxZXTKna.mjs";
import path from "node:path";
//#region src/state/openclaw-agent-db-disposal.ts
/** Join one unambiguous transient owner before removing its durable registration. */
async function disposeOpenClawAgentDatabaseByPath(databasePath, options = {}) {
const resolvedPath = path.resolve(databasePath);
const pending = [...cache.activePending].filter((owner) => isSameOpenClawAgentDatabasePath(owner.path, resolvedPath));
const retained = [...cache.retainedCloses].filter((owner) => isSameOpenClawAgentDatabasePath(owner.path, resolvedPath));
const native = [...cache.databases.values()].filter((database) => isSameOpenClawAgentDatabasePath(database.path, resolvedPath));
const database = native[0];
const incognito = database && cache.incognito.has(database);
const identity = readDatabasePathIdentitySync(resolvedPath);
const context = !incognito && native.length <= 1 && (identity.key.startsWith("file:") || database) ? captureOpenClawStateWorkerContext({ env: options.env ?? (database && cache.leases.get(database.path)?.env) }) : void 0;
const paths = [.../* @__PURE__ */ new Set([
resolvedPath,
identity.canonicalPath,
...pending.map((owner) => owner.path),
...retained.map((owner) => owner.path),
...native.map((owner) => owner.path)
])];
const assertCurrent = () => {
context?.admission.assertCurrent();
context?.maintenanceScope?.assertAdmission();
for (const pathname of paths) assertDatabasePathIdentity(pathname, identity);
};
const dispose = async () => {
for (const pathname of paths) invalidateOpenClawAgentDatabaseValidation(pathname);
for (const owner of pending) revokePendingAgentDatabaseOpen(owner.path, owner.agentId);
for (const owner of retained) owner.close();
await Promise.allSettled(pending.map((owner) => owner.promise));
assertCurrent();
if (native.length > 1) throw new Error(`Agent database disposal has multiple native owners: ${resolvedPath}`);
const closeCapturedPaths = async (additionalPath) => {
assertCurrent();
const closePaths = additionalPath ? [.../* @__PURE__ */ new Set([...paths, additionalPath])] : paths;
const results = await Promise.allSettled(closePaths.map((pathname) => closeOpenClawAgentDatabaseByPathAsync(pathname)));
assertCurrent();
throwSqliteLifecycleErrors(results.flatMap((result) => result.status === "rejected" ? [result.reason] : []), "Agent disposal resource drainage failed");
return results.some((result) => result.status === "fulfilled" && result.value);
};
if (!context) {
const closed = await closeCapturedPaths();
return incognito ? closed : false;
}
let target = database && {
agentId: database.agentId,
path: database.path
};
if (!target) {
const snapshot = await prepareOpenClawAgentDatabaseRegistrySnapshotRead({ env: context.environment }).read();
assertCurrent();
snapshot.assertCurrent();
if (snapshot.result.status !== "available") throw new Error("Transient agent disposal cannot read its shared registry");
const [match, ...ambiguous] = snapshot.result.entries.filter((entry) => isSameOpenClawAgentDatabasePath(entry.path, resolvedPath));
if (ambiguous.length) throw new Error(`Agent database disposal has multiple registered owners: ${resolvedPath}`);
if (!match) {
await closeCapturedPaths();
return false;
}
target = match;
}
const owned = target;
const assertOwned = () => {
assertCurrent();
assertDatabasePathIdentity(owned.path, identity);
};
return withAgentDatabaseCloseFence({ path: owned.path }, async () => {
assertOwned();
invalidateOpenClawAgentDatabaseValidation(owned.path);
await closeCapturedPaths(owned.path);
assertOwned();
const publication = captureOpenClawAgentDatabaseRegistration({
kind: "remove",
agentId: owned.agentId,
agentPath: owned.path,
admission: context.admission,
assertPublicationCurrent: context.assertPublicationCurrent
});
let settlement;
let committed = false;
const record = (receipt) => {
publication.recordCommitted(receipt);
committed = true;
};
const errors = [];
try {
const receipt = await runOpenClawStateWorkerOperation(context, (scope) => scope.execute({
type: "agentDatabaseRegistry.remove",
input: {
agentId: owned.agentId,
agentPath: owned.path,
identity
}
}), {
assertCurrent: assertOwned,
createAdmission(operation) {
settlement = operation.settled;
const admission = createSqliteWorkerWriteAdmission((request) => {
assertOwned();
if (request.stage === "transaction") publication.begin();
}, [
context.admission.databasePath,
owned.path,
...paths
])(operation);
observeSqliteWorkerCommittedFacts(admission.admission, ({ facts }) => {
if (!isRecord(facts) || typeof facts.agentId !== "string" || typeof facts.agentPath !== "string" || typeof facts.stateDatabasePath !== "string" || typeof facts.stateDatabaseIdentity !== "string") throw new Error("Agent disposal returned an invalid registry receipt");
record({
agentId: facts.agentId,
agentPath: facts.agentPath,
stateDatabasePath: facts.stateDatabasePath,
stateDatabaseIdentity: facts.stateDatabaseIdentity
});
});
return admission;
}
});
if (!committed) record(receipt);
} catch (error) {
errors.push(error);
}
try {
publication.finish(await settlement);
} catch (error) {
errors.push(error);
}
throwSqliteLifecycleErrors(errors, "Agent disposal and registry publication failed");
assertOwned();
return true;
});
};
const fence = (index) => index === paths.length ? dispose() : withAgentDatabaseCloseFence({ path: paths[index] }, () => fence(index + 1));
return fence(0);
}
//#endregion
export { disposeOpenClawAgentDatabaseByPath as t };