mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
1171 lines
40 KiB
TypeScript
1171 lines
40 KiB
TypeScript
// Gateway exec approval manager.
|
|
// Tracks pending operator decisions and short-lived resolved approval records.
|
|
import { randomUUID } from "node:crypto";
|
|
import { expectDefined } from "@openclaw/normalization-core";
|
|
import { resolveExpiresAtMsFromDurationMs } from "@openclaw/normalization-core/number-coercion";
|
|
import { normalizeLowercaseStringOrEmpty } from "@openclaw/normalization-core/string-coerce";
|
|
import { buildApprovalPresentation } from "../infra/approval-presentation.js";
|
|
import { buildApprovalResolutionRef } from "../infra/approval-resolution-ref.js";
|
|
import type {
|
|
ExecApprovalDecision,
|
|
ExecApprovalRequestPayload as InfraExecApprovalRequestPayload,
|
|
} from "../infra/exec-approvals.js";
|
|
import { resolveTimerTimeoutMs } from "../shared/number-coercion.js";
|
|
import type { OpenClawStateDatabaseOptions } from "../state/openclaw-state-db.js";
|
|
import {
|
|
consumeOperatorApprovalAllowOnce,
|
|
forceDenyOperatorApproval,
|
|
insertOperatorApproval,
|
|
resolveOperatorApproval,
|
|
type ForceDenyOperatorApprovalResult,
|
|
type OperatorApprovalKind,
|
|
type OperatorApprovalRecord,
|
|
type OperatorApprovalResolver,
|
|
type OperatorApprovalSource,
|
|
type OperatorApprovalStatus,
|
|
type OperatorApprovalTerminalReason,
|
|
type ResolveOperatorApprovalResult,
|
|
} from "./operator-approval-store.js";
|
|
|
|
// Grace period to keep resolved entries for late awaitDecision calls.
|
|
// Exported because system.run timeout replay bounds its ask-fallback window
|
|
// to the same anchor; drifting values would widen or starve that window.
|
|
export const EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS = 15_000;
|
|
|
|
function unrefTimer(timer: ReturnType<typeof setTimeout>): void {
|
|
const unref = (timer as { unref?: () => void }).unref;
|
|
if (typeof unref === "function") {
|
|
unref.call(timer);
|
|
}
|
|
}
|
|
|
|
function scheduleResolvedEntryCleanup(cleanup: () => void): ReturnType<typeof setTimeout> {
|
|
// Resolved approvals stay visible briefly so node.invoke sanitizers can
|
|
// consume a just-approved id after the UI decision races the command retry.
|
|
const timer = setTimeout(cleanup, EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS);
|
|
unrefTimer(timer);
|
|
return timer;
|
|
}
|
|
|
|
function resolveApprovalTimeoutMs(timeoutMs: number): number {
|
|
return resolveTimerTimeoutMs(timeoutMs, 1);
|
|
}
|
|
|
|
// Approval IDs cross terminal, UI, push, and channel surfaces unchanged. Keep
|
|
// unsafe display bytes and unbounded identifiers out at the creation boundary.
|
|
const EXPLICIT_APPROVAL_ID_INVALID_CHAR_PATTERN = /[^A-Za-z0-9._:-]/;
|
|
|
|
/** Typed creation failure for an explicit approval id outside the shared safe format. */
|
|
export class InvalidApprovalIdError extends Error {
|
|
readonly code = "EXEC_APPROVAL_ID_INVALID";
|
|
readonly reason = "INVALID_APPROVAL_ID";
|
|
|
|
constructor() {
|
|
super(
|
|
"approval id must be 1-128 characters using only letters, numbers, '.', '_', ':', or '-', and cannot be '.' or '..'",
|
|
);
|
|
this.name = "InvalidApprovalIdError";
|
|
}
|
|
}
|
|
|
|
type ExecApprovalRequestPayload = InfraExecApprovalRequestPayload;
|
|
|
|
// Distinguishes operator decisions from trusted auto-review resolutions.
|
|
// system.run replay validation is stricter for auto-review approvals, so this
|
|
// runtime fact must survive on the process-local record (bindings never persist).
|
|
type ExecApprovalResolutionSource = "operator" | "auto-review";
|
|
|
|
export type ExecApprovalRecord<TPayload = ExecApprovalRequestPayload> = {
|
|
id: string;
|
|
request: TPayload;
|
|
createdAtMs: number;
|
|
expiresAtMs: number;
|
|
// Caller metadata (best-effort). Used to prevent other clients from replaying an approval id.
|
|
requestedByConnId?: string | null;
|
|
requestedByDeviceId?: string | null;
|
|
requestedByClientId?: string | null;
|
|
requestedByDeviceTokenAuth?: boolean;
|
|
approvalReviewerDeviceIds?: string[];
|
|
resolvedAtMs?: number;
|
|
decision?: ExecApprovalDecision;
|
|
consumedDecision?: ExecApprovalDecision;
|
|
resolutionSource?: ExecApprovalResolutionSource;
|
|
askFallbackConsumed?: boolean;
|
|
resolvedBy?: string | null;
|
|
status?: OperatorApprovalStatus;
|
|
terminalReason?: OperatorApprovalTerminalReason | null;
|
|
runtimeEpoch?: string;
|
|
resolverKind?: OperatorApprovalResolver["kind"] | null;
|
|
consumedAtMs?: number | null;
|
|
consumedBy?: string | null;
|
|
};
|
|
|
|
type OperatorApprovalPersistenceRuntime = {
|
|
runtimeEpoch: string;
|
|
databaseOptions?: OpenClawStateDatabaseOptions;
|
|
};
|
|
|
|
type ExecApprovalManagerOptions<TPayload> = {
|
|
approvalKind?: OperatorApprovalKind;
|
|
persistence?: OperatorApprovalPersistenceRuntime;
|
|
resolveAllowedDecisions?: (request: TPayload) => readonly ExecApprovalDecision[];
|
|
/** Session-lineage audience policy is gateway-owned and injected as a
|
|
* non-throwing resolver; importing it here would close an agents->gateway
|
|
* barrel cycle. Absent resolver (tests) seeds only the raising session. */
|
|
resolveAudienceSessionKeys?: (
|
|
sourceSessionKey: string,
|
|
sourceAgentId?: string | null,
|
|
) => string[];
|
|
onError?: (
|
|
error: Error,
|
|
context: { approvalId: string; approvalKind: OperatorApprovalKind; operation: "expire" },
|
|
) => void;
|
|
onLifecycle?: (event: OperatorApprovalLifecycleEvent) => void;
|
|
};
|
|
|
|
export type OperatorApprovalLifecycleEvent = {
|
|
phase: "pending" | "terminal";
|
|
record: OperatorApprovalRecord;
|
|
};
|
|
|
|
type WithLiveRecord<TResult, TPayload> = TResult extends { record: OperatorApprovalRecord }
|
|
? TResult & { liveRecord?: ExecApprovalRecord<TPayload> }
|
|
: TResult;
|
|
|
|
type ExecApprovalResolveResult<TPayload = ExecApprovalRequestPayload> = WithLiveRecord<
|
|
ResolveOperatorApprovalResult,
|
|
TPayload
|
|
>;
|
|
|
|
type ExecApprovalForceDenyResult<TPayload = ExecApprovalRequestPayload> = WithLiveRecord<
|
|
ForceDenyOperatorApprovalResult,
|
|
TPayload
|
|
>;
|
|
|
|
type ExecApprovalDurableLookup =
|
|
| { outcome: "found"; record: OperatorApprovalRecord }
|
|
| { outcome: "missing" | "corrupt"; id: string };
|
|
|
|
type PendingEntry<TPayload = ExecApprovalRequestPayload> = {
|
|
record: ExecApprovalRecord<TPayload>;
|
|
resolve: (decision: ExecApprovalDecision | null) => void;
|
|
reject: (err: Error) => void;
|
|
timer: ReturnType<typeof setTimeout>;
|
|
cleanupTimer: ReturnType<typeof setTimeout> | null;
|
|
handoffRetainCount: number;
|
|
handoffReleasedAtMs: number | null;
|
|
retainForManagerLifetime: boolean;
|
|
promise: Promise<ExecApprovalDecision | null>;
|
|
};
|
|
|
|
export type ExecApprovalIdLookupResult =
|
|
| { kind: "exact" | "prefix"; id: string }
|
|
| { kind: "ambiguous"; ids: string[] }
|
|
| { kind: "none" };
|
|
|
|
function readRequestString(request: unknown, key: string): string | null {
|
|
if (typeof request !== "object" || request === null) {
|
|
return null;
|
|
}
|
|
const value = (request as Record<string, unknown>)[key];
|
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
}
|
|
|
|
function resolveApprovalSource(request: unknown): OperatorApprovalSource {
|
|
return {
|
|
agentId: readRequestString(request, "agentId"),
|
|
sessionKey: readRequestString(request, "sessionKey"),
|
|
sessionId: readRequestString(request, "sessionId"),
|
|
runId: readRequestString(request, "runId"),
|
|
toolCallId: readRequestString(request, "toolCallId"),
|
|
toolName: readRequestString(request, "toolName"),
|
|
};
|
|
}
|
|
|
|
function normalizeAllowedDecisions(
|
|
decisions: readonly ExecApprovalDecision[] | undefined,
|
|
): ExecApprovalDecision[] {
|
|
const normalized: ExecApprovalDecision[] = [];
|
|
for (const decision of decisions ?? ["allow-once", "allow-always", "deny"]) {
|
|
if (
|
|
(decision === "allow-once" || decision === "allow-always" || decision === "deny") &&
|
|
!normalized.includes(decision)
|
|
) {
|
|
normalized.push(decision);
|
|
}
|
|
}
|
|
// Denial is always a valid fail-closed verdict, including for malformed input.
|
|
if (!normalized.includes("deny")) {
|
|
normalized.push("deny");
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
function attachLiveRecord<TPayload, TResult extends { outcome: string }>(
|
|
result: TResult,
|
|
liveRecord: ExecApprovalRecord<TPayload> | undefined,
|
|
): WithLiveRecord<TResult, TPayload> {
|
|
if (!("record" in result) || !liveRecord) {
|
|
return result as WithLiveRecord<TResult, TPayload>;
|
|
}
|
|
return {
|
|
...result,
|
|
liveRecord,
|
|
} as WithLiveRecord<TResult, TPayload>;
|
|
}
|
|
|
|
// Without `persistence` the manager runs process-local-only. Gateway
|
|
// production always injects persistence (server-aux-handlers); local mode
|
|
// exists for unit tests and is slated for removal once the embedded broker
|
|
// migrates onto the durable store — do not grow it new behavior.
|
|
export class ExecApprovalManager<TPayload = ExecApprovalRequestPayload> {
|
|
private pending = new Map<string, PendingEntry<TPayload>>();
|
|
|
|
constructor(private readonly options: ExecApprovalManagerOptions<TPayload> = {}) {}
|
|
|
|
get approvalKind(): OperatorApprovalKind {
|
|
return this.options.approvalKind ?? "exec";
|
|
}
|
|
|
|
get runtimeEpoch(): string | null {
|
|
return this.options.persistence?.runtimeEpoch ?? null;
|
|
}
|
|
|
|
create(request: TPayload, timeoutMs: number, id?: string | null): ExecApprovalRecord<TPayload> {
|
|
const now = Date.now();
|
|
const resolvedTimeoutMs = resolveApprovalTimeoutMs(timeoutMs);
|
|
const expiresAtMs = resolveExpiresAtMsFromDurationMs(resolvedTimeoutMs, { nowMs: now });
|
|
if (expiresAtMs === undefined) {
|
|
throw new Error("approval expiry is unavailable");
|
|
}
|
|
// Empty remains the caller-facing sentinel for manager-generated ids.
|
|
const hasExplicitId = id !== null && id !== undefined && id.length > 0;
|
|
if (
|
|
hasExplicitId &&
|
|
(id.length > 128 ||
|
|
id === "." ||
|
|
id === ".." ||
|
|
EXPLICIT_APPROVAL_ID_INVALID_CHAR_PATTERN.test(id))
|
|
) {
|
|
throw new InvalidApprovalIdError();
|
|
}
|
|
const resolvedId = hasExplicitId ? id : randomUUID();
|
|
const record: ExecApprovalRecord<TPayload> = {
|
|
id: resolvedId,
|
|
request,
|
|
createdAtMs: now,
|
|
expiresAtMs,
|
|
};
|
|
return record;
|
|
}
|
|
|
|
/**
|
|
* Register an approval record and return a promise that resolves when the decision is made.
|
|
* This separates registration (synchronous) from waiting (async), allowing callers to
|
|
* confirm registration before the decision is made.
|
|
*/
|
|
register(
|
|
record: ExecApprovalRecord<TPayload>,
|
|
_timeoutMs: number,
|
|
): Promise<ExecApprovalDecision | null> {
|
|
const persistence = this.options.persistence;
|
|
const allowedDecisions = persistence
|
|
? normalizeAllowedDecisions(this.options.resolveAllowedDecisions?.(record.request))
|
|
: null;
|
|
const presentation = persistence
|
|
? buildApprovalPresentation({
|
|
kind: this.approvalKind,
|
|
request: record.request,
|
|
allowedDecisions: allowedDecisions ?? [],
|
|
})
|
|
: null;
|
|
if (persistence && !presentation) {
|
|
// No durable row or live waiter may exist without a safe prompt that every
|
|
// reviewer surface can render; otherwise an approval could be unreviewable.
|
|
throw new Error("approval cannot be persisted without a valid reviewer presentation");
|
|
}
|
|
|
|
const existing = this.pending.get(record.id);
|
|
if (existing) {
|
|
// Idempotent: return existing promise if still pending
|
|
if (existing.record.resolvedAtMs === undefined) {
|
|
return existing.promise;
|
|
}
|
|
// Already resolved - don't allow re-registration
|
|
throw new Error(`approval id '${record.id}' already resolved`);
|
|
}
|
|
|
|
let insertedRecord: OperatorApprovalRecord | null = null;
|
|
if (persistence) {
|
|
const source = resolveApprovalSource(record.request);
|
|
let audienceSessionKeys: string[] = [];
|
|
if (source.sessionKey) {
|
|
// The injected resolver owns lineage lookup plus its own agent-scoped
|
|
// fallback and never throws. Without one (tests), seed the raw source.
|
|
audienceSessionKeys = this.options.resolveAudienceSessionKeys?.(
|
|
source.sessionKey,
|
|
source.agentId,
|
|
) ?? [source.sessionKey];
|
|
}
|
|
const inserted = insertOperatorApproval({
|
|
approval: {
|
|
id: record.id,
|
|
kind: this.approvalKind,
|
|
presentation: presentation!,
|
|
requester: {
|
|
deviceId: record.requestedByDeviceId,
|
|
clientId: record.requestedByClientId,
|
|
deviceTokenAuth: record.requestedByDeviceTokenAuth === true,
|
|
},
|
|
reviewerDeviceIds: record.approvalReviewerDeviceIds,
|
|
source,
|
|
audienceSessionKeys,
|
|
runtimeEpoch: persistence.runtimeEpoch,
|
|
createdAtMs: record.createdAtMs,
|
|
expiresAtMs: record.expiresAtMs,
|
|
},
|
|
databaseOptions: persistence.databaseOptions,
|
|
});
|
|
if (inserted.outcome === "conflict") {
|
|
throw new Error(`approval id '${record.id}' conflicts with persisted state`);
|
|
}
|
|
if (inserted.outcome === "inserted") {
|
|
insertedRecord = inserted.record;
|
|
}
|
|
}
|
|
|
|
let resolvePromise: (decision: ExecApprovalDecision | null) => void;
|
|
let rejectPromise: (err: Error) => void;
|
|
const promise = new Promise<ExecApprovalDecision | null>((resolve, reject) => {
|
|
resolvePromise = resolve;
|
|
rejectPromise = reject;
|
|
});
|
|
// Create entry first so we can capture it in the closure (not re-fetch from map)
|
|
const entry: PendingEntry<TPayload> = {
|
|
record,
|
|
resolve: resolvePromise!,
|
|
reject: rejectPromise!,
|
|
timer: null as unknown as ReturnType<typeof setTimeout>,
|
|
cleanupTimer: null,
|
|
handoffRetainCount: 0,
|
|
handoffReleasedAtMs: null,
|
|
retainForManagerLifetime: false,
|
|
promise,
|
|
};
|
|
this.pending.set(record.id, entry);
|
|
this.scheduleExpiryTimer(entry);
|
|
if (insertedRecord) {
|
|
this.emitLifecycle({ phase: "pending", record: insertedRecord });
|
|
}
|
|
return promise;
|
|
}
|
|
|
|
private emitLifecycle(event: OperatorApprovalLifecycleEvent): void {
|
|
try {
|
|
this.options.onLifecycle?.(event);
|
|
} catch {
|
|
// Stream fanout is observational. It must never change approval truth or
|
|
// prevent the durable first-answer transition from releasing its waiter.
|
|
}
|
|
}
|
|
|
|
private projectLocalRecord(record: ExecApprovalRecord<TPayload>): OperatorApprovalRecord | null {
|
|
const presentation = buildApprovalPresentation({
|
|
kind: this.approvalKind,
|
|
request: record.request,
|
|
allowedDecisions: normalizeAllowedDecisions(
|
|
this.options.resolveAllowedDecisions?.(record.request),
|
|
),
|
|
});
|
|
if (!presentation) {
|
|
return null;
|
|
}
|
|
const status = record.status ?? (record.resolvedAtMs === undefined ? "pending" : "denied");
|
|
const source = resolveApprovalSource(record.request);
|
|
return {
|
|
id: record.id,
|
|
resolutionRef: buildApprovalResolutionRef({
|
|
approvalId: record.id,
|
|
approvalKind: this.approvalKind,
|
|
}),
|
|
kind: this.approvalKind,
|
|
status,
|
|
presentation,
|
|
requester: {
|
|
deviceId: record.requestedByDeviceId ?? null,
|
|
clientId: record.requestedByClientId ?? null,
|
|
deviceTokenAuth: record.requestedByDeviceTokenAuth === true,
|
|
},
|
|
reviewerDeviceIds: record.approvalReviewerDeviceIds ?? [],
|
|
source,
|
|
audienceSessionKeys: source.sessionKey ? [source.sessionKey] : [],
|
|
runtimeEpoch: this.runtimeEpoch ?? "process-local",
|
|
createdAtMs: record.createdAtMs,
|
|
expiresAtMs: record.expiresAtMs,
|
|
updatedAtMs: record.resolvedAtMs ?? record.createdAtMs,
|
|
decision: status === "pending" ? null : (record.decision ?? "deny"),
|
|
terminalReason: status === "pending" ? null : (record.terminalReason ?? "user"),
|
|
resolvedAtMs: record.resolvedAtMs ?? null,
|
|
resolver:
|
|
record.resolvedAtMs === undefined
|
|
? null
|
|
: { kind: record.resolverKind ?? "runtime", id: record.resolvedBy ?? null },
|
|
consumedAtMs: record.consumedAtMs ?? null,
|
|
consumedBy: record.consumedBy ?? null,
|
|
};
|
|
}
|
|
|
|
/** Persist the first verdict, then release the process-local waiter. */
|
|
resolveDetailed(
|
|
recordId: string,
|
|
decision: ExecApprovalDecision,
|
|
resolver: OperatorApprovalResolver,
|
|
localResolvedBy: string | null = null,
|
|
localResolutionSource: ExecApprovalResolutionSource = "operator",
|
|
): ExecApprovalResolveResult<TPayload> {
|
|
const persistence = this.options.persistence;
|
|
const localEntry = this.pending.get(recordId);
|
|
if (localEntry?.record.terminalReason === "storage-corrupt") {
|
|
const repaired = this.persistStorageCorruptDeny(recordId);
|
|
if (repaired.outcome === "expired") {
|
|
return repaired;
|
|
}
|
|
if (repaired.outcome === "not-found" || repaired.outcome === "corrupt") {
|
|
return repaired;
|
|
}
|
|
if (repaired.outcome === "denied" && decision === "deny") {
|
|
return attachLiveRecord(
|
|
{ outcome: "resolved", record: repaired.record } as const,
|
|
repaired.liveRecord,
|
|
);
|
|
}
|
|
return {
|
|
outcome: "already-resolved",
|
|
retry: repaired.record.decision === decision ? "same" : "conflict",
|
|
record: repaired.record,
|
|
...(repaired.liveRecord ? { liveRecord: repaired.liveRecord } : {}),
|
|
};
|
|
}
|
|
if (!persistence) {
|
|
if (!localEntry) {
|
|
return { outcome: "not-found" };
|
|
}
|
|
const previousDecision = localEntry.record.decision ?? localEntry.record.consumedDecision;
|
|
if (localEntry.record.resolvedAtMs !== undefined) {
|
|
const record = this.projectLocalRecord(localEntry.record);
|
|
return record
|
|
? {
|
|
outcome: "already-resolved",
|
|
retry: previousDecision === decision ? "same" : "conflict",
|
|
record,
|
|
liveRecord: localEntry.record,
|
|
}
|
|
: { outcome: "corrupt" };
|
|
}
|
|
const allowedDecisions = normalizeAllowedDecisions(
|
|
this.options.resolveAllowedDecisions?.(localEntry.record.request),
|
|
);
|
|
if (!allowedDecisions.includes(decision)) {
|
|
const record = this.projectLocalRecord(localEntry.record);
|
|
return record
|
|
? { outcome: "decision-not-allowed", record, liveRecord: localEntry.record }
|
|
: { outcome: "corrupt" };
|
|
}
|
|
this.resolveLocal(recordId, decision, localResolvedBy);
|
|
const record = this.projectLocalRecord(localEntry.record);
|
|
return record
|
|
? { outcome: "resolved", record, liveRecord: localEntry.record }
|
|
: { outcome: "corrupt" };
|
|
}
|
|
if (decision !== "deny" && !localEntry) {
|
|
return { outcome: "not-found" };
|
|
}
|
|
|
|
let result: ResolveOperatorApprovalResult;
|
|
try {
|
|
result = resolveOperatorApproval({
|
|
id: recordId,
|
|
decision,
|
|
resolver,
|
|
expectedKind: this.approvalKind,
|
|
runtimeEpoch: persistence.runtimeEpoch,
|
|
databaseOptions: persistence.databaseOptions,
|
|
});
|
|
} catch (error) {
|
|
this.settleLocalStorageFailure(recordId);
|
|
throw error;
|
|
}
|
|
|
|
if (
|
|
result.outcome === "resolved" ||
|
|
result.outcome === "expired" ||
|
|
result.outcome === "already-resolved"
|
|
) {
|
|
// The caller's source only applies when its own CAS won; a lost race or
|
|
// expiry settles with the durable winner, which is an operator decision.
|
|
this.settleLocalFromStore(
|
|
result.record,
|
|
undefined,
|
|
localResolvedBy,
|
|
result.outcome === "resolved" ? localResolutionSource : "operator",
|
|
);
|
|
} else if (result.outcome === "not-found" || result.outcome === "corrupt") {
|
|
this.settleLocalStorageFailure(recordId);
|
|
}
|
|
return attachLiveRecord(result, localEntry?.record) as ExecApprovalResolveResult<TPayload>;
|
|
}
|
|
|
|
/** Persist a fail-closed terminal state, then release the local waiter. */
|
|
forceDenyDetailed(
|
|
recordId: string,
|
|
reason: OperatorApprovalTerminalReason,
|
|
resolver: OperatorApprovalResolver,
|
|
status: "denied" | "expired" | "cancelled" = "denied",
|
|
localDecision?: ExecApprovalDecision | null,
|
|
requireDue = false,
|
|
localResolvedBy: string | null = null,
|
|
): ExecApprovalForceDenyResult<TPayload> {
|
|
const persistence = this.options.persistence;
|
|
const localRecord = this.pending.get(recordId)?.record;
|
|
if (localRecord?.terminalReason === "storage-corrupt") {
|
|
return this.persistStorageCorruptDeny(recordId);
|
|
}
|
|
if (!persistence) {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return { outcome: "not-found" };
|
|
}
|
|
if (entry.record.resolvedAtMs !== undefined) {
|
|
const record = this.projectLocalRecord(entry.record);
|
|
return record
|
|
? { outcome: "already-terminal", record, liveRecord: entry.record }
|
|
: { outcome: "corrupt" };
|
|
}
|
|
this.settleLocalEntry({
|
|
recordId,
|
|
decision:
|
|
localDecision === undefined ? (status === "denied" ? "deny" : null) : localDecision,
|
|
resolvedAtMs: Date.now(),
|
|
resolvedBy: localResolvedBy,
|
|
resolverKind: resolver.kind,
|
|
status,
|
|
terminalReason: reason,
|
|
});
|
|
const record = this.projectLocalRecord(entry.record);
|
|
return record
|
|
? { outcome: "denied", record, liveRecord: entry.record }
|
|
: { outcome: "corrupt" };
|
|
}
|
|
|
|
let result: ForceDenyOperatorApprovalResult;
|
|
try {
|
|
result = forceDenyOperatorApproval({
|
|
id: recordId,
|
|
status,
|
|
requireDue,
|
|
reason,
|
|
resolver,
|
|
expectedKind: this.approvalKind,
|
|
runtimeEpoch: persistence.runtimeEpoch,
|
|
databaseOptions: persistence.databaseOptions,
|
|
});
|
|
} catch (error) {
|
|
this.settleLocalStorageFailure(recordId);
|
|
throw error;
|
|
}
|
|
if (result.outcome === "denied") {
|
|
this.settleLocalFromStore(result.record, localDecision, localResolvedBy);
|
|
} else if (result.outcome === "expired" || result.outcome === "already-terminal") {
|
|
this.settleLocalFromStore(result.record, undefined, localResolvedBy);
|
|
} else if (result.outcome === "not-found" || result.outcome === "corrupt") {
|
|
this.settleLocalStorageFailure(recordId);
|
|
}
|
|
return attachLiveRecord(result, localRecord) as ExecApprovalForceDenyResult<TPayload>;
|
|
}
|
|
|
|
private settleLocalFromStore(
|
|
record: OperatorApprovalRecord,
|
|
localDecision?: ExecApprovalDecision | null,
|
|
localResolvedBy: string | null = null,
|
|
localResolutionSource: ExecApprovalResolutionSource = "operator",
|
|
): boolean {
|
|
const persistence = this.options.persistence;
|
|
if (
|
|
record.kind !== this.approvalKind ||
|
|
(persistence && record.runtimeEpoch !== persistence.runtimeEpoch) ||
|
|
record.status === "pending" ||
|
|
record.resolvedAtMs === null
|
|
) {
|
|
return false;
|
|
}
|
|
const decision =
|
|
localDecision === undefined
|
|
? record.status === "allowed" || record.status === "denied"
|
|
? record.decision
|
|
: null
|
|
: localDecision;
|
|
const settled = this.settleLocalEntry({
|
|
recordId: record.id,
|
|
decision,
|
|
resolvedAtMs: record.resolvedAtMs,
|
|
resolvedBy: localResolvedBy,
|
|
resolverKind: record.resolver?.kind ?? null,
|
|
status: record.status,
|
|
terminalReason: record.terminalReason,
|
|
consumedAtMs: record.consumedAtMs,
|
|
consumedBy: record.consumedBy,
|
|
resolutionSource: localResolutionSource,
|
|
});
|
|
if (settled) {
|
|
this.emitLifecycle({ phase: "terminal", record });
|
|
}
|
|
return settled;
|
|
}
|
|
|
|
/** Settle one durable terminal transition and report whether this manager published it. */
|
|
reconcileDurableTerminal(record: OperatorApprovalRecord): boolean {
|
|
return this.settleLocalFromStore(record);
|
|
}
|
|
|
|
/** Reconciles durable truth with an existing waiter without rehydrating its request. */
|
|
reconcileDurableLookup(
|
|
lookup: ExecApprovalDurableLookup,
|
|
localResolvedBy: string | null = null,
|
|
): OperatorApprovalRecord | null {
|
|
const recordId = lookup.outcome === "found" ? lookup.record.id : lookup.id;
|
|
const entry = this.pending.get(recordId);
|
|
if (lookup.outcome !== "found") {
|
|
if (entry) {
|
|
this.settleLocalStorageFailure(recordId);
|
|
}
|
|
return null;
|
|
}
|
|
const persistence = this.options.persistence;
|
|
if (
|
|
!entry ||
|
|
!persistence ||
|
|
lookup.record.kind !== this.approvalKind ||
|
|
lookup.record.runtimeEpoch !== persistence.runtimeEpoch
|
|
) {
|
|
return lookup.record;
|
|
}
|
|
if (lookup.record.status === "pending" && entry.record.terminalReason === "storage-corrupt") {
|
|
const repaired = this.persistStorageCorruptDeny(recordId);
|
|
return "record" in repaired ? repaired.record : null;
|
|
}
|
|
if (lookup.record.status !== "pending") {
|
|
this.settleLocalFromStore(lookup.record, undefined, localResolvedBy);
|
|
}
|
|
return lookup.record;
|
|
}
|
|
|
|
private settleLocalStorageFailure(recordId: string): void {
|
|
this.settleLocalEntry({
|
|
recordId,
|
|
decision: "deny",
|
|
resolvedAtMs: Date.now(),
|
|
resolvedBy: "storage-error",
|
|
resolverKind: "system",
|
|
status: "denied",
|
|
terminalReason: "storage-corrupt",
|
|
retainForManagerLifetime: true,
|
|
});
|
|
}
|
|
|
|
private persistStorageCorruptDeny(recordId: string): ExecApprovalForceDenyResult<TPayload> {
|
|
const localEntry = this.pending.get(recordId);
|
|
const persistence = this.options.persistence;
|
|
if (!localEntry) {
|
|
return { outcome: "not-found" };
|
|
}
|
|
if (!persistence) {
|
|
return { outcome: "not-found" };
|
|
}
|
|
const result = forceDenyOperatorApproval({
|
|
id: recordId,
|
|
status: "denied",
|
|
reason: "storage-corrupt",
|
|
resolver: { kind: "system", id: "storage-error" },
|
|
expectedKind: this.approvalKind,
|
|
runtimeEpoch: persistence.runtimeEpoch,
|
|
databaseOptions: persistence.databaseOptions,
|
|
});
|
|
if (result.outcome === "denied" || result.outcome === "expired") {
|
|
this.emitLifecycle({ phase: "terminal", record: result.record });
|
|
}
|
|
return attachLiveRecord(result, localEntry.record) as ExecApprovalForceDenyResult<TPayload>;
|
|
}
|
|
|
|
private settleLocalEntry(params: {
|
|
recordId: string;
|
|
decision: ExecApprovalDecision | null;
|
|
resolvedAtMs: number;
|
|
resolvedBy: string | null;
|
|
resolverKind: OperatorApprovalResolver["kind"] | null;
|
|
status: OperatorApprovalStatus;
|
|
terminalReason: OperatorApprovalTerminalReason | null;
|
|
consumedAtMs?: number | null;
|
|
consumedBy?: string | null;
|
|
resolutionSource?: ExecApprovalResolutionSource;
|
|
retainForManagerLifetime?: boolean;
|
|
}): boolean {
|
|
const pending = this.pending.get(params.recordId);
|
|
if (!pending || pending.record.resolvedAtMs !== undefined) {
|
|
return false;
|
|
}
|
|
clearTimeout(pending.timer);
|
|
pending.record.resolvedAtMs = params.resolvedAtMs;
|
|
if (params.decision === null) {
|
|
delete pending.record.decision;
|
|
} else {
|
|
pending.record.decision = params.decision;
|
|
// Only explicit decisions carry a source; timeouts/cancellations stay
|
|
// source-less so system.run ask-fallback replay can identify them.
|
|
pending.record.resolutionSource = params.resolutionSource ?? "operator";
|
|
}
|
|
pending.record.resolvedBy = params.resolvedBy;
|
|
pending.record.resolverKind = params.resolverKind;
|
|
pending.record.status = params.status;
|
|
pending.record.terminalReason = params.terminalReason;
|
|
pending.record.runtimeEpoch = this.runtimeEpoch ?? undefined;
|
|
pending.record.consumedAtMs = params.consumedAtMs ?? null;
|
|
pending.record.consumedBy = params.consumedBy ?? null;
|
|
pending.retainForManagerLifetime ||= params.retainForManagerLifetime === true;
|
|
// Keep resolved entries briefly so late waitDecision and system.run replay
|
|
// validation see the same durable verdict that released this waiter.
|
|
pending.resolve(params.decision);
|
|
if (!pending.retainForManagerLifetime && pending.handoffRetainCount === 0) {
|
|
this.scheduleResolvedCleanup(pending);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private scheduleResolvedCleanup(entry: PendingEntry<TPayload>): void {
|
|
if (
|
|
entry.cleanupTimer ||
|
|
entry.record.resolvedAtMs === undefined ||
|
|
entry.retainForManagerLifetime ||
|
|
entry.handoffRetainCount > 0
|
|
) {
|
|
return;
|
|
}
|
|
const cleanupTimer = scheduleResolvedEntryCleanup(() => {
|
|
if (entry.cleanupTimer !== cleanupTimer) {
|
|
return;
|
|
}
|
|
entry.cleanupTimer = null;
|
|
if (
|
|
this.pending.get(entry.record.id) === entry &&
|
|
entry.handoffRetainCount === 0 &&
|
|
!entry.retainForManagerLifetime
|
|
) {
|
|
this.pending.delete(entry.record.id);
|
|
}
|
|
});
|
|
entry.cleanupTimer = cleanupTimer;
|
|
}
|
|
|
|
private resolvedGraceAnchorMs(entry: PendingEntry<TPayload>, nowMs: number): number | null {
|
|
if (entry.record.resolvedAtMs === undefined) {
|
|
return null;
|
|
}
|
|
if (entry.handoffRetainCount > 0) {
|
|
return nowMs;
|
|
}
|
|
return entry.handoffReleasedAtMs ?? entry.record.resolvedAtMs;
|
|
}
|
|
|
|
/** Retains an existing local binding across async delivery; final release starts a fresh grace. */
|
|
retainForHandoff(recordId: string): (() => void) | null {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
const nowMs = Date.now();
|
|
const graceAnchorMs = this.resolvedGraceAnchorMs(entry, nowMs);
|
|
if (
|
|
!entry.retainForManagerLifetime &&
|
|
graceAnchorMs !== null &&
|
|
entry.handoffRetainCount === 0 &&
|
|
nowMs - graceAnchorMs >= EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS
|
|
) {
|
|
this.pending.delete(recordId);
|
|
return null;
|
|
}
|
|
if (entry.cleanupTimer) {
|
|
clearTimeout(entry.cleanupTimer);
|
|
entry.cleanupTimer = null;
|
|
}
|
|
entry.handoffRetainCount += 1;
|
|
let released = false;
|
|
return () => {
|
|
if (released) {
|
|
return;
|
|
}
|
|
released = true;
|
|
if (this.pending.get(recordId) !== entry) {
|
|
return;
|
|
}
|
|
entry.handoffRetainCount = Math.max(0, entry.handoffRetainCount - 1);
|
|
if (entry.handoffRetainCount > 0 || entry.record.resolvedAtMs === undefined) {
|
|
return;
|
|
}
|
|
entry.handoffReleasedAtMs = Date.now();
|
|
this.scheduleResolvedCleanup(entry);
|
|
};
|
|
}
|
|
|
|
private reportError(error: unknown, context: { approvalId: string; operation: "expire" }): void {
|
|
const onError = this.options.onError;
|
|
if (!onError) {
|
|
return;
|
|
}
|
|
try {
|
|
onError(error instanceof Error ? error : new Error(String(error)), {
|
|
...context,
|
|
approvalKind: this.approvalKind,
|
|
});
|
|
} catch {
|
|
// Error reporting must not turn a fail-closed timeout into an uncaught timer exception.
|
|
}
|
|
}
|
|
|
|
private scheduleExpiryTimer(entry: PendingEntry<TPayload>): void {
|
|
const timerDelayMs = resolveApprovalTimeoutMs(entry.record.expiresAtMs - Date.now());
|
|
entry.timer = setTimeout(() => {
|
|
try {
|
|
this.expireDue(entry.record.id);
|
|
} catch (error) {
|
|
this.reportError(error, { approvalId: entry.record.id, operation: "expire" });
|
|
}
|
|
}, timerDelayMs);
|
|
}
|
|
|
|
private expireDue(recordId: string): boolean {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry || entry.record.resolvedAtMs !== undefined) {
|
|
return false;
|
|
}
|
|
if (!this.options.persistence) {
|
|
if (entry.record.expiresAtMs > Date.now()) {
|
|
this.scheduleExpiryTimer(entry);
|
|
return false;
|
|
}
|
|
return this.expireLocal(recordId, null);
|
|
}
|
|
const result = this.forceDenyDetailed(
|
|
recordId,
|
|
"timeout",
|
|
{ kind: "system", id: null },
|
|
"expired",
|
|
undefined,
|
|
true,
|
|
);
|
|
if (result.outcome === "not-due") {
|
|
this.scheduleExpiryTimer(entry);
|
|
return false;
|
|
}
|
|
return result.outcome === "denied" || result.outcome === "expired";
|
|
}
|
|
|
|
private resolveLocal(
|
|
recordId: string,
|
|
decision: ExecApprovalDecision,
|
|
resolvedBy: string | null,
|
|
resolutionSource: ExecApprovalResolutionSource = "operator",
|
|
): boolean {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry || entry.record.resolvedAtMs !== undefined) {
|
|
return false;
|
|
}
|
|
const allowedDecisions = normalizeAllowedDecisions(
|
|
this.options.resolveAllowedDecisions?.(entry.record.request),
|
|
);
|
|
if (!allowedDecisions.includes(decision)) {
|
|
return false;
|
|
}
|
|
return this.settleLocalEntry({
|
|
recordId,
|
|
decision,
|
|
resolvedAtMs: Date.now(),
|
|
resolvedBy,
|
|
resolverKind: "runtime",
|
|
status: decision === "deny" ? "denied" : "allowed",
|
|
terminalReason: "user",
|
|
resolutionSource,
|
|
});
|
|
}
|
|
|
|
private expireLocal(recordId: string, resolvedBy: string | null): boolean {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry || entry.record.resolvedAtMs !== undefined) {
|
|
return false;
|
|
}
|
|
const noRoute = resolvedBy === "no-approval-route";
|
|
return this.settleLocalEntry({
|
|
recordId,
|
|
decision: null,
|
|
resolvedAtMs: Date.now(),
|
|
resolvedBy,
|
|
resolverKind: "system",
|
|
status: noRoute ? "denied" : "expired",
|
|
terminalReason: noRoute ? "no-route" : "timeout",
|
|
});
|
|
}
|
|
|
|
resolve(recordId: string, decision: ExecApprovalDecision, resolvedBy?: string | null): boolean {
|
|
if (!this.options.persistence) {
|
|
return this.resolveLocal(recordId, decision, resolvedBy ?? null);
|
|
}
|
|
return (
|
|
this.resolveDetailed(
|
|
recordId,
|
|
decision,
|
|
{
|
|
kind: "runtime",
|
|
id: resolvedBy ?? null,
|
|
},
|
|
resolvedBy ?? null,
|
|
).outcome === "resolved"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Trusted auto-review resolution (identity-matched approval runtime).
|
|
* Always allow-once; system.run replay validation treats the resulting
|
|
* record more strictly than an operator decision (see #103515).
|
|
*/
|
|
resolveAutoReview(recordId: string, resolvedBy?: string | null): boolean {
|
|
if (!this.options.persistence) {
|
|
return this.resolveLocal(recordId, "allow-once", resolvedBy ?? null, "auto-review");
|
|
}
|
|
return (
|
|
this.resolveDetailed(
|
|
recordId,
|
|
"allow-once",
|
|
{
|
|
kind: "runtime",
|
|
id: resolvedBy ?? null,
|
|
},
|
|
resolvedBy ?? null,
|
|
"auto-review",
|
|
).outcome === "resolved"
|
|
);
|
|
}
|
|
|
|
/**
|
|
* One-shot ask-fallback re-admission for a timed-out approval. This is
|
|
* pre-gate policy on the process-local record only: the durable row stays
|
|
* `expired` and no execution authority is minted here. The strict exec
|
|
* timeout cutover is deferred (docs/refactor/operator-approvals.md); until
|
|
* then system.run replay uses this flag to keep re-admission single-use.
|
|
*/
|
|
consumeAskFallback(recordId: string): boolean {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return false;
|
|
}
|
|
const record = entry.record;
|
|
if (
|
|
record.resolvedAtMs === undefined ||
|
|
record.decision !== undefined ||
|
|
record.consumedDecision !== undefined ||
|
|
record.askFallbackConsumed === true
|
|
) {
|
|
return false;
|
|
}
|
|
record.askFallbackConsumed = true;
|
|
return true;
|
|
}
|
|
|
|
expire(recordId: string, resolvedBy?: string | null): boolean {
|
|
if (!this.options.persistence) {
|
|
return this.expireLocal(recordId, resolvedBy ?? null);
|
|
}
|
|
const noRoute = resolvedBy === "no-approval-route";
|
|
return (
|
|
this.forceDenyDetailed(
|
|
recordId,
|
|
noRoute ? "no-route" : "timeout",
|
|
{ kind: "system", id: resolvedBy ?? null },
|
|
noRoute ? "denied" : "expired",
|
|
noRoute ? null : undefined,
|
|
false,
|
|
resolvedBy ?? null,
|
|
).outcome === "denied"
|
|
);
|
|
}
|
|
|
|
getSnapshot(recordId: string): ExecApprovalRecord<TPayload> | null {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
const nowMs = Date.now();
|
|
const graceAnchorMs = this.resolvedGraceAnchorMs(entry, nowMs);
|
|
if (
|
|
entry.record.terminalReason !== "storage-corrupt" &&
|
|
graceAnchorMs !== null &&
|
|
nowMs - graceAnchorMs >= EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS
|
|
) {
|
|
this.pending.delete(recordId);
|
|
return null;
|
|
}
|
|
if (entry.record.resolvedAtMs === undefined && entry.record.expiresAtMs <= nowMs) {
|
|
this.expireDue(recordId);
|
|
}
|
|
return entry.record;
|
|
}
|
|
|
|
/** Returns an exact live request snapshot without reading durable state or mutating expiry. */
|
|
getLiveSnapshot(recordId: string): ExecApprovalRecord<TPayload> | null {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return null;
|
|
}
|
|
const nowMs = Date.now();
|
|
if (entry.record.resolvedAtMs === undefined) {
|
|
return entry.record.expiresAtMs > nowMs ? entry.record : null;
|
|
}
|
|
const graceAnchorMs = this.resolvedGraceAnchorMs(entry, nowMs);
|
|
if (graceAnchorMs === null || nowMs - graceAnchorMs >= EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS) {
|
|
return null;
|
|
}
|
|
return entry.record;
|
|
}
|
|
|
|
listPendingRecords(): ExecApprovalRecord<TPayload>[] {
|
|
const nowMs = Date.now();
|
|
for (const entry of this.pending.values()) {
|
|
if (entry.record.resolvedAtMs === undefined && entry.record.expiresAtMs <= nowMs) {
|
|
this.expireDue(entry.record.id);
|
|
}
|
|
}
|
|
return Array.from(this.pending.values())
|
|
.map((entry) => entry.record)
|
|
.filter((record) => record.resolvedAtMs === undefined);
|
|
}
|
|
|
|
consumeAllowOnce(recordId: string, consumerId = recordId): boolean {
|
|
const entry = this.pending.get(recordId);
|
|
if (!entry) {
|
|
return false;
|
|
}
|
|
const nowMs = Date.now();
|
|
const resolvedAtMs = entry.record.resolvedAtMs;
|
|
const graceAnchorMs = this.resolvedGraceAnchorMs(entry, nowMs);
|
|
// Durable records are audit/control-plane truth, not executable capability
|
|
// material. Redemption requires the live waiter entry and its requester binding.
|
|
if (
|
|
resolvedAtMs === undefined ||
|
|
graceAnchorMs === null ||
|
|
nowMs - graceAnchorMs >= EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS ||
|
|
entry.record.decision !== "allow-once" ||
|
|
entry.record.consumedDecision
|
|
) {
|
|
return false;
|
|
}
|
|
const persistence = this.options.persistence;
|
|
if (persistence) {
|
|
const result = consumeOperatorApprovalAllowOnce({
|
|
id: recordId,
|
|
consumerId,
|
|
expectedKind: this.approvalKind,
|
|
runtimeEpoch: persistence.runtimeEpoch,
|
|
redemptionWindowMs:
|
|
EXEC_APPROVAL_RESOLVED_ENTRY_GRACE_MS + Math.max(0, graceAnchorMs - resolvedAtMs),
|
|
databaseOptions: persistence.databaseOptions,
|
|
});
|
|
if (result.outcome !== "consumed") {
|
|
return false;
|
|
}
|
|
// Keep the winning decision for audit/retry reporting; consumedDecision
|
|
// is the process-local replay guard during the resolved grace window.
|
|
entry.record.consumedDecision = "allow-once";
|
|
entry.record.consumedAtMs = result.record.consumedAtMs;
|
|
entry.record.consumedBy = result.record.consumedBy;
|
|
return true;
|
|
}
|
|
entry.record.consumedDecision = "allow-once";
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Wait for decision on an already-registered approval.
|
|
* Returns the decision promise if the ID is pending, null otherwise.
|
|
*/
|
|
awaitDecision(recordId: string): Promise<ExecApprovalDecision | null> | null {
|
|
if (!this.getSnapshot(recordId)) {
|
|
return null;
|
|
}
|
|
const entry = this.pending.get(recordId);
|
|
return entry?.promise ?? null;
|
|
}
|
|
|
|
lookupApprovalId(
|
|
input: string,
|
|
opts: {
|
|
includeResolved?: boolean;
|
|
filter?: (record: ExecApprovalRecord<TPayload>) => boolean;
|
|
} = {},
|
|
): ExecApprovalIdLookupResult {
|
|
const rawExact = this.getSnapshot(input);
|
|
if (rawExact) {
|
|
return (opts.includeResolved || rawExact.resolvedAtMs === undefined) &&
|
|
(opts.filter?.(rawExact) ?? true)
|
|
? { kind: "exact", id: input }
|
|
: { kind: "none" };
|
|
}
|
|
|
|
const normalized = input.trim();
|
|
if (!normalized) {
|
|
return { kind: "none" };
|
|
}
|
|
|
|
const exact = this.getSnapshot(normalized);
|
|
if (exact) {
|
|
return (opts.includeResolved || exact.resolvedAtMs === undefined) &&
|
|
(opts.filter?.(exact) ?? true)
|
|
? { kind: "exact", id: normalized }
|
|
: { kind: "none" };
|
|
}
|
|
|
|
const lowerPrefix = normalizeLowercaseStringOrEmpty(normalized);
|
|
const matches: string[] = [];
|
|
const candidates = new Map<string, ExecApprovalRecord<TPayload>>();
|
|
for (const entry of this.pending.values()) {
|
|
candidates.set(entry.record.id, entry.record);
|
|
}
|
|
for (const record of this.listPendingRecords()) {
|
|
candidates.set(record.id, record);
|
|
}
|
|
for (const [id, record] of candidates) {
|
|
if (!opts.includeResolved && record.resolvedAtMs !== undefined) {
|
|
continue;
|
|
}
|
|
if (opts.filter && !opts.filter(record)) {
|
|
continue;
|
|
}
|
|
if (normalizeLowercaseStringOrEmpty(id).startsWith(lowerPrefix)) {
|
|
matches.push(id);
|
|
}
|
|
}
|
|
|
|
if (matches.length === 1) {
|
|
return {
|
|
kind: "prefix",
|
|
id: expectDefined(matches[0], "matches capture group 0"),
|
|
};
|
|
}
|
|
if (matches.length > 1) {
|
|
return { kind: "ambiguous", ids: matches };
|
|
}
|
|
return { kind: "none" };
|
|
}
|
|
|
|
lookupPendingId(input: string): ExecApprovalIdLookupResult {
|
|
return this.lookupApprovalId(input);
|
|
}
|
|
}
|
|
/* oxlint-disable max-lines -- TODO: split this grandfathered oversized file. */
|