openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
826 lines (825 loc) • 37.2 kB
JavaScript
import { t as createDeferredCore } from "./deferred-D0La5CRk.mjs";
import { a as resolveGlobalSingleton } from "./global-singleton-0m-JziJW.mjs";
import { r as getAsyncWorkSignal, t as AsyncWorkScope } from "./async-work-scope-BYeX3gh6.mjs";
import { t as hasErrnoCode } from "./errno-FR4CRyya.mjs";
import { n as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-KSR14F6C.mjs";
import { a as prepareSqliteReadOnlyLocationFromOwnedDatabase, s as prepareSqliteReadOnlyLocationSyncInProcess } from "./sqlite-readonly-location-OdGkIPCl.mjs";
import { t as isPromiseLike } from "./promise-like-D7-l5Fsp.mjs";
import { i as SqliteCoordinatorError, s as throwSqliteLifecycleErrors } from "./sqlite-lifecycle-errors-DuOygjcn.mjs";
import { d as retainSnapshotWork, t as SqliteSnapshotCleanupError, u as retainSnapshotTempDirectory } from "./sqlite-readonly-location-cleanup-CPS8QEIp.mjs";
import { f as maintenanceOwnerMayCopySourcesInProcess, l as getOpenClawDatabaseMaintenanceScope, o as allowsMaintenanceLiveAuthorityReads, p as observeOpenClawDatabaseMaintenanceResource, t as StateDatabaseReadAdmissionInvalidatedError } from "./openclaw-state-db-async-lifecycle-DLKxSPCk.mjs";
import { c as resolveOpenClawStateSqlitePath, n as existingPathOrUndefined } from "./openclaw-state-db.paths-DfifnSGp.mjs";
import { i as startSqliteReadOnlyLocationAsync, n as prepareSqliteReadOnlyLocationSync, r as readSqliteSourceContentVersionSync, t as prepareSqliteReadOnlyLocation } from "./sqlite-snapshot-source-BPapZs5n.mjs";
import { n as isUpdateRehearsalPrivateDatabase } from "./update-rehearsal-paths-DTVdt0cq.mjs";
import { S as retainOpenClawStateDatabaseForIndependentRead, _ as registerOpenClawStateDatabaseAsyncResource, f as openClawStateDatabaseCache, n as captureOpenClawStateDatabaseReadAdmission, t as borrowOpenClawStateDatabaseForAsyncRead, y as requireOpenClawStateDatabaseIdentity } from "./openclaw-state-db-cache-BKCnj4of.mjs";
import { a as isExistingOpenClawStateSchema } from "./openclaw-state-db-schema-policy-BxAJZRG6.mjs";
import { a as withOpenClawStateReadOnlyLocation, i as openOpenClawStateReadOnlyLocation, t as assertStateReadSchema } from "./openclaw-state-db-read-connection-C62_-Nv8.mjs";
import { t as isManagedStateTransaction } from "./openclaw-state-db-transaction-LzNJgkWu.mjs";
import { t as captureOpenClawStateReadSource } from "./openclaw-state-read-worker-Dz7y6uEu.mjs";
import { n as captureOpenClawStateReadWorkerContext } from "./openclaw-state-worker-context-DRG_I6tz.mjs";
import { lstatSync } from "node:fs";
import path from "node:path";
import { AsyncLocalStorage } from "node:async_hooks";
//#region src/state/openclaw-state-db-content-version.ts
/** The read-only owner has checked retained scopes and exited discovery first. */
function readAdmittedStateContentVersion(pathname, env) {
const assertCurrent = () => {
getOpenClawDatabaseMaintenanceScope()?.assertReadAdmission();
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
};
assertCurrent();
if (existingPathOrUndefined(pathname) === void 0) return;
const version = readSqliteSourceContentVersionSync(pathname);
assertCurrent();
return version === void 0 ? void 0 : `${pathname}:${isExistingOpenClawStateSchema(pathname)}:${version}`;
}
//#endregion
//#region src/state/openclaw-state-db-readonly-reuse.ts
const maintenanceReaders = /* @__PURE__ */ new WeakMap();
/** Mutable maintenance owns this live reader until drainage; each guard queries current rows. */
function withMaintenanceOpenClawStateDatabaseReadOnly(operation, pathname) {
const scope = getOpenClawDatabaseMaintenanceScope();
if (!scope || !allowsMaintenanceLiveAuthorityReads(scope, pathname)) return { reused: false };
scope.assertReadAdmission();
let readers = maintenanceReaders.get(scope);
if (!readers) {
readers = /* @__PURE__ */ new Map();
maintenanceReaders.set(scope, readers);
}
let reader = readers.get(pathname);
if (!reader) {
const admission = captureOpenClawStateDatabaseReadAdmission(pathname);
assertExistingDatabaseIdentity(pathname, admission.identity.key, admission.identity.birthtime);
const connection = openOpenClawStateReadOnlyLocation(pathname, pathname);
let closed = false;
const close = () => {
if (closed) return;
if (!connection.close()) throw new Error("Maintenance authority reader cleanup is incomplete");
closed = true;
readers.delete(pathname);
unregister();
};
const unregister = registerOpenClawStateDatabaseAsyncResource({ async close(identity) {
if (!identity || identity.key === admission.identity.key || identity.canonicalPath === admission.identity.canonicalPath) close();
} });
scope.own(connection, "shared-handles", close);
reader = { read(readOperation) {
admission.assertCurrent();
assertExistingDatabaseIdentity(pathname, admission.identity.key, admission.identity.birthtime);
assertStateReadSchema(connection.database.db, pathname);
const value = readOperation(connection.database);
if (isPromiseLike(value)) throw new SqliteCoordinatorError("SQLite maintenance authority read must remain synchronous");
return value;
} };
readers.set(pathname, reader);
}
return {
reused: true,
value: reader.read(operation)
};
}
/** Current-authority guards can borrow their writer; discovery sees committed rows. */
function withCachedOpenClawStateDatabaseReadOnly(operation, pathname, currentAuthority) {
const opened = openClawStateDatabaseCache.getCachedOpenClawStateDatabase(pathname, { readOnly: true });
if (!opened?.db.isOpen) return { reused: false };
const ownedTransaction = currentAuthority && isManagedStateTransaction(opened.db);
if (opened.db.isTransaction && !ownedTransaction) return { reused: false };
try {
if (isExistingOpenClawStateSchema(pathname, opened.db)) assertStateReadSchema(opened.db, pathname);
observeOpenClawDatabaseMaintenanceResource(opened.db);
const value = operation(opened);
if (ownedTransaction && isPromiseLike(value)) throw new SqliteCoordinatorError("SQLite current-authority read must remain synchronous");
return {
reused: true,
value
};
} catch (error) {
openClawStateDatabaseCache.evictOpenClawStateDatabaseAfterCorruption(opened, error);
throw error;
}
}
/** A native read borrow can avoid copying only while its original physical path still matches. */
function canReadWarmNativeSourceIndependently(database, pathname, admittedIdentity) {
const identity = requireOpenClawStateDatabaseIdentity(database);
if (identity.key !== admittedIdentity) return false;
try {
assertExistingDatabaseIdentity(pathname, identity.key);
return true;
} catch {
return false;
}
}
//#endregion
//#region src/state/openclaw-state-read-operation.ts
/** Owns query admission and release together, so a later reader can release an earlier slot. */
function startOpenClawStateReadOperation(command, selection) {
const { pathname, snapshot, scopes, context, preserveArtifacts, preferIndependentWarmRead, controller, signal, receipt } = selection;
const resume = AsyncLocalStorage.snapshot();
const result = createDeferredCore();
result.promise.catch(() => void 0);
let outcome = { status: "pending" };
let source;
let transport;
let unregisterSource;
let unregister;
let borrowed;
let prepared;
let preparation;
let preparationClose;
let startPreparedCleanup;
let releasePreparedSource;
let expectedIdentity;
let expectedSourceIdentity;
let awaitedOnly = false;
let producerSettled = false;
let value;
const errors = [];
const acceptanceErrors = [];
let producerStep;
let cleanupStep;
let cleanupAttempt;
let transportStopped = false;
let cleaned = false;
let validated = false;
let servicing = false;
const assertReadLifetime = () => {
signal.throwIfAborted();
context.maintenanceScope?.assertAdmission();
context.admission.assertCurrent();
snapshot?.assertCurrent?.();
borrowed?.assertCurrent();
if (expectedIdentity !== void 0) assertExistingDatabaseIdentity(pathname, expectedIdentity);
if (expectedSourceIdentity) assertExistingDatabaseIdentity(pathname, expectedSourceIdentity.key, expectedSourceIdentity.birthtime);
if (scopes.some((scope) => !scope.active)) throw new Error("Shared-state read scope is closed");
};
const authority = {
signal,
assertCurrent() {
assertReadLifetime();
openClawStateDatabaseCache.assertOpenClawStateDatabaseOpenAllowed(pathname, "cached-read");
}
};
function settle(cleanupErrors = []) {
if (outcome.status !== "pending") return;
try {
throwSqliteLifecycleErrors([
...errors,
...[...new Set(acceptanceErrors)].filter((error) => !errors.includes(error)),
...cleanupErrors
], "Shared-state read and cleanup failed");
outcome = {
status: "fulfilled",
value
};
result.resolve(value);
} catch (error) {
let mapped;
try {
mapped = selection.mapError ? selection.mapError(error, receipt.phase) : error;
} catch (mappingError) {
mapped = mappingError;
}
outcome = {
status: "rejected",
error: mapped
};
result.reject(mapped);
}
}
function finishCleanup(error) {
const attempt = cleanupAttempt;
cleanupAttempt = void 0;
cleanupStep = void 0;
if (error) attempt?.reject(error.error);
else attempt?.resolve();
if (producerSettled) settle(error ? [error.error] : []);
}
function release() {
if (!validated) {
validated = true;
try {
authority.assertCurrent();
} catch (error) {
acceptanceErrors.push(error);
}
}
borrowed?.release();
borrowed = void 0;
snapshot?.release?.();
cleaned = true;
unregister?.();
for (const scope of scopes) scope.resources.delete(resource);
unregisterSource?.();
finishCleanup();
}
function acceptCleanup(success) {
if (!success) throw new Error(`Shared-state read snapshot cleanup failed: ${prepared?.cleanupRoot ?? pathname}`);
prepared = void 0;
startPreparedCleanup = void 0;
closePreparation();
}
function startPreparationClose() {
if (!preparation) return;
if (!preparationClose || preparationClose.read().status === "rejected") {
preparationClose = preparation.startClose();
preparationClose.result.then(service, service);
}
return preparationClose;
}
function closePreparation() {
const closing = startPreparationClose();
if (!closing) {
release();
return;
}
waitRetained("cleanup", closing, () => {
preparation = void 0;
preparationClose = void 0;
release();
});
}
function cleanupPrepared() {
if (!prepared) {
closePreparation();
return;
}
releasePreparedSource?.();
if (startPreparedCleanup) waitRetained("cleanup", startPreparedCleanup(), acceptCleanup);
else {
const pending = prepared.cleanupAsync();
cleanupStep = void 0;
waitAwaited(pending, acceptCleanup, finishCleanup);
}
}
function waitProducer() {
cleanupStep = () => {
if (!producerSettled) {
if (signal.aborted) {
const closing = startPreparationClose();
closing?.service();
const joined = closing?.read();
if (joined?.status === "rejected") throw joined.error;
}
return false;
}
cleanupStep = void 0;
cleanupPrepared();
return true;
};
}
function cleanup() {
if (cleaned) return Promise.resolve();
if (cleanupAttempt) return cleanupAttempt.promise;
const attempt = createDeferredCore();
attempt.promise.catch(() => void 0);
cleanupAttempt = attempt;
try {
if (!transportStopped && transport) waitRetained("cleanup", transport.startClose(), () => {
transportStopped = true;
waitProducer();
});
else waitProducer();
} catch (error) {
finishCleanup({ error });
}
service();
return attempt.promise;
}
function finishProducer(error) {
producerStep = void 0;
producerSettled = true;
if (error) errors.push(error.error);
cleanup();
}
function service() {
if (servicing) return;
servicing = true;
try {
resume(() => {
let changed;
do {
try {
changed = producerStep?.() ?? false;
} catch (error) {
finishProducer({ error });
changed = true;
}
try {
changed = (cleanupStep?.() ?? false) || changed;
} catch (error) {
finishCleanup({ error });
changed = true;
}
} while (changed);
});
} finally {
servicing = false;
}
}
function waitRetained(lane, operation, accept) {
const step = () => {
operation.service();
const next = operation.read();
if (next.status === "pending") return false;
if (lane === "producer") producerStep = void 0;
else cleanupStep = void 0;
if (next.status === "rejected") throw next.error;
accept(next.value);
return true;
};
if (lane === "producer") producerStep = step;
else cleanupStep = step;
operation.result.then(service, service);
}
function waitAwaited(pending, accept, fail) {
pending.then((next) => resume(() => {
try {
accept(next);
} catch (error) {
fail({ error });
}
service();
}), (error) => resume(() => {
fail({ error });
service();
}));
}
function query() {
if (!snapshot && !prepared) expectedIdentity = context.admission.identity.key;
if (prepared) {
authority.assertCurrent();
releasePreparedSource = retainSnapshotTempDirectory(prepared.cleanupRoot ?? path.dirname(prepared.location));
}
receipt.phase = "unobserved";
if (!transport) throw new Error("Shared-state read transport is unavailable");
waitRetained("producer", transport.startRead({
context,
location: prepared?.location ?? snapshot?.location ?? pathname,
checkFreshAdmission: !borrowed,
expectedIdentity,
snapshotRoot: prepared?.cleanupRoot ?? snapshot?.cleanupRoot
}, authority), (readOutcome) => {
const admitted = "error" in readOutcome ? readOutcome.sourceAdmitted : readOutcome.value.type === "admit" ? void 0 : readOutcome.value.sourceAdmitted;
if (admitted === true) receipt.phase = "read";
else if (admitted === false && receipt.phase !== "read") receipt.phase = "before-read";
try {
authority.assertCurrent();
if (admitted) borrowed?.observe();
} catch (error) {
if (!("error" in readOutcome)) throw error;
acceptanceErrors.push(error);
}
if ("error" in readOutcome) throw readOutcome.error;
value = readOutcome.value;
finishProducer();
});
}
const resource = { close() {
controller.abort(/* @__PURE__ */ new Error("Shared-state read admission closed"));
return resume(cleanup);
} };
try {
source = captureOpenClawStateReadSource();
transport = source.createTransport(command);
unregister = registerOpenClawStateDatabaseAsyncResource({ async close(identity) {
if (!identity || identity.key === context.admission.identity.key || identity.canonicalPath === context.admission.identity.canonicalPath) await resource.close();
} });
context.maintenanceScope?.own(resource, "shared-resources", () => resource.close());
for (const scope of scopes) scope.resources.add(resource);
unregisterSource = source.own(service, () => resource.close());
assertReadLifetime();
if (snapshot) openClawStateDatabaseCache.assertOpenClawStateDatabaseOpenAllowed(pathname, "cached-read");
const native = !snapshot && preserveArtifacts ? borrowOpenClawStateDatabaseForAsyncRead(pathname, "cached-read") : void 0;
borrowed = native ?? (!snapshot && !preserveArtifacts ? retainOpenClawStateDatabaseForIndependentRead(pathname, "cached-read") : void 0);
const independentWarmSource = native && preferIndependentWarmRead && canReadWarmNativeSourceIndependently(native.database, pathname, context.admission.identity.key);
if (!snapshot && !borrowed && !existingPathOrUndefined(pathname)) finishProducer();
else if (native && !independentWarmSource) {
awaitedOnly = true;
waitAwaited(prepareSqliteReadOnlyLocationFromOwnedDatabase(native.database.db, authority.assertCurrent, authority.signal, "async"), (location) => {
prepared = location;
query();
}, finishProducer);
} else if (!snapshot && preserveArtifacts && !independentWarmSource) {
expectedSourceIdentity = { key: context.admission.identity.key };
authority.assertCurrent();
waitRetained("producer", transport.startValidateFresh(context, authority), () => {
authority.assertCurrent();
preparation = startSqliteReadOnlyLocationAsync(pathname, {
preserveSourceArtifacts: preserveArtifacts,
signal: authority.signal,
expectedSourceIdentity
});
waitRetained("producer", preparation, (location) => {
prepared = location;
startPreparedCleanup = () => location.startCleanup();
query();
});
});
} else query();
} catch (error) {
finishProducer({ error });
}
service();
return awaitedOnly ? {
kind: "awaited-only",
result: result.promise
} : {
kind: "retained",
operation: {
result: result.promise,
read: () => outcome,
service() {
source?.service();
service();
}
}
};
}
//#endregion
//#region src/state/openclaw-state-read-scope.ts
/** Normal drainage and explicit abort retain the selected callback's context. */
function bindRetainedReadScope(scope) {
const context = scope.work.run(() => AsyncLocalStorage.snapshot());
return {
run: (operation) => context(() => runRetainedReadScope(scope, () => scope.work.track(operation))),
abort: (reason) => context(() => scope.work.beginClose(reason))
};
}
/** Closing retains custody for accepted readers, but never admits a new reader. */
function assertRetainedReadScopeAdmission(pathname, scopes) {
if (scopes.some((scope) => scope?.path === pathname && (!scope.active || scope.work.isClosing))) throw new StateDatabaseReadAdmissionInvalidatedError("Shared-state read scope is closing or closed; retry the operation in a current scope.");
}
function createRetainedReadScope(pathname, identity, cleanup) {
let pending;
let unregister;
const scope = {
path: pathname,
active: true,
work: new AsyncWorkScope(),
resources: /* @__PURE__ */ new Set(),
close() {
if (!scope.active) return Promise.resolve();
unregister ??= registerOpenClawStateDatabaseAsyncResource({ async close(current) {
if (!current || current.key === identity.key || current.canonicalPath === identity.canonicalPath) await scope.close();
} });
return pending ??= (async () => {
await scope.work.drain();
const settled = await Promise.allSettled([...scope.resources].map((resource) => resource.close()));
throwSqliteLifecycleErrors(settled.flatMap((result) => result.status === "rejected" ? [result.reason] : []), "Shared-state read scope drainage failed");
await cleanup?.();
scope.active = false;
unregister?.();
})().finally(() => {
pending = void 0;
});
}
};
return scope;
}
async function runRetainedReadScope(scope, operation) {
let result;
const errors = [];
try {
result = await operation();
} catch (error) {
errors.push(error);
}
try {
await scope.close();
} catch (error) {
errors.push(error);
}
throwSqliteLifecycleErrors(errors, "Shared-state read scope and cleanup failed");
return result;
}
/** Leave synchronous admission before native cleanup can reenter a reader. */
function runSynchronousReadScope(scope, operation) {
let result;
let failed = false;
let failure;
const cleanupErrors = [];
try {
result = operation();
if (isPromiseLike(result)) throw new SqliteCoordinatorError("SQLite metadata snapshot scope must remain synchronous");
} catch (error) {
failed = true;
failure = error;
} finally {
scope.leave();
for (const reader of scope.readers.values()) try {
if (!reader.close()) cleanupErrors.push(/* @__PURE__ */ new Error("Shared-state metadata snapshot cleanup is incomplete."));
} catch (error) {
cleanupErrors.push(error);
}
scope.readers.clear();
}
if (cleanupErrors.length) throw new AggregateError(failed ? [failure, ...cleanupErrors] : cleanupErrors, "Shared-state metadata snapshot cleanup failed.");
if (failed) throw failure;
return result;
}
//#endregion
//#region src/state/openclaw-state-db-readonly.ts
const artifactPreservingReads = resolveGlobalSingleton(Symbol.for("openclaw.artifactPreservingStateReads"), () => new AsyncLocalStorage());
const disposableStateReads = resolveGlobalSingleton(Symbol.for("openclaw.disposableStateReads"), () => new AsyncLocalStorage());
const stateSnapshotReads = resolveGlobalSingleton(Symbol.for("openclaw.stateSnapshotReads"), () => new AsyncLocalStorage());
/** Opaque identity for derived facts scoped to these owned private database bytes. */
function getActiveOpenClawStateDatabaseReadSnapshot(options = {}) {
const current = stateSnapshotReads.getStore();
return current?.path === resolveReadOnlyPath(options) ? current : void 0;
}
/** Resolve a composite read from one online snapshot without redirecting live writers. */
async function withOpenClawStateDatabaseReadSnapshot(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
const current = stateSnapshotReads.getStore();
if (current?.active && current.path === pathname || !existingPathOrUndefined(pathname)) return await operation();
const env = options.env ?? process.env;
const callerSignal = getAsyncWorkSignal();
const controller = new AbortController();
let closeSnapshotWork;
const run = async () => {
let admission;
let prepared;
try {
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
admission = captureOpenClawStateDatabaseReadAdmission(pathname);
controller.signal.throwIfAborted();
if (isArtifactPreservingStateRead() && maintenanceOwnerMayCopySourcesInProcess(getOpenClawDatabaseMaintenanceScope(), pathname) && !openClawStateDatabaseCache.isOpenClawStateDatabaseOpen(pathname)) prepared = prepareSqliteReadOnlyLocationSyncInProcess(pathname);
else prepared = await prepareSqliteReadOnlyLocation(pathname, {
preserveSourceArtifacts: isArtifactPreservingStateRead(),
signal: controller.signal
});
} catch (error) {
throw new Error(`Cannot read shared state for discovery: ${pathname}. Retry after the current state operation completes. ${String(error)}`, { cause: error });
}
const releaseSource = retainSnapshotTempDirectory(prepared.cleanupRoot ?? path.dirname(prepared.location));
const snapshot = Object.assign(createRetainedReadScope(pathname, admission.identity, async () => {
releaseSource();
let cause;
try {
if (await prepared.cleanupAsync()) return;
} catch (error) {
cause = error;
}
throw new SqliteSnapshotCleanupError(`Shared-state discovery snapshot cleanup failed: ${prepared.cleanupRoot ?? pathname}`, { cause });
}), {
location: prepared.location,
cleanupRoot: prepared.cleanupRoot,
env
});
const lifecycle = stateSnapshotReads.run(snapshot, () => bindRetainedReadScope(snapshot));
closeSnapshotWork = lifecycle.abort;
const closeFromCaller = () => lifecycle.abort(callerSignal?.reason);
callerSignal?.addEventListener("abort", closeFromCaller, { once: true });
if (callerSignal?.aborted) closeFromCaller();
try {
return await lifecycle.run(async () => {
controller.signal.throwIfAborted();
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
admission.assertCurrent();
return await operation();
});
} finally {
callerSignal?.removeEventListener("abort", closeFromCaller);
}
};
return await retainSnapshotWork(run(), () => {
controller.abort(/* @__PURE__ */ new Error("Shared-state snapshot admission closed"));
closeSnapshotWork?.(controller.signal.reason);
});
}
/** The caller owns this private database and removes its files after the scope closes. */
async function withDisposableOpenClawStateReads(pathname, operation) {
const resolvedPath = resolveReadOnlyPath({ path: pathname });
const scope = createRetainedReadScope(resolvedPath, captureOpenClawStateDatabaseReadAdmission(resolvedPath).identity);
return await runRetainedReadScope(scope, () => disposableStateReads.run([...disposableStateReads.getStore() ?? [], scope], operation));
}
function requiresArtifactPreservingSnapshot(pathname) {
return isArtifactPreservingStateRead() && !isUpdateRehearsalPrivateDatabase(pathname, process.env) && !disposableStateReads.getStore()?.some((scope) => scope.active && scope.path === pathname);
}
/** Admission scopes every nested reader without changing normal live-read semantics. */
function withArtifactPreservingStateReads(operation) {
return artifactPreservingReads.run(true, operation);
}
function isArtifactPreservingStateRead() {
return artifactPreservingReads.getStore() === true;
}
const synchronousReadSnapshots = resolveGlobalSingleton(Symbol.for("openclaw.synchronousStateReadSnapshots"), () => ({ current: void 0 }));
/** One synchronous metadata operation shares private bytes, never later admission reads. */
function withSynchronousArtifactPreservingStateSnapshot(operation, options) {
if (options?.current) {
const pathname = resolveReadOnlyPath(options.current);
const inherited = synchronousReadSnapshots.current;
const inheritedAuthority = synchronousReadSnapshots.currentAuthorityPath;
if (inherited && inheritedAuthority === pathname) return operation();
return stateSnapshotReads.exit(() => {
synchronousReadSnapshots.current = void 0;
synchronousReadSnapshots.currentAuthorityPath = pathname;
try {
return withArtifactPreservingStateReads(() => withSynchronousArtifactPreservingStateSnapshot(operation));
} finally {
synchronousReadSnapshots.current = inherited;
synchronousReadSnapshots.currentAuthorityPath = inheritedAuthority;
}
});
}
if (!isArtifactPreservingStateRead() || synchronousReadSnapshots.current) return operation();
const readers = /* @__PURE__ */ new Map();
synchronousReadSnapshots.current = readers;
return runSynchronousReadScope({
readers,
leave: () => {
synchronousReadSnapshots.current = void 0;
}
}, operation);
}
function resolveReadOnlyPath(options) {
const pathname = path.resolve(options.path ?? resolveOpenClawStateSqlitePath(options.env ?? process.env));
assertRetainedReadScopeAdmission(pathname, [stateSnapshotReads.getStore(), ...disposableStateReads.getStore() ?? []]);
isExistingOpenClawStateSchema(pathname);
return pathname;
}
function withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname, currentAuthority = false) {
const snapshot = stateSnapshotReads.getStore();
if (snapshot?.active && snapshot.path === pathname) {
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, snapshot.env);
return {
reused: true,
value: withOpenClawStateReadOnlyLocation(operation, pathname, snapshot.location)
};
}
return withCachedOpenClawStateDatabaseReadOnly(operation, pathname, currentAuthority || synchronousReadSnapshots.currentAuthorityPath === pathname);
}
function withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname) {
const env = options.env ?? process.env;
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
if (synchronousReadSnapshots.currentAuthorityPath === pathname) {
const maintained = withMaintenanceOpenClawStateDatabaseReadOnly(operation, pathname);
if (maintained.reused) return maintained.value;
}
const readers = synchronousReadSnapshots.current;
if (readers && requiresArtifactPreservingSnapshot(pathname)) {
let opened = readers.get(pathname);
if (!opened) {
opened = openOpenClawStateReadOnlyLocation(pathname, prepareSqliteReadOnlyLocationSync(pathname));
readers.set(pathname, opened);
}
assertStateReadSchema(opened.database.db, pathname);
const result = operation(opened.database);
if (isPromiseLike(result)) throw new SqliteCoordinatorError("SQLite metadata snapshot read must remain synchronous");
return result;
}
const prepared = requiresArtifactPreservingSnapshot(pathname) ? prepareSqliteReadOnlyLocationSync(pathname) : void 0;
return withOpenClawStateReadOnlyLocation(operation, pathname, prepared ?? pathname);
}
/** Read shared state without joining writers; admission inherits artifact preservation. */
function withOpenClawStateDatabaseReadOnly(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
if (synchronousReadSnapshots.current?.has(pathname)) return withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
return withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname);
}
/** A missing pathname is not absence while this read owner can serve retained state. */
function isOpenClawStateDatabaseDefinitelyAbsent(env = process.env) {
try {
const pathname = resolveReadOnlyPath({ env });
const snapshot = stateSnapshotReads.getStore();
if (synchronousReadSnapshots.current?.has(pathname) || snapshot?.active && snapshot.path === pathname || openClawStateDatabaseCache.getCachedOpenClawStateDatabase(pathname)?.db.isOpen) return false;
try {
lstatSync(pathname);
return false;
} catch (error) {
return hasErrnoCode(error, "ENOENT");
}
} catch {
return false;
}
}
/** Read existing shared state while preserving non-missing filesystem failures. */
function withExistingOpenClawStateDatabaseReadOnly(operation, options = {}) {
const pathname = resolveReadOnlyPath(options);
if (synchronousReadSnapshots.current?.has(pathname)) return withFreshOpenClawStateDatabaseReadOnly(operation, options, pathname);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
const existingPath = existingPathOrUndefined(pathname);
return existingPath === void 0 ? void 0 : withFreshOpenClawStateDatabaseReadOnly(operation, options, existingPath);
}
/** Fixed reads observe committed state unless their owner explicitly selected a snapshot. */
function executeExistingOpenClawStateRead(options, command, readOptions = {}) {
const completion = startExistingOpenClawStateRead(options, command, readOptions);
return completion.kind === "retained" ? completion.operation.result : completion.result;
}
/** Native cached backups remain awaited-only; fresh and inherited readers retain real progress. */
function startExistingOpenClawStateRead(options, command, { context, current, live, mapError, signal, preferIndependentWarmRead } = {}) {
const receipt = { phase: "before-read" };
try {
context?.admission.assertCurrent();
const execute = () => startRetainedOpenClawStateRead(options, command, receipt, mapError, context, signal, current || live, preferIndependentWarmRead);
const read = live ? () => artifactPreservingReads.run(false, () => stateSnapshotReads.exit(execute)) : current ? () => stateSnapshotReads.exit(execute) : execute;
return context?.runInCapturedSchemaScope ? context.runInCapturedSchemaScope(read) : read();
} catch (error) {
throw mapError ? mapError(error, receipt.phase) : error;
}
}
function startRetainedOpenClawStateRead(options, command, receipt, mapError, capturedContext, signal, currentRead = false, preferIndependentWarmRead) {
const pathname = resolveReadOnlyPath(options);
const current = stateSnapshotReads.getStore();
const snapshot = current?.active && current.path === pathname ? current : void 0;
const scopes = [...snapshot ? [snapshot] : [], ...(disposableStateReads.getStore() ?? []).filter((scope) => scope.active && scope.path === pathname)];
const env = snapshot?.env ?? options.env;
const context = capturedContext ?? captureOpenClawStateReadWorkerContext({
path: pathname,
env
});
if (capturedContext) {
if (context.admission.databasePath !== pathname) throw new Error("Shared-state read context does not match its selected source");
context.maintenanceScope?.assertAdmission();
context.admission.assertCurrent();
}
const preserveArtifacts = requiresArtifactPreservingSnapshot(pathname);
const controller = new AbortController();
const readSignal = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
const run = () => {
const inheritedSource = currentRead ? void 0 : synchronousReadSnapshots.current?.get(pathname)?.snapshotSource?.retain();
return startOpenClawStateReadOperation(command, {
pathname,
snapshot: inheritedSource ?? snapshot,
scopes,
context,
preserveArtifacts,
preferIndependentWarmRead,
controller,
signal: readSignal,
receipt,
mapError
});
};
const tracked = scopes.reduceRight((operation, scope) => () => scope.work.run(() => {
const completion = operation();
const result = completion.kind === "retained" ? completion.operation.result : completion.result;
scope.work.track(() => result).catch(() => void 0);
return completion;
}), run);
const maintenance = context.maintenanceScope;
let completion;
if (maintenance) maintenance.run(() => {
const accepted = tracked();
completion = accepted;
return accepted.kind === "retained" ? accepted.operation.result : accepted.result;
});
else completion = tracked();
if (!completion) throw new Error("Shared-state read maintenance scope did not start its operation");
const result = completion.kind === "retained" ? completion.operation.result : completion.result;
retainSnapshotWork(result, () => controller.abort(/* @__PURE__ */ new Error("Shared-state read admission closed")));
return completion;
}
/** Read existing shared state without creating or updating its SQLite sidecars. */
function withExistingOpenClawStateDatabaseArtifactPreservingReadOnly(operation, options = {}, openStateSchemaReadAdmission) {
if (openStateSchemaReadAdmission) return withExistingOpenClawStateDatabaseCurrentReadOnly(operation, options, openStateSchemaReadAdmission);
return withArtifactPreservingStateReads(() => withExistingOpenClawStateDatabaseReadOnly(operation, options));
}
/** Publication guards need current rows, never an inherited discovery snapshot. */
function withExistingOpenClawStateDatabaseCurrentReadOnly(operation, options = {}, openStateSchemaReadAdmission) {
const pathname = resolveReadOnlyPath(options);
return stateSnapshotReads.exit(() => {
if (!openStateSchemaReadAdmission) {
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname, true);
if (reused.reused) return reused.value;
}
if (existingPathOrUndefined(pathname) === void 0) return;
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, options.env ?? process.env);
return withOpenClawStateReadOnlyLocation(operation, pathname, options.allowNativeRead && !isArtifactPreservingStateRead() && !openStateSchemaReadAdmission ? pathname : prepareSqliteReadOnlyLocationSync(pathname), openStateSchemaReadAdmission);
});
}
/** Preserve source artifacts while allowing the caller to progress during snapshot preparation. */
function withExistingOpenClawStateDatabaseArtifactPreservingReadOnlyAsync(operation, options = {}) {
return withArtifactPreservingStateReads(async () => {
const pathname = resolveReadOnlyPath(options);
const reused = withOpenClawStateDatabaseReadOnlyIfOpen(operation, pathname);
if (reused.reused) return reused.value;
if (existingPathOrUndefined(pathname) === void 0) return;
const env = options.env ?? process.env;
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
if (!requiresArtifactPreservingSnapshot(pathname)) return withOpenClawStateReadOnlyLocation(operation, pathname, pathname);
const prepared = await prepareSqliteReadOnlyLocation(pathname, { preserveSourceArtifacts: true });
try {
openClawStateDatabaseCache.assertOpenClawStateDatabaseFreshOpenAllowedAtPath(pathname, env);
} catch (error) {
prepared.cleanup();
throw error;
}
return withOpenClawStateReadOnlyLocation(operation, pathname, prepared);
});
}
function readCurrentOpenClawStateDatabaseContentVersion(options = {}) {
const pathname = resolveReadOnlyPath(options);
const env = options.env ?? process.env;
return stateSnapshotReads.exit(() => readAdmittedStateContentVersion(pathname, env));
}
/** Current guards leave discovery snapshots after validating their inherited read admission. */
function withCurrentOpenClawStateReadScope(options, operation) {
const pathname = resolveReadOnlyPath(options);
return stateSnapshotReads.exit(() => operation(pathname));
}
//#endregion
export { withMaintenanceOpenClawStateDatabaseReadOnly as _, readCurrentOpenClawStateDatabaseContentVersion as a, withDisposableOpenClawStateReads as c, withExistingOpenClawStateDatabaseCurrentReadOnly as d, withExistingOpenClawStateDatabaseReadOnly as f, canReadWarmNativeSourceIndependently as g, withSynchronousArtifactPreservingStateSnapshot as h, isOpenClawStateDatabaseDefinitelyAbsent as i, withExistingOpenClawStateDatabaseArtifactPreservingReadOnly as l, withOpenClawStateDatabaseReadSnapshot as m, getActiveOpenClawStateDatabaseReadSnapshot as n, withArtifactPreservingStateReads as o, withOpenClawStateDatabaseReadOnly as p, isArtifactPreservingStateRead as r, withCurrentOpenClawStateReadScope as s, executeExistingOpenClawStateRead as t, withExistingOpenClawStateDatabaseArtifactPreservingReadOnlyAsync as u };