openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
130 lines (129 loc) • 6.19 kB
JavaScript
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs";
import { c as registerNodeSqliteDisposeCallback } from "./kysely-sync-cache-state-DbAMR_DD.mjs";
import { m as registerSqliteSchemaMutationListener } from "./sqlite-schema-facts-BVf0E_0z.mjs";
import { d as readDatabasePathIdentitySync, r as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-BRNRpRyc.mjs";
import { a as resolveExistingSqliteFileUri, r as openNodeSqliteDatabase } from "./node-sqlite-DyeJqxPf.mjs";
import { p as withSqliteNativeOpen } from "./sqlite-error-diagnostics-CWRyv4lz.mjs";
import { o as stageSqliteTransactionState } from "./sqlite-post-commit-DENvzR6w.mjs";
import { i as assertStateDatabaseAccessAllowed } from "./gateway-state-owner-eDtEELE9.mjs";
import { n as assertSqliteIntegrity } from "./sqlite-integrity-D3yHPOet.mjs";
//#region src/state/openclaw-state-db-handle.ts
const identities = resolveGlobalSingleton(Symbol.for("openclaw.stateNativeIdentities"), () => /* @__PURE__ */ new WeakMap());
/** Physical identity admitted by the native opener, never a later pathname observation. */
function readTrackedStateDatabaseIdentity(database) {
return identities.get(database);
}
function openTrackedStateDatabase(pathname, options) {
const result = openTrackedStateDatabaseResult(pathname, options);
if (result.status === "unavailable") throw result.error;
return result.database;
}
/** Native open failure is an ordinary read failure; admitted handles retain their own cleanup. */
function openTrackedStateDatabaseResult(pathname, options) {
assertStateDatabaseAccessAllowed(pathname);
try {
if (options?.expectedIdentity !== void 0) assertExistingDatabaseIdentity(pathname, options.expectedIdentity);
const location = options?.existingOnly || options?.expectedIdentity !== void 0 ? resolveExistingSqliteFileUri(pathname) : pathname;
const nativeOptions = options?.readOnly ? {
readOnly: true,
timeout: options.timeout
} : { enableForeignKeyConstraints: options?.enableForeignKeyConstraints };
const openingIdentity = readDatabasePathIdentitySync(pathname);
const database = withSqliteNativeOpen(() => openNodeSqliteDatabase(location, nativeOptions));
try {
assertStateDatabaseAccessAllowed(pathname);
if (openingIdentity.key.startsWith("file:")) assertExistingDatabaseIdentity(pathname, openingIdentity.key, openingIdentity.birthtime);
const identity = openingIdentity.key.startsWith("file:") ? openingIdentity : readDatabasePathIdentitySync(pathname);
if (identity.key.startsWith("file:")) {
identities.set(database, identity);
const unregister = registerNodeSqliteDisposeCallback(database, () => {
identities.delete(database);
unregister();
});
}
} catch (error) {
database.close();
throw error;
}
return {
status: "available",
database
};
} catch (error) {
return {
status: "unavailable",
error
};
}
}
function closeTrackedStateDatabase(database) {
if (database.isOpen) database.close();
}
//#endregion
//#region src/state/openclaw-state-db-integrity-admission.ts
const bindings = resolveGlobalSingleton(Symbol.for("openclaw.stateIntegrityBindings"), () => /* @__PURE__ */ new WeakMap());
function invalidate(revision) {
let previous = Atomics.load(revision, 0);
while (previous >= 0n) {
const observed = Atomics.compareExchange(revision, 0, previous, previous + 1n);
if (observed === previous) return;
previous = observed;
}
}
/** Corruption observed in an isolate revokes the exact host proof borrowed by its native handle. */
function invalidateOpenClawStateRuntimeIntegrity(database) {
const bound = bindings.get(database);
if (bound) invalidate(new BigInt64Array(bound.revision));
}
/** Native bindings revoke borrowed proof; the host generation alone owns its lifetime. */
function bind(database, admission) {
if (bindings.get(database)?.revision === admission.revision) return;
bindings.get(database)?.release();
const revision = new BigInt64Array(admission.revision);
const unobserve = registerSqliteSchemaMutationListener(database, () => invalidate(revision));
const release = () => {
unobserve();
unregister();
};
const unregister = registerNodeSqliteDisposeCallback(database, (reason) => {
if (reason === "replace") invalidate(revision);
release();
});
bindings.set(database, {
revision: admission.revision,
release
});
}
/** Reuse only completed integrity proof; shape and mutable metadata retain their admission owners. */
function assertOpenClawStateRuntimeIntegrity(database, pathname, schema, admission, policy = "verify") {
const identity = admission && readTrackedStateDatabaseIdentity(database);
if (!admission || !identity || !identity.key.startsWith("file:") || identity.key !== admission.identity.key || identity.birthtime !== admission.identity.birthtime) {
if (policy === "require-proof") throw new Error("Shared-state reader requires current worker integrity proof");
assertSqliteIntegrity(database, pathname);
return;
}
bind(database, admission);
const revision = new BigInt64Array(admission.revision);
const proof = new BigInt64Array(admission.proof);
const metadata = BigInt.asIntN(64, BigInt(schema.userVersion >>> 0) << 32n | BigInt(schema.schemaVersion >>> 0));
const observed = Atomics.load(proof, 0);
if (Atomics.load(revision, 0) === admission.epoch && observed !== -1n) {
if (observed === metadata && Atomics.load(revision, 0) === admission.epoch) return;
invalidate(revision);
}
if (policy === "require-proof") throw new Error("Shared-state reader requires current worker integrity proof");
assertSqliteIntegrity(database, pathname);
const publish = () => {
if (Atomics.load(revision, 0) === admission.epoch) Atomics.store(proof, 0, metadata);
};
return () => {
if (database.isTransaction) stageSqliteTransactionState(database, {
stage() {},
rollback() {},
commit: publish
});
else publish();
};
}
//#endregion
export { openTrackedStateDatabaseResult as a, openTrackedStateDatabase as i, invalidateOpenClawStateRuntimeIntegrity as n, readTrackedStateDatabaseIdentity as o, closeTrackedStateDatabase as r, assertOpenClawStateRuntimeIntegrity as t };