core: dedupe approval not-found handling (#60932)

Merged via squash.

Prepared head SHA: 108221fdfe
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
Gustavo Madeira Santana
2026-04-04 13:23:58 -04:00
committed by GitHub
parent ef7c84ae92
commit e627f53d24
10 changed files with 67 additions and 70 deletions

View File

@@ -3,8 +3,8 @@ import {
resolveChannelApprovalCapability,
} from "../../channels/plugins/index.js";
import { callGateway } from "../../gateway/call.js";
import { ErrorCodes } from "../../gateway/protocol/index.js";
import { logVerbose } from "../../globals.js";
import { isApprovalNotFoundError } from "../../infra/approval-errors.js";
import { resolveApprovalCommandAuthorization } from "../../infra/channel-approval-auth.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../../utils/message-channel.js";
import { resolveChannelAccountId } from "./channel-context.js";
@@ -78,39 +78,6 @@ function buildResolvedByLabel(params: Parameters<CommandHandler>[0]): string {
return `${channel}:${sender}`;
}
function readErrorCode(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value : null;
}
function readApprovalNotFoundDetailsReason(value: unknown): string | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
const reason = (value as { reason?: unknown }).reason;
return typeof reason === "string" && reason.trim() ? reason : null;
}
function isApprovalNotFoundError(err: unknown): boolean {
if (!(err instanceof Error)) {
return false;
}
const gatewayCode = readErrorCode((err as { gatewayCode?: unknown }).gatewayCode);
if (gatewayCode === ErrorCodes.APPROVAL_NOT_FOUND) {
return true;
}
const detailsReason = readApprovalNotFoundDetailsReason((err as { details?: unknown }).details);
if (
gatewayCode === ErrorCodes.INVALID_REQUEST &&
detailsReason === ErrorCodes.APPROVAL_NOT_FOUND
) {
return true;
}
// Legacy server/client combinations may only include the message text.
return /unknown or expired approval id/i.test(err.message);
}
function formatApprovalSubmitError(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}

View File

@@ -0,0 +1,29 @@
import { describe, expect, it } from "vitest";
import { isApprovalNotFoundError } from "./approval-errors.js";
describe("isApprovalNotFoundError", () => {
it("matches direct approval-not-found gateway codes", () => {
const err = new Error("approval not found") as Error & { gatewayCode?: string };
err.gatewayCode = "APPROVAL_NOT_FOUND";
expect(isApprovalNotFoundError(err)).toBe(true);
});
it("matches structured invalid-request approval-not-found details", () => {
const err = new Error("approval not found") as Error & {
gatewayCode?: string;
details?: { reason?: string };
};
err.gatewayCode = "INVALID_REQUEST";
err.details = { reason: "APPROVAL_NOT_FOUND" };
expect(isApprovalNotFoundError(err)).toBe(true);
});
it("matches legacy message-only not-found errors", () => {
expect(isApprovalNotFoundError(new Error("unknown or expired approval id"))).toBe(true);
});
it("ignores unrelated errors", () => {
expect(isApprovalNotFoundError(new Error("network timeout"))).toBe(false);
expect(isApprovalNotFoundError("unknown or expired approval id")).toBe(false);
});
});

View File

@@ -0,0 +1,29 @@
const INVALID_REQUEST = "INVALID_REQUEST";
const APPROVAL_NOT_FOUND = "APPROVAL_NOT_FOUND";
function readErrorCode(value: unknown): string | null {
return typeof value === "string" && value.trim() ? value : null;
}
function readApprovalNotFoundDetailsReason(value: unknown): string | null {
if (!value || typeof value !== "object" || Array.isArray(value)) {
return null;
}
const reason = (value as { reason?: unknown }).reason;
return typeof reason === "string" && reason.trim() ? reason : null;
}
export function isApprovalNotFoundError(err: unknown): boolean {
if (!(err instanceof Error)) {
return false;
}
const gatewayCode = readErrorCode((err as { gatewayCode?: unknown }).gatewayCode);
if (gatewayCode === APPROVAL_NOT_FOUND) {
return true;
}
const detailsReason = readApprovalNotFoundDetailsReason((err as { details?: unknown }).details);
if (gatewayCode === INVALID_REQUEST && detailsReason === APPROVAL_NOT_FOUND) {
return true;
}
return /unknown or expired approval id/i.test(err.message);
}

View File

@@ -7,3 +7,4 @@ export {
formatUncaughtError,
readErrorName,
} from "../infra/errors.js";
export { isApprovalNotFoundError } from "../infra/approval-errors.ts";

View File

@@ -841,6 +841,7 @@ describe("plugin-sdk subpath exports", () => {
expectSourceMentions("infra-runtime", ["createRuntimeOutboundDelegates"]);
expectSourceContains("infra-runtime", "../infra/outbound/send-deps.js");
expectSourceMentions("error-runtime", ["formatUncaughtError", "isApprovalNotFoundError"]);
expect(typeof channelLifecycleSdk.createDraftStreamLoop).toBe("function");
expect(typeof channelLifecycleSdk.createFinalizableDraftLifecycle).toBe("function");