openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
499 lines (498 loc) • 19.7 kB
JavaScript
import { l as normalizeOptionalString } from "./string-coerce-1VuiLaaR.mjs";
import { c as isRecord } from "./record-coerce-TIsquoVR.mjs";
import { t as normalizeControlUiBasePath } from "./control-ui-shared-DqFhbHR8.mjs";
import { t as _usingCtx } from "./usingCtx-DwOBYOJf.mjs";
import { h as validateApprovalResolveParams, m as validateApprovalHistoryParams, p as validateApprovalGetParams } from "./src-l2dWvEsN.mjs";
import { n as isWellFormedApprovalId } from "./approval-id-BTRnO3t1.mjs";
import { t as ErrorCodes } from "./gateway-error-details-DIefe7Zy.mjs";
import { f as errorShape } from "./error-codes-Dh56LniQ.mjs";
import { i as OperatorApprovalHistoryCursorError } from "./operator-approval-store.rows-CUyuQiIg.mjs";
import { d as prepareApprovalChannelCustody, u as respondApprovalStorageUnavailable } from "./approval-shared-HH3f7vXt.mjs";
import { t as canAccessApprovalSession } from "./approval-record-lookup-MqaA3N6s.mjs";
import { i as getOperatorApprovalDetailed, o as isOperatorApprovalStoreOutcomeUnknown, s as isOperatorApprovalStoreRefusal, u as listTerminalOperatorApprovals } from "./operator-approval-store-cPImwg80.mjs";
import { n as canResolveOperatorApproval, r as canReviewOperatorApproval, t as canAccessOperatorApproval } from "./operator-approval-authorization-BCjW3avN.mjs";
import { t as projectOperatorApprovalSnapshot } from "./operator-approval-snapshot-DiSAwAzh.mjs";
import { t as publishAppliedApprovalResolution } from "./approval-publication-RHfPEwnM.mjs";
import { t as createApprovalRequestAuthority } from "./approval-request-authority-CSVE0CJ5.mjs";
//#region src/gateway/server-methods/approval-visible-record.ts
async function loadVisibleApproval(params) {
const authorized = params.allowApprovalRuntime ? canResolveOperatorApproval(params.client) : canReviewOperatorApproval(params.client);
if (!params.authority.isCurrent() || !authorized || params.client?.invalidated) return null;
const liveRecord = params.execApprovalManager.getLiveSnapshot(params.id) ?? params.pluginApprovalManager.getLiveSnapshot(params.id) ?? params.systemAgentApprovalManager?.getLiveSnapshot(params.id);
if (liveRecord && !canAccessApprovalSession({
cfg: params.getCfg(),
client: params.client,
sessionKey: liveRecord.request.sessionKey,
agentId: liveRecord.request.agentId
})) return null;
if (liveRecord && !canAccessOperatorApproval({
client: params.client,
allowApprovalRuntime: params.allowApprovalRuntime,
binding: { reviewerDeviceIds: liveRecord.approvalReviewerDeviceIds }
})) return null;
let bindingId = params.id;
let admittedRecord = liveRecord?.resolvedAtMs === void 0 ? liveRecord : void 0;
let admittedManager = admittedRecord ? [
params.execApprovalManager,
params.pluginApprovalManager,
params.systemAgentApprovalManager
].find((manager) => manager?.getLocalSnapshot(params.id) === admittedRecord) : void 0;
let sourceSessionKey = admittedRecord?.request.sessionKey;
let sourceAgentId = admittedRecord?.request.agentId;
if (admittedRecord) params.authority.bindSource(admittedRecord.request);
const assertBindingCurrent = () => {
if (admittedRecord && (admittedManager?.getLocalSnapshot(bindingId) !== admittedRecord || admittedRecord.request.sessionKey !== sourceSessionKey || admittedRecord.request.agentId !== sourceAgentId || !canAccessOperatorApproval({
client: params.client,
allowApprovalRuntime: params.allowApprovalRuntime,
binding: { reviewerDeviceIds: admittedRecord.approvalReviewerDeviceIds }
}))) throw new Error("Approval lookup authority is no longer active");
};
const lookupAuthority = {
assertCurrent: () => {
params.authority.assertCurrent();
assertBindingCurrent();
},
guard: {
family: params.authority.guard.family,
assertCurrent: () => {
params.authority.assertCommitCurrent();
assertBindingCurrent();
}
}
};
const isLookupCurrent = () => {
try {
lookupAuthority.assertCurrent();
return true;
} catch {
return false;
}
};
const reconcile = async (manager, value) => {
try {
return await manager?.reconcileDurableLookup(value, null, lookupAuthority);
} catch (error) {
if (!isLookupCurrent()) return null;
throw error;
}
};
let lookup;
try {
lookup = await getOperatorApprovalDetailed({
id: params.id,
allowTransportRef: params.allowTransportRef,
databaseOptions: params.databaseOptions,
guard: lookupAuthority.guard
});
} catch (error) {
if (!isLookupCurrent()) return null;
if (isOperatorApprovalStoreRefusal(error) || isOperatorApprovalStoreOutcomeUnknown(error)) throw error;
const corrupt = {
outcome: "corrupt",
id: params.id
};
await reconcile(params.execApprovalManager, corrupt);
await reconcile(params.pluginApprovalManager, corrupt);
await reconcile(params.systemAgentApprovalManager, corrupt);
throw error;
}
if (!isLookupCurrent() || params.client?.invalidated || !(params.allowApprovalRuntime ? canResolveOperatorApproval(params.client) : canReviewOperatorApproval(params.client))) return null;
if (lookup.outcome === "found") {
if (!canAccessApprovalSession({
cfg: params.getCfg(),
client: params.client,
sessionKey: lookup.record.source.sessionKey,
agentId: lookup.record.source.agentId
})) return null;
if (!canAccessOperatorApproval({
client: params.client,
allowApprovalRuntime: params.allowApprovalRuntime,
binding: { reviewerDeviceIds: lookup.record.reviewerDeviceIds }
})) return null;
params.authority.bindSource(lookup.record.source);
const manager = lookup.record.kind === "exec" ? params.execApprovalManager : lookup.record.kind === "plugin" ? params.pluginApprovalManager : params.systemAgentApprovalManager;
if (lookup.record.status === "pending") {
const current = manager?.getLocalSnapshot(lookup.record.id);
if (current) {
if ((normalizeOptionalString(current.request.sessionKey) ?? null) !== lookup.record.source.sessionKey || (normalizeOptionalString(current.request.agentId) ?? null) !== lookup.record.source.agentId || !canAccessOperatorApproval({
client: params.client,
allowApprovalRuntime: params.allowApprovalRuntime,
binding: { reviewerDeviceIds: current.approvalReviewerDeviceIds }
})) return null;
if (!admittedRecord) {
bindingId = lookup.record.id;
admittedRecord = current;
admittedManager = manager;
sourceSessionKey = current.request.sessionKey;
sourceAgentId = current.request.agentId;
}
}
}
const reconciled = await reconcile(manager, lookup);
if (!reconciled) return null;
return {
guard: lookupAuthority.guard,
readCurrent: () => params.authority.isCurrent() && (reconciled.status !== "pending" || isLookupCurrent()) && !params.client?.invalidated && canAccessApprovalSession({
cfg: params.getCfg(),
client: params.client,
sessionKey: reconciled.source.sessionKey,
agentId: reconciled.source.agentId
}) && canAccessOperatorApproval({
client: params.client,
allowApprovalRuntime: params.allowApprovalRuntime,
binding: { reviewerDeviceIds: reconciled.reviewerDeviceIds }
}) ? reconciled : null
};
}
const missing = {
outcome: lookup.outcome === "corrupt" ? "corrupt" : "missing",
id: lookup.outcome === "corrupt" ? lookup.id ?? params.id : params.id
};
await reconcile(params.execApprovalManager, missing);
await reconcile(params.pluginApprovalManager, missing);
await reconcile(params.systemAgentApprovalManager, missing);
return null;
}
//#endregion
//#region src/gateway/server-methods/approval.ts
function buildApprovalSnapshot(record, controlUiBasePath) {
const snapshot = projectOperatorApprovalSnapshot(record, controlUiBasePath);
if (!snapshot || snapshot.status === "pending") return snapshot;
return {
...snapshot,
source: {
...record.source.agentId ? { agentId: record.source.agentId } : {},
...record.source.sessionKey ? { sessionKey: record.source.sessionKey } : {}
},
...record.resolver ? { resolver: {
kind: record.resolver.kind,
...record.resolver.id ? { id: record.resolver.id } : {}
} } : {}
};
}
function resolveApprovalResolver(client) {
const deviceId = normalizeOptionalString(client?.connect?.device?.id);
if (deviceId) return {
kind: "device",
id: deviceId
};
return {
kind: "runtime",
id: normalizeOptionalString(client?.connect?.client?.id) ?? null
};
}
function resolveLegacyApprovalLabel(client) {
return normalizeOptionalString(client?.connect?.client?.displayName) ?? normalizeOptionalString(client?.connect?.client?.id) ?? null;
}
function respondApprovalNotFound(respond) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "approval not found", { details: { reason: ErrorCodes.APPROVAL_NOT_FOUND } }));
}
function readExactApprovalId(params) {
if (!isRecord(params) || typeof params.id !== "string") return null;
const id = params.id;
return isWellFormedApprovalId(id) ? id : null;
}
async function applyApprovalDecision(params) {
const result = params.forceMalformedDeny ? await params.manager.forceDenyDetailed(params.id, "malformed-verdict", params.resolver, "denied", void 0, false, params.localResolvedBy, void 0, params.guard) : await params.manager.resolveDetailed(params.id, params.decision, params.resolver, params.localResolvedBy, "operator", {
guard: params.guard,
...params.grantExpiresAtMs !== void 0 ? { grantExpiresAtMs: params.grantExpiresAtMs } : {}
});
if (result.outcome === "decision-not-allowed") return applyApprovalDecision({
...params,
forceMalformedDeny: true
});
if (result.outcome === "not-found" || result.outcome === "corrupt") return { ok: false };
const applied = result.outcome === "resolved" || result.outcome === "denied";
return {
ok: true,
applied,
record: result.record,
liveRecord: applied ? result.liveRecord ?? params.manager.getLiveSnapshot(params.id) ?? void 0 : result.liveRecord
};
}
function createApprovalHandlers(params) {
return {
"approval.history": async (options) => {
try {
var _usingCtx$1 = _usingCtx();
const { params: rawParams, respond, client, context } = options;
const authority = _usingCtx$1.u(createApprovalRequestAuthority(options));
if (!validateApprovalHistoryParams(rawParams)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "invalid approval.history params"));
return;
}
if (!authority.isCurrent()) {
respondApprovalNotFound(respond);
return;
}
let history;
try {
history = await listTerminalOperatorApprovals({
cursor: rawParams.cursor,
limit: rawParams.limit,
kind: rawParams.kind,
databaseOptions: params.databaseOptions,
guard: authority.guard
});
} catch (error) {
if (!authority.isCurrent()) {
respondApprovalNotFound(respond);
return;
}
if (error instanceof OperatorApprovalHistoryCursorError) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "invalid approval.history cursor"));
return;
}
respondApprovalStorageUnavailable({
context,
respond,
operation: "history",
error
});
return;
}
if (!authority.isCurrent()) {
respondApprovalNotFound(respond);
return;
}
const cfg = context.getRuntimeConfig();
const controlUiBasePath = normalizeControlUiBasePath(cfg.gateway?.controlUi?.basePath);
respond(true, {
items: history.records.flatMap((record) => {
if (!canAccessApprovalSession({
cfg,
client,
sessionKey: record.source.sessionKey,
agentId: record.source.agentId
})) return [];
const snapshot = buildApprovalSnapshot(record, controlUiBasePath);
return snapshot && snapshot.status !== "pending" ? [snapshot] : [];
}),
...history.nextCursor ? { nextCursor: history.nextCursor } : {}
}, void 0);
} catch (_) {
_usingCtx$1.e = _;
} finally {
_usingCtx$1.d();
}
},
"approval.get": async (options) => {
try {
var _usingCtx3 = _usingCtx();
const { params: rawParams, respond, client, context } = options;
const authority = _usingCtx3.u(createApprovalRequestAuthority(options));
if (!validateApprovalGetParams(rawParams)) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, "invalid approval.get params"));
return;
}
const id = readExactApprovalId(rawParams);
let record;
try {
record = (id ? await loadVisibleApproval({
id,
authority,
client,
getCfg: () => context.getRuntimeConfig(),
execApprovalManager: params.execApprovalManager,
pluginApprovalManager: params.pluginApprovalManager,
systemAgentApprovalManager: params.systemAgentApprovalManager,
databaseOptions: params.databaseOptions
}) : null)?.readCurrent() ?? null;
} catch (error) {
if (!authority.isCurrent()) {
respondApprovalNotFound(respond);
return;
}
respondApprovalStorageUnavailable({
context,
respond,
operation: "lookup",
error
});
return;
}
const controlUiBasePath = normalizeControlUiBasePath(context.getRuntimeConfig()?.gateway?.controlUi?.basePath);
const approval = record ? buildApprovalSnapshot(record, controlUiBasePath) : null;
if (!approval) {
respondApprovalNotFound(respond);
return;
}
respond(true, { approval }, void 0);
} catch (_) {
_usingCtx3.e = _;
} finally {
_usingCtx3.d();
}
},
"approval.resolve": async (options) => {
try {
var _usingCtx4 = _usingCtx();
const { params: rawParams, respond, client, context } = options;
const authority = _usingCtx4.u(createApprovalRequestAuthority(options));
const validParams = validateApprovalResolveParams(rawParams);
const resolveParams = validParams ? rawParams : null;
if (isRecord(rawParams) && "reviewer" in rawParams && !resolveParams?.reviewer) {
respondApprovalNotFound(respond);
return;
}
const id = readExactApprovalId(rawParams);
let record;
let prepared;
try {
prepared = id ? await loadVisibleApproval({
id,
authority,
client,
getCfg: () => context.getRuntimeConfig(),
allowApprovalRuntime: true,
allowTransportRef: true,
execApprovalManager: params.execApprovalManager,
pluginApprovalManager: params.pluginApprovalManager,
systemAgentApprovalManager: params.systemAgentApprovalManager,
databaseOptions: params.databaseOptions
}) : null;
record = prepared?.readCurrent() ?? null;
} catch (error) {
if (!authority.isCurrent()) {
respondApprovalNotFound(respond);
return;
}
respondApprovalStorageUnavailable({
context,
respond,
operation: "lookup",
error
});
return;
}
if (!id || !record || !prepared) {
respondApprovalNotFound(respond);
return;
}
const { guard: approvalGuard, readCurrent } = prepared;
const custody = resolveParams?.reviewer ? prepareApprovalChannelCustody({
cfg: context.getRuntimeConfig(),
approvalKind: record.kind,
reviewer: resolveParams.reviewer
}) : null;
const liveRecord = record.kind === "exec" ? params.execApprovalManager.getLiveSnapshot(record.id) : record.kind === "plugin" ? params.pluginApprovalManager.getLiveSnapshot(record.id) : params.systemAgentApprovalManager?.getLiveSnapshot(record.id);
if (resolveParams?.reviewer && (!custody || !liveRecord || !custody.authorizes(liveRecord))) {
respondApprovalNotFound(respond);
return;
}
if (record.status !== "pending") {
const controlUiBasePath = normalizeControlUiBasePath(context.getRuntimeConfig()?.gateway?.controlUi?.basePath);
const approval = buildApprovalSnapshot(record, controlUiBasePath);
if (!approval || approval.status === "pending") {
respondApprovalNotFound(respond);
return;
}
respond(true, {
applied: false,
approval
}, void 0);
return;
}
const resolver = custody ? {
kind: "channel",
id: custody.resolverId
} : resolveApprovalResolver(client);
const localResolvedBy = resolveLegacyApprovalLabel(client);
const requestedDecision = resolveParams?.decision ?? null;
const decisionAllowed = requestedDecision === "deny" || requestedDecision !== null && record.presentation.allowedDecisions.includes(requestedDecision);
const kindMatches = resolveParams?.kind === record.presentation.kind;
const forceMalformedDeny = !validParams || !kindMatches || !decisionAllowed;
const assertCurrent = () => {
approvalGuard.assertCurrent();
const currentCfg = context.getRuntimeConfig();
const currentCustody = resolveParams?.reviewer ? prepareApprovalChannelCustody({
cfg: currentCfg,
approvalKind: record.kind,
reviewer: resolveParams.reviewer
}) : null;
if (client?.invalidated || !canAccessOperatorApproval({
client,
allowApprovalRuntime: true,
binding: { reviewerDeviceIds: record.reviewerDeviceIds }
}) || approvalGuard.family === "native-compatibility" && !canAccessApprovalSession({
cfg: currentCfg,
client,
sessionKey: record.source.sessionKey,
agentId: record.source.agentId
}) || resolveParams?.reviewer && (!liveRecord || !currentCustody?.authorizes(liveRecord))) throw new Error("approval resolver authority is no longer active");
};
let resolution;
try {
const decisionParams = {
id: record.id,
decision: requestedDecision,
forceMalformedDeny,
resolver,
localResolvedBy,
guard: {
family: approvalGuard.family,
assertCurrent
}
};
resolution = record.kind === "exec" ? await applyApprovalDecision({
...decisionParams,
manager: params.execApprovalManager,
...requestedDecision === "allow-always" && typeof resolveParams?.grantExpiresInDays === "number" ? { grantExpiresAtMs: Date.now() + Math.floor(resolveParams.grantExpiresInDays) * 864e5 } : {}
}) : record.kind === "plugin" ? await applyApprovalDecision({
...decisionParams,
manager: params.pluginApprovalManager
}) : await applyApprovalDecision({
...decisionParams,
manager: params.systemAgentApprovalManager
});
} catch (error) {
if (!readCurrent()) {
respondApprovalNotFound(respond);
return;
}
respondApprovalStorageUnavailable({
context,
respond,
operation: "resolve",
error
});
return;
}
if (!authority.isCurrent() || !resolution.ok) {
respondApprovalNotFound(respond);
return;
}
const terminalRecord = resolution.record;
if (terminalRecord.status === "pending") {
respondApprovalNotFound(respond);
return;
}
const approval = buildApprovalSnapshot(terminalRecord, normalizeControlUiBasePath(context.getRuntimeConfig()?.gateway?.controlUi?.basePath));
if (!approval) {
respondApprovalNotFound(respond);
return;
}
respond(true, {
applied: resolution.applied,
approval
}, void 0);
if (resolution.applied && resolution.liveRecord) publishAppliedApprovalResolution({
record: terminalRecord,
liveRecord: resolution.liveRecord,
context,
forwarder: params.forwarder,
iosPushDelivery: params.iosPushDelivery,
pluginIosPushDelivery: params.pluginIosPushDelivery
}).catch((error) => {
context.logGateway?.error?.(`${terminalRecord.kind} approvals: unified resolve publication failed: ${String(error)}`);
});
} catch (_) {
_usingCtx4.e = _;
} finally {
_usingCtx4.d();
}
}
};
}
//#endregion
export { createApprovalHandlers };