openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
508 lines (505 loc) • 25.3 kB
JavaScript
import { s as normalizeNullableString } from "./string-coerce-1VuiLaaR.mjs";
import "./src-BirUqOZp.mjs";
import { t as stableStringify } from "./stable-stringify-Djn3uxNo.mjs";
import { a as executeSqliteQueryTakeFirstSync, i as executeSqliteQuerySync, o as getNodeSqliteKysely } from "./kysely-sync-DUWzQvCU.mjs";
import { i as tableExists } from "./openclaw-state-db-schema-helpers-DKz5xGgh.mjs";
import { r as runSqliteDeferredTransactionSync } from "./sqlite-transaction-DBRLvCDM.mjs";
import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-DJZ7EKoI.mjs";
import { f as resolveCronJobGrantDefinitionGenerationFloor, p as resolveCronJobGrantDefinitionRevision, s as loadedCronStoreFromRows } from "./row-codec-Fr_vfXdw.mjs";
import { i as mintMcpToolGrantLocked } from "./exec-approvals-sqlite-CbRxT0B7.mjs";
import { r as buildSystemRunApprovalEnvBinding } from "./system-run-approval-binding-Cl9jeqJB.mjs";
import { t as resolveCronJobConfigRevision } from "./config-revision-CA1eZYCq.mjs";
import { r as readCronRunReceiptCurrentFactsInDatabase } from "./run-receipt-read-CcxJup9X.mjs";
import { S as operatorApprovalTerminalFields, _ as requireDecodedRecord, a as clampAuditTimestamp, c as denyCorruptPendingRow, g as requireApprovalId, l as expirePendingRow, m as matchesExpectedApprovalOwner, p as isValidTimestamp, s as decodeOperatorApprovalRow, v as requireString, y as selectOperatorApprovalRow } from "./operator-approval-store.rows-CK66kG3A.mjs";
import { isDeepStrictEqual } from "node:util";
import { randomUUID } from "node:crypto";
//#region src/gateway/operator-approval-standing-grants.ts
const STANDING_GRANT_TABLE = "operator_approval_standing_grants";
const STANDING_GRANT_GENERATION_TABLE = "operator_approval_standing_grant_generations";
const STANDING_GRANT_SCHEMA_SQL = `
CREATE TABLE IF NOT EXISTS operator_approval_standing_grants (
grant_id TEXT NOT NULL PRIMARY KEY CHECK (length(grant_id) > 0),
minted_by_approval_id TEXT NOT NULL
REFERENCES operator_approvals(approval_id) ON DELETE CASCADE,
agent_id TEXT NOT NULL CHECK (length(agent_id) > 0),
cron_job_id TEXT NOT NULL CHECK (length(cron_job_id) > 0),
job_config_revision TEXT NOT NULL CHECK (length(job_config_revision) > 0),
operation_binding TEXT NOT NULL CHECK (length(operation_binding) > 0),
created_at_ms INTEGER NOT NULL,
expires_at_ms INTEGER CHECK (expires_at_ms IS NULL OR expires_at_ms >= created_at_ms),
revoked_at_ms INTEGER,
revoked_by TEXT,
last_used_at_ms INTEGER,
use_count INTEGER NOT NULL DEFAULT 0
) STRICT;
CREATE INDEX IF NOT EXISTS idx_operator_approval_standing_grants_binding
ON operator_approval_standing_grants(agent_id, cron_job_id, operation_binding, created_at_ms DESC);
CREATE TABLE IF NOT EXISTS operator_approval_standing_grant_generations (
grant_id TEXT NOT NULL PRIMARY KEY
REFERENCES operator_approval_standing_grants(grant_id) ON DELETE CASCADE,
job_definition_generation INTEGER NOT NULL CHECK (job_definition_generation >= 1)
) STRICT;
`;
function projectCronStandingGrant(row) {
return {
grantId: row.grant_id,
mintedByApprovalId: row.minted_by_approval_id,
agentId: row.agent_id,
cronJobId: row.cron_job_id,
jobConfigRevision: row.job_config_revision,
operationBinding: row.operation_binding,
createdAtMs: row.created_at_ms,
expiresAtMs: row.expires_at_ms,
lastUsedAtMs: row.last_used_at_ms,
useCount: row.use_count
};
}
/**
* Exact gateway-exec operation binding: trimmed command text, cwd, and the
* env-override hash. Both mint (approval creation) and use (allowlist
* evaluation) derive it from the same raw inputs, so matching is byte-exact —
* the same semantics as systemRunBinding digest matching.
*/
function buildCronExecOperationBinding(params) {
return stableStringify({
v: 1,
command: params.command.trim(),
cwd: params.cwd?.trim() || null,
envHash: buildSystemRunApprovalEnvBinding(params.env).envHash
});
}
/** Parses a stored operation binding back into its display facts. */
function parseCronExecOperationBinding(binding) {
try {
const parsed = JSON.parse(binding);
if (parsed.v !== 1 || typeof parsed.command !== "string") return null;
return {
command: parsed.command,
cwd: typeof parsed.cwd === "string" ? parsed.cwd : null
};
} catch {
return null;
}
}
function ensureStandingGrantSchema(db) {
if (tableExists(db, STANDING_GRANT_TABLE)) {
if (db.prepare(`PRAGMA table_info(${STANDING_GRANT_TABLE})`).all().some((column) => column.name === "expires_at_ms" && column.notnull === 1)) db.exec(`DROP TABLE ${STANDING_GRANT_TABLE};`);
}
db.exec(STANDING_GRANT_SCHEMA_SQL);
}
function decodeDefinitionGeneration(value) {
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1 ? value : null;
}
/**
* Mints one standing grant inside the caller's open write transaction — the
* same transaction that resolves the minting approval to allow-always. A
* re-mint for the same (agent, job, binding) replaces prior grants.
*/
function mintCronStandingGrantLocked(database, params) {
ensureStandingGrantSchema(database.db);
const stateDb = getNodeSqliteKysely(database.db);
executeSqliteQuerySync(database.db, stateDb.deleteFrom(STANDING_GRANT_TABLE).where("expires_at_ms", "is not", null).where("expires_at_ms", "<=", params.nowMs));
const jobRows = executeSqliteQuerySync(database.db, stateDb.selectFrom("cron_jobs").selectAll().where("job_id", "=", params.cronJobId).limit(2)).rows;
if (jobRows.length !== 1) return;
const jobRow = jobRows[0];
const job = loadedCronStoreFromRows(jobRows).store.jobs.find((entry) => entry.id === params.cronJobId);
if (!job || resolveCronJobConfigRevision(job) !== params.jobConfigRevision) return;
const grantDefinitionRevision = resolveCronJobGrantDefinitionRevision(job);
let jobDefinitionGeneration = decodeDefinitionGeneration(jobRow.grant_definition_generation);
if (jobRow.grant_definition_revision !== grantDefinitionRevision || jobRow.grant_definition_updated_at !== jobRow.updated_at || jobDefinitionGeneration === null) {
const retainedGenerationFloor = resolveCronJobGrantDefinitionGenerationFloor(database.db, params.cronJobId);
jobDefinitionGeneration = decodeDefinitionGeneration(Math.max((jobDefinitionGeneration ?? 0) + 1, retainedGenerationFloor));
if (jobDefinitionGeneration === null) return;
executeSqliteQuerySync(database.db, stateDb.updateTable("cron_jobs").set({
grant_definition_revision: grantDefinitionRevision,
grant_definition_generation: jobDefinitionGeneration,
grant_definition_updated_at: jobRow.updated_at
}).where("store_key", "=", jobRow.store_key).where("job_id", "=", jobRow.job_id));
}
executeSqliteQuerySync(database.db, stateDb.deleteFrom(STANDING_GRANT_TABLE).where("agent_id", "=", params.agentId).where("cron_job_id", "=", params.cronJobId).where("operation_binding", "=", params.operationBinding));
const grantId = randomUUID();
executeSqliteQuerySync(database.db, stateDb.insertInto(STANDING_GRANT_TABLE).values({
grant_id: grantId,
minted_by_approval_id: params.approvalId,
agent_id: params.agentId,
cron_job_id: params.cronJobId,
job_config_revision: params.jobConfigRevision,
operation_binding: params.operationBinding,
created_at_ms: params.nowMs,
expires_at_ms: params.expiresAtMs,
revoked_at_ms: null,
revoked_by: null,
last_used_at_ms: null,
use_count: 0
}));
executeSqliteQuerySync(database.db, stateDb.insertInto(STANDING_GRANT_GENERATION_TABLE).values({
grant_id: grantId,
job_definition_generation: jobDefinitionGeneration
}));
}
/** Worker snapshot lookup; only committed consumption authorizes a launch. */
function lookupCronStandingGrantInDatabase(db, params, recordUse) {
return runSqliteDeferredTransactionSync(db, () => {
if (!tableExists(db, STANDING_GRANT_TABLE)) return { outcome: "no-grant" };
const nowMs = params.nowMs ?? Date.now();
const stateDb = getNodeSqliteKysely(db);
const grant = executeSqliteQueryTakeFirstSync(db, stateDb.selectFrom(STANDING_GRANT_TABLE).selectAll().where("agent_id", "=", params.agentId).where("cron_job_id", "=", params.cronJobId).where("operation_binding", "=", params.operationBinding).orderBy("created_at_ms", "desc").orderBy("grant_id", "desc").limit(1));
if (!grant || params.expectedGrant && (grant.grant_id !== params.expectedGrant.grantId || grant.minted_by_approval_id !== params.expectedGrant.mintedByApprovalId)) return { outcome: "no-grant" };
if (grant.revoked_at_ms !== null) return { outcome: "revoked" };
if (grant.expires_at_ms !== null && grant.expires_at_ms <= nowMs) return { outcome: "expired" };
if (grant.job_config_revision !== params.jobConfigRevision) return { outcome: "job-revision-changed" };
const jobRows = executeSqliteQuerySync(db, stateDb.selectFrom("cron_jobs").selectAll().where("job_id", "=", params.cronJobId).limit(2)).rows;
if (jobRows.length !== 1) return { outcome: "job-missing" };
const job = loadedCronStoreFromRows(jobRows).store.jobs.find((entry) => entry.id === params.cronJobId);
if (!job) return { outcome: "job-missing" };
if (resolveCronJobConfigRevision(job) !== grant.job_config_revision) return { outcome: "job-revision-changed" };
const jobRow = jobRows[0];
if (jobRow.grant_definition_revision !== resolveCronJobGrantDefinitionRevision(job)) return { outcome: "job-revision-changed" };
if (jobRow.grant_definition_updated_at !== jobRow.updated_at) return { outcome: "job-revision-changed" };
const grantGeneration = decodeDefinitionGeneration((tableExists(db, STANDING_GRANT_GENERATION_TABLE) ? executeSqliteQueryTakeFirstSync(db, stateDb.selectFrom(STANDING_GRANT_GENERATION_TABLE).select("job_definition_generation").where("grant_id", "=", grant.grant_id)) : void 0)?.job_definition_generation);
const jobGeneration = decodeDefinitionGeneration(jobRow.grant_definition_generation);
if (grantGeneration === null || jobGeneration === null || grantGeneration !== jobGeneration) return { outcome: "job-revision-changed" };
const { handle } = params;
const facts = readCronRunReceiptCurrentFactsInDatabase(db, {
type: "cron.currentReceipt",
handle,
includeJob: false,
includeAvailability: true
});
if (!isDeepStrictEqual(facts.receipt, handle) || facts.deletionBlocked || handle.agentId !== params.agentId || handle.jobId !== params.cronJobId || handle.storeKey !== jobRow.store_key || handle.configRevision !== params.jobConfigRevision || job.agentId !== void 0 && job.agentId !== handle.agentId) return { outcome: "receipt-not-current" };
const approvalRow = executeSqliteQueryTakeFirstSync(db, stateDb.selectFrom("operator_approvals").select(["status", "decision"]).where("approval_id", "=", grant.minted_by_approval_id));
if (!approvalRow) return { outcome: "approval-missing" };
if (approvalRow.status !== "allowed" || approvalRow.decision !== "allow-always") return { outcome: "approval-not-allow-always" };
if (!recordUse) return {
outcome: "consumed",
grant: projectCronStandingGrant(grant)
};
const nextUseCount = grant.use_count + 1;
if (executeSqliteQuerySync(db, stateDb.updateTable(STANDING_GRANT_TABLE).set({
last_used_at_ms: nowMs,
use_count: nextUseCount
}).where("grant_id", "=", grant.grant_id).where("revoked_at_ms", "is", null).where((eb) => eb.or([eb("expires_at_ms", "is", null), eb("expires_at_ms", ">", nowMs)]))).numAffectedRows !== 1n) return { outcome: "no-grant" };
return {
outcome: "consumed",
grant: {
...projectCronStandingGrant(grant),
lastUsedAtMs: nowMs,
useCount: nextUseCount
}
};
});
}
/** Called only by the existing shared-state writer transaction. */
function consumeCronStandingGrantInDatabase(params) {
return runOpenClawStateWriteTransaction(({ db }) => lookupCronStandingGrantInDatabase(db, params, params.recordUse), params.databaseOptions);
}
/** Repeated revocation preserves the original actor and timestamp. */
function revokeCronStandingGrantInDatabase(params) {
return runOpenClawStateWriteTransaction((database) => {
if (!tableExists(database.db, STANDING_GRANT_TABLE)) return { outcome: "not-found" };
const nowMs = params.nowMs ?? Date.now();
const stateDb = getNodeSqliteKysely(database.db);
const grant = executeSqliteQueryTakeFirstSync(database.db, stateDb.selectFrom(STANDING_GRANT_TABLE).selectAll().where("grant_id", "=", params.grantId));
if (!grant) return { outcome: "not-found" };
if (grant.revoked_at_ms !== null) return { outcome: "already-revoked" };
executeSqliteQuerySync(database.db, stateDb.updateTable(STANDING_GRANT_TABLE).set({
revoked_at_ms: nowMs,
revoked_by: params.revokedBy
}).where("grant_id", "=", params.grantId).where("revoked_at_ms", "is", null));
return {
outcome: "revoked",
grant: {
...projectCronStandingGrant(grant),
cronJobName: null,
revokedAtMs: nowMs,
revokedBy: params.revokedBy
}
};
}, params.databaseOptions);
}
//#endregion
//#region src/gateway/operator-approval-store.transitions.ts
function resolveOperatorApprovalInDatabase(params) {
const id = requireApprovalId(params.id);
const resolverId = normalizeNullableString(params.resolver.id);
const runtimeEpoch = params.runtimeEpoch === void 0 ? void 0 : requireString(params.runtimeEpoch, "operator approval runtime epoch");
return runOpenClawStateWriteTransaction((database) => {
const nowMs = params.nowMs ?? Date.now();
let row = selectOperatorApprovalRow(database, id);
if (!row) return { outcome: "not-found" };
if (!matchesExpectedApprovalOwner({
row,
expectedKind: params.expectedKind,
runtimeEpoch
})) return { outcome: "not-found" };
let record = decodeOperatorApprovalRow(row);
if (!record) {
denyCorruptPendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
return { outcome: "corrupt" };
}
if (record.status !== "pending") return {
outcome: "already-resolved",
retry: record.decision === params.decision ? "same" : "conflict",
record
};
if (record.expiresAtMs <= nowMs) {
row = expirePendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
if (!row) return { outcome: "not-found" };
record = requireDecodedRecord(row);
return {
outcome: "expired",
record
};
}
if (!Array.prototype.includes.call(record.presentation.allowedDecisions, params.decision)) return {
outcome: "decision-not-allowed",
record
};
const auditTimestampMs = clampAuditTimestamp(nowMs, record.createdAtMs);
let resolveQuery = getNodeSqliteKysely(database.db).updateTable("operator_approvals").set(operatorApprovalTerminalFields(params.decision === "deny" ? "denied" : "allowed", "user", auditTimestampMs, params.decision, {
kind: params.resolver.kind,
id: resolverId
})).where("approval_id", "=", id).where("status", "=", "pending").where("expires_at_ms", ">", nowMs);
if (params.expectedKind !== void 0) resolveQuery = resolveQuery.where("kind", "=", params.expectedKind);
if (runtimeEpoch !== void 0) resolveQuery = resolveQuery.where("runtime_epoch", "=", runtimeEpoch);
const result = executeSqliteQuerySync(database.db, resolveQuery);
row = selectOperatorApprovalRow(database, id);
if (!row) return { outcome: "not-found" };
record = requireDecodedRecord(row);
if (result.numAffectedRows === 1n) {
if (params.decision === "allow-always" && params.mcpToolGrant && record.kind === "plugin" && record.source.agentId === params.mcpToolGrant.agentId) mintMcpToolGrantLocked(database.db, params.mcpToolGrant, auditTimestampMs);
if (params.decision === "allow-always" && params.standingGrant) mintCronStandingGrantLocked(database, {
...params.standingGrant,
approvalId: id,
nowMs: auditTimestampMs
});
return {
outcome: "resolved",
record
};
}
if (record.status === "pending" && record.expiresAtMs <= nowMs) {
const expiredRow = expirePendingRow({
database,
id,
nowMs,
createdAtMs: record.createdAtMs
});
if (!expiredRow) return { outcome: "not-found" };
return {
outcome: "expired",
record: requireDecodedRecord(expiredRow)
};
}
return {
outcome: "already-resolved",
retry: record.decision === params.decision ? "same" : "conflict",
record
};
}, params.databaseOptions);
}
function forceDenyOperatorApprovalInDatabase(params) {
const id = requireApprovalId(params.id);
const runtimeEpoch = params.runtimeEpoch === void 0 ? void 0 : requireString(params.runtimeEpoch, "operator approval runtime epoch");
return runOpenClawStateWriteTransaction((database) => {
const nowMs = params.nowMs ?? Date.now();
const row = selectOperatorApprovalRow(database, id);
if (!row) return { outcome: "not-found" };
if (!matchesExpectedApprovalOwner({
row,
expectedKind: params.expectedKind,
runtimeEpoch
})) return { outcome: "not-found" };
if (row.status === "pending" && row.expires_at_ms <= nowMs) {
const expiredRow = expirePendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
if (!expiredRow) return { outcome: "not-found" };
const expiredRecord = decodeOperatorApprovalRow(expiredRow);
return expiredRecord ? {
outcome: "expired",
record: expiredRecord
} : { outcome: "corrupt" };
}
const record = decodeOperatorApprovalRow(row);
if (!record) {
denyCorruptPendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
return { outcome: "corrupt" };
}
if (record.status !== "pending") return {
outcome: "already-terminal",
record
};
if (params.status === "expired" && params.requireDue === true && record.expiresAtMs > nowMs) return {
outcome: "not-due",
record
};
const auditTimestampMs = clampAuditTimestamp(nowMs, record.createdAtMs);
let denyQuery = getNodeSqliteKysely(database.db).updateTable("operator_approvals").set(operatorApprovalTerminalFields(params.status ?? "denied", params.reason, auditTimestampMs, "deny", {
kind: params.resolver.kind,
id: normalizeNullableString(params.resolver.id)
})).where("approval_id", "=", id).where("status", "=", "pending");
if (params.expectedKind !== void 0) denyQuery = denyQuery.where("kind", "=", params.expectedKind);
if (runtimeEpoch !== void 0) denyQuery = denyQuery.where("runtime_epoch", "=", runtimeEpoch);
executeSqliteQuerySync(database.db, denyQuery);
const terminalRow = selectOperatorApprovalRow(database, id);
if (!terminalRow) return { outcome: "not-found" };
return {
outcome: "denied",
record: requireDecodedRecord(terminalRow)
};
}, params.databaseOptions);
}
function expireDueOperatorApprovalsInDatabase(params) {
return runOpenClawStateWriteTransaction((database) => {
const nowMs = params.nowMs ?? Date.now();
const stateDb = getNodeSqliteKysely(database.db);
const dueRows = executeSqliteQuerySync(database.db, stateDb.selectFrom("operator_approvals").selectAll().where("status", "=", "pending").where("expires_at_ms", "<=", nowMs).orderBy("expires_at_ms", "asc").orderBy("approval_id", "asc")).rows;
if (dueRows.length === 0) return {
affected: 0,
records: []
};
const terminalFields = operatorApprovalTerminalFields("expired", "timeout", nowMs);
const result = executeSqliteQuerySync(database.db, stateDb.updateTable("operator_approvals").set(terminalFields).where("status", "=", "pending").where("expires_at_ms", "<=", nowMs));
return {
affected: Number(result.numAffectedRows ?? 0n),
records: dueRows.map((row) => decodeOperatorApprovalRow({
...row,
...terminalFields
})).filter((record) => record !== null)
};
}, params.databaseOptions);
}
function closeOrphanedOperatorApprovals(params) {
const runtimeEpoch = requireString(params.runtimeEpoch, "operator approval runtime epoch");
return runOpenClawStateWriteTransaction((database) => {
const nowMs = params.nowMs ?? Date.now();
const stateDb = getNodeSqliteKysely(database.db);
const orphanRows = executeSqliteQuerySync(database.db, stateDb.selectFrom("operator_approvals").selectAll().where("status", "=", "pending").where("runtime_epoch", "!=", runtimeEpoch).orderBy("created_at_ms", "asc").orderBy("approval_id", "asc")).rows;
if (orphanRows.length === 0) return {
affected: 0,
records: []
};
let affected = 0;
const terminalRows = [];
for (const row of orphanRows) {
const auditTimestampMs = clampAuditTimestamp(nowMs, row.created_at_ms);
const terminalFields = operatorApprovalTerminalFields("cancelled", "gateway-restart", auditTimestampMs);
const result = executeSqliteQuerySync(database.db, stateDb.updateTable("operator_approvals").set(terminalFields).where("approval_id", "=", row.approval_id).where("status", "=", "pending"));
const rowAffected = Number(result.numAffectedRows ?? 0n);
affected += rowAffected;
if (rowAffected === 1) terminalRows.push({
...row,
...terminalFields
});
}
return {
affected,
records: terminalRows.map((row) => decodeOperatorApprovalRow(row)).filter((record) => record !== null)
};
}, params.databaseOptions);
}
function consumeOperatorApprovalAllowOnceInDatabase(params) {
const id = requireApprovalId(params.id);
const consumerId = requireString(params.consumerId, "operator approval consumer id");
const runtimeEpoch = params.runtimeEpoch === void 0 ? void 0 : requireString(params.runtimeEpoch, "operator approval runtime epoch");
if (params.redemptionWindowMs !== void 0 && !isValidTimestamp(params.redemptionWindowMs)) throw new Error("operator approval redemption window must be a non-negative safe integer");
return runOpenClawStateWriteTransaction((database) => {
const nowMs = params.nowMs ?? Date.now();
const redemptionThresholdMs = params.redemptionWindowMs === void 0 ? void 0 : nowMs - params.redemptionWindowMs;
let row = selectOperatorApprovalRow(database, id);
if (!row) return { outcome: "not-found" };
if (!matchesExpectedApprovalOwner({
row,
expectedKind: params.expectedKind,
runtimeEpoch
})) return { outcome: "not-found" };
if (row.status === "pending" && row.expires_at_ms <= nowMs) {
row = expirePendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
if (!row) return { outcome: "not-found" };
}
let record = decodeOperatorApprovalRow(row);
if (!record) {
denyCorruptPendingRow({
database,
id,
nowMs,
createdAtMs: row.created_at_ms
});
return { outcome: "corrupt" };
}
if (record.status !== "allowed" || record.decision !== "allow-once") return {
outcome: "not-allow-once",
record
};
if (record.consumedAtMs !== null) return {
outcome: "already-consumed",
record
};
if (record.resolvedAtMs === null) return { outcome: "corrupt" };
if (redemptionThresholdMs !== void 0 && record.resolvedAtMs <= redemptionThresholdMs) return {
outcome: "redemption-expired",
record
};
const auditTimestampMs = clampAuditTimestamp(nowMs, record.createdAtMs, record.resolvedAtMs, record.updatedAtMs);
let consumeQuery = getNodeSqliteKysely(database.db).updateTable("operator_approvals").set({
consumed_at_ms: auditTimestampMs,
consumed_by: consumerId,
updated_at_ms: auditTimestampMs
}).where("approval_id", "=", id).where("status", "=", "allowed").where("decision", "=", "allow-once").where("consumed_at_ms", "is", null);
if (redemptionThresholdMs !== void 0) consumeQuery = consumeQuery.where("resolved_at_ms", ">", redemptionThresholdMs);
if (params.expectedKind !== void 0) consumeQuery = consumeQuery.where("kind", "=", params.expectedKind);
if (runtimeEpoch !== void 0) consumeQuery = consumeQuery.where("runtime_epoch", "=", runtimeEpoch);
const result = executeSqliteQuerySync(database.db, consumeQuery);
row = selectOperatorApprovalRow(database, id);
if (!row) return { outcome: "not-found" };
record = requireDecodedRecord(row);
if (result.numAffectedRows === 1n) return {
outcome: "consumed",
record
};
if (redemptionThresholdMs !== void 0 && record.resolvedAtMs !== null && record.resolvedAtMs <= redemptionThresholdMs) return {
outcome: "redemption-expired",
record
};
return {
outcome: "already-consumed",
record
};
}, params.databaseOptions);
}
function pruneTerminalOperatorApprovals(params) {
const retentionMs = params.retentionMs ?? 2592e6;
if (!Number.isSafeInteger(retentionMs) || retentionMs < 0) throw new Error("operator approval retention must be a non-negative safe integer");
return runOpenClawStateWriteTransaction((database) => {
const cutoffMs = (params.nowMs ?? Date.now()) - retentionMs;
const stateDb = getNodeSqliteKysely(database.db);
const result = executeSqliteQuerySync(database.db, stateDb.deleteFrom("operator_approvals").where("status", "!=", "pending").where("resolved_at_ms", "is not", null).where("resolved_at_ms", "<=", cutoffMs));
return Number(result.numAffectedRows ?? 0n);
}, params.databaseOptions);
}
//#endregion
export { pruneTerminalOperatorApprovals as a, consumeCronStandingGrantInDatabase as c, forceDenyOperatorApprovalInDatabase as i, parseCronExecOperationBinding as l, consumeOperatorApprovalAllowOnceInDatabase as n, resolveOperatorApprovalInDatabase as o, expireDueOperatorApprovalsInDatabase as r, buildCronExecOperationBinding as s, closeOrphanedOperatorApprovals as t, revokeCronStandingGrantInDatabase as u };