openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
144 lines (143 loc) • 5.17 kB
JavaScript
import { t as createDeferredCore } from "./deferred-D0La5CRk.mjs";
import { n as assertExistingDatabaseIdentity } from "./sqlite-worker-identity-KSR14F6C.mjs";
import { i as mapRetainedOperation, n as finallyRetainedOperation, r as flatMapRetainedOperation } from "./retained-operation-CODoIe4t.mjs";
import { a as createSqliteLifecycleAggregateError, s as throwSqliteLifecycleErrors } from "./sqlite-lifecycle-errors-DuOygjcn.mjs";
import { S as retainOpenClawStateDatabaseForIndependentRead, _ as registerOpenClawStateDatabaseAsyncResource } from "./openclaw-state-db-cache-BKCnj4of.mjs";
import { t as captureOpenClawStateReadSource } from "./openclaw-state-read-worker-Dz7y6uEu.mjs";
//#region src/state/openclaw-state-settlement-read.ts
/** A fixed read completes an accepted mutation; it grants no new write or path admission. */
async function withOpenClawStateSettlementRead(context, operation) {
context.admission.assertCurrent();
context.maintenanceScope?.assertAdmission();
const pathname = context.admission.databasePath;
const identity = { ...context.admission.identity };
const source = captureOpenClawStateReadSource();
let borrowed = retainOpenClawStateDatabaseForIndependentRead(pathname);
const producer = createDeferredCore();
const controller = new AbortController();
let active = true;
let pending = false;
let selected;
let transport;
let tail;
let nativeSettlement;
let recovery;
let closing;
const authority = {
signal: controller.signal,
assertCurrent() {
if (!active) throw new Error("Shared-state settlement read has released its owner");
borrowed?.assertCurrent();
assertExistingDatabaseIdentity(pathname, identity.key);
}
};
const startRecoveryRead = (read) => {
authority.assertCurrent();
const readTransport = source.createTransport(read.command);
transport = readTransport;
const query = mapRetainedOperation(readTransport.startRead({
context,
location: pathname,
checkFreshAdmission: false,
expectedIdentity: identity.key
}, authority), (outcome) => {
if ("error" in outcome) throw outcome.error;
return outcome.value;
});
const released = finallyRetainedOperation(query, () => mapRetainedOperation(readTransport.startClose(), () => {
transport = void 0;
}), (readError, cleanupError) => createSqliteLifecycleAggregateError([readError, cleanupError], "Shared-state settlement read and cleanup failed", readError));
return mapRetainedOperation(released, (reply) => {
authority.assertCurrent();
if (reply.type !== "userProfiles.reconcile") throw new Error("Unexpected shared-state settlement read reply");
read.publish(reply.profile, reply.emailBindings);
pending = false;
});
};
const recover = () => recovery ??= (async () => {
if (!pending || !selected) return;
nativeSettlement ??= await selected.settlement;
if (nativeSettlement.kind === "not-entered") {
pending = false;
return;
}
const read = selected;
tail = transport ? flatMapRetainedOperation(transport.startClose(), () => {
transport = void 0;
return startRecoveryRead(read);
}) : startRecoveryRead(read);
await tail.result;
})().finally(() => {
tail = void 0;
recovery = void 0;
});
const close = () => closing ??= (async () => {
await producer.promise;
await recover();
if (transport) {
tail = mapRetainedOperation(transport.startClose(), () => {
transport = void 0;
});
await tail.result;
tail = void 0;
}
borrowed?.release();
borrowed = void 0;
selected?.release();
active = false;
unregister();
releaseSource();
})().finally(() => {
closing = void 0;
});
const unregister = registerOpenClawStateDatabaseAsyncResource({ async close(target) {
if (!target || target.key === identity.key || target.canonicalPath === identity.canonicalPath) await close();
} });
const releaseSource = source.own(() => tail?.service(), close);
context.maintenanceScope?.own(producer, "shared-resources", close);
const errors = [];
let result;
try {
result = await operation({
bind(command, settlement, publish, release) {
if (selected || !active) throw new Error("Shared-state settlement read was already bound");
authority.assertCurrent();
selected = {
command: { ...command },
settlement,
publish,
release
};
pending = true;
},
acknowledge(profile, bindings) {
authority.assertCurrent();
if (selected) {
if (!profile || profile.id !== selected.command.profileId) throw new Error("Profile commit differs from its retained settlement read");
selected.publish(profile, bindings);
} else if (profile) throw new Error("Profile commit did not retain its catalog publication");
pending = false;
}
});
} catch (error) {
errors.push(error);
}
let recovered = false;
try {
await recover();
recovered = true;
} catch (error) {
errors.push(error);
} finally {
producer.resolve();
}
if (recovered) try {
await close();
} catch (error) {
errors.push(error);
}
throwSqliteLifecycleErrors(errors, "Shared-state mutation and settlement read failed");
return result;
}
//#endregion
export { withOpenClawStateSettlementRead };