From 73a97ee255391f1dcaca70f4db4468abbf413975 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Mon, 16 Feb 2026 01:25:06 +0000 Subject: [PATCH] refactor(gateway): share node invoke error handling --- src/gateway/server-methods/browser.ts | 11 ++------- src/gateway/server-methods/exec-approvals.ts | 24 ++++++------------- src/gateway/server-methods/nodes.helpers.ts | 25 ++++++++++++++++++++ src/gateway/server-methods/nodes.ts | 10 ++------ 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/gateway/server-methods/browser.ts b/src/gateway/server-methods/browser.ts index 80e13e7ec..a26243277 100644 --- a/src/gateway/server-methods/browser.ts +++ b/src/gateway/server-methods/browser.ts @@ -10,7 +10,7 @@ import { createBrowserRouteDispatcher } from "../../browser/routes/dispatcher.js import { loadConfig } from "../../config/config.js"; import { isNodeCommandAllowed, resolveNodeCommandAllowlist } from "../node-command-policy.js"; import { ErrorCodes, errorShape } from "../protocol/index.js"; -import { safeParseJson } from "./nodes.helpers.js"; +import { respondUnavailableOnNodeInvokeError, safeParseJson } from "./nodes.helpers.js"; type BrowserRequestParams = { method?: string; @@ -194,14 +194,7 @@ export const browserHandlers: GatewayRequestHandlers = { timeoutMs, idempotencyKey: crypto.randomUUID(), }); - if (!res.ok) { - respond( - false, - undefined, - errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { - details: { nodeError: res.error ?? null }, - }), - ); + if (!respondUnavailableOnNodeInvokeError(respond, res)) { return; } const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload; diff --git a/src/gateway/server-methods/exec-approvals.ts b/src/gateway/server-methods/exec-approvals.ts index 79ba63260..a4c510395 100644 --- a/src/gateway/server-methods/exec-approvals.ts +++ b/src/gateway/server-methods/exec-approvals.ts @@ -17,7 +17,11 @@ import { validateExecApprovalsSetParams, } from "../protocol/index.js"; import { resolveBaseHashParam } from "./base-hash.js"; -import { respondUnavailableOnThrow, safeParseJson } from "./nodes.helpers.js"; +import { + respondUnavailableOnNodeInvokeError, + respondUnavailableOnThrow, + safeParseJson, +} from "./nodes.helpers.js"; import { assertValidParams } from "./validation.js"; function requireApprovalsBaseHash( @@ -147,14 +151,7 @@ export const execApprovalsHandlers: GatewayRequestHandlers = { command: "system.execApprovals.get", params: {}, }); - if (!res.ok) { - respond( - false, - undefined, - errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { - details: { nodeError: res.error ?? null }, - }), - ); + if (!respondUnavailableOnNodeInvokeError(respond, res)) { return; } const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload; @@ -188,14 +185,7 @@ export const execApprovalsHandlers: GatewayRequestHandlers = { command: "system.execApprovals.set", params: { file, baseHash }, }); - if (!res.ok) { - respond( - false, - undefined, - errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { - details: { nodeError: res.error ?? null }, - }), - ); + if (!respondUnavailableOnNodeInvokeError(respond, res)) { return; } const payload = safeParseJson(res.payloadJSON ?? null); diff --git a/src/gateway/server-methods/nodes.helpers.ts b/src/gateway/server-methods/nodes.helpers.ts index 5f77112e1..33192193d 100644 --- a/src/gateway/server-methods/nodes.helpers.ts +++ b/src/gateway/server-methods/nodes.helpers.ts @@ -51,3 +51,28 @@ export function safeParseJson(value: string | null | undefined): unknown { return { payloadJSON: value }; } } + +export function respondUnavailableOnNodeInvokeError( + respond: RespondFn, + res: T, +): res is T & { ok: true } { + if (res.ok) { + return true; + } + const message = + res.error && typeof res.error === "object" && "message" in res.error + ? (res.error as { message?: unknown }).message + : null; + respond( + false, + undefined, + errorShape( + ErrorCodes.UNAVAILABLE, + typeof message === "string" ? message : "node invoke failed", + { + details: { nodeError: res.error ?? null }, + }, + ), + ); + return false; +} diff --git a/src/gateway/server-methods/nodes.ts b/src/gateway/server-methods/nodes.ts index 6edb38887..c300ea2f7 100644 --- a/src/gateway/server-methods/nodes.ts +++ b/src/gateway/server-methods/nodes.ts @@ -28,6 +28,7 @@ import { import { handleNodeInvokeResult } from "./nodes.handlers.invoke-result.js"; import { respondInvalidParams, + respondUnavailableOnNodeInvokeError, respondUnavailableOnThrow, safeParseJson, uniqueSortedStrings, @@ -433,14 +434,7 @@ export const nodeHandlers: GatewayRequestHandlers = { timeoutMs: p.timeoutMs, idempotencyKey: p.idempotencyKey, }); - if (!res.ok) { - respond( - false, - undefined, - errorShape(ErrorCodes.UNAVAILABLE, res.error?.message ?? "node invoke failed", { - details: { nodeError: res.error ?? null }, - }), - ); + if (!respondUnavailableOnNodeInvokeError(respond, res)) { return; } const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;