Skip to content

Commit c623234

Browse files
committed
refactor: share exec approvals node invoke
1 parent b73e135 commit c623234

1 file changed

Lines changed: 53 additions & 64 deletions

File tree

src/gateway/server-methods/exec-approvals.ts

Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import {
2121
respondUnavailableOnThrow,
2222
safeParseJson,
2323
} from "./nodes.helpers.js";
24-
import type { GatewayRequestHandlers, RespondFn } from "./types.js";
25-
import { assertValidParams } from "./validation.js";
24+
import type { GatewayRequestContext, GatewayRequestHandlers, RespondFn } from "./types.js";
25+
import { assertValidParams, type Validator } from "./validation.js";
2626

2727
function requireApprovalsBaseHash(
2828
params: unknown,
@@ -90,13 +90,37 @@ function toExecApprovalsPayload(snapshot: ExecApprovalsSnapshot) {
9090
};
9191
}
9292

93-
function resolveNodeIdOrRespond(nodeId: string, respond: RespondFn): string | null {
94-
const id = nodeId.trim();
95-
if (!id) {
96-
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId required"));
97-
return null;
93+
async function respondWithExecApprovalsNodePayload<TParams extends { nodeId: string }>(params: {
94+
method: string;
95+
rawParams: unknown;
96+
validate: Validator<TParams>;
97+
context: GatewayRequestContext;
98+
respond: RespondFn;
99+
command: "system.execApprovals.get" | "system.execApprovals.set";
100+
commandParams: (parsedParams: TParams) => Record<string, unknown>;
101+
readPayload: (response: { payload?: unknown; payloadJSON?: string | null }) => unknown;
102+
}): Promise<void> {
103+
const rawParams = params.rawParams;
104+
if (!assertValidParams(rawParams, params.validate, params.method, params.respond)) {
105+
return;
98106
}
99-
return id;
107+
const parsedParams = rawParams;
108+
const nodeId = parsedParams.nodeId.trim();
109+
if (!nodeId) {
110+
params.respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "nodeId required"));
111+
return;
112+
}
113+
await respondUnavailableOnThrow(params.respond, async () => {
114+
const res = await params.context.nodeRegistry.invoke({
115+
nodeId,
116+
command: params.command,
117+
params: params.commandParams(parsedParams),
118+
});
119+
if (!respondUnavailableOnNodeInvokeError(params.respond, res)) {
120+
return;
121+
}
122+
params.respond(true, params.readPayload(res), undefined);
123+
});
100124
}
101125

102126
export const execApprovalsHandlers: GatewayRequestHandlers = {
@@ -133,69 +157,34 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
133157
respond(true, toExecApprovalsPayload(nextSnapshot), undefined);
134158
},
135159
"exec.approvals.node.get": async ({ params, respond, context }) => {
136-
if (
137-
!assertValidParams(
138-
params,
139-
validateExecApprovalsNodeGetParams,
140-
"exec.approvals.node.get",
141-
respond,
142-
)
143-
) {
144-
return;
145-
}
146-
const { nodeId } = params as { nodeId: string };
147-
const id = resolveNodeIdOrRespond(nodeId, respond);
148-
if (!id) {
149-
return;
150-
}
151-
await respondUnavailableOnThrow(respond, async () => {
152-
const res = await context.nodeRegistry.invoke({
153-
nodeId: id,
154-
command: "system.execApprovals.get",
155-
params: {},
156-
});
157-
if (!respondUnavailableOnNodeInvokeError(respond, res)) {
158-
return;
159-
}
160+
await respondWithExecApprovalsNodePayload({
161+
method: "exec.approvals.node.get",
162+
rawParams: params,
163+
validate: validateExecApprovalsNodeGetParams,
164+
context,
165+
respond,
166+
command: "system.execApprovals.get",
167+
commandParams: () => ({}),
160168
// Node invocations can return structured payloads or JSON strings
161169
// depending on the transport; normalize before echoing the RPC response.
162-
const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
163-
respond(true, payload, undefined);
170+
readPayload: (res) => (res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload),
164171
});
165172
},
166173
"exec.approvals.node.set": async ({ params, respond, context }) => {
167-
if (
168-
!assertValidParams(
169-
params,
170-
validateExecApprovalsNodeSetParams,
171-
"exec.approvals.node.set",
172-
respond,
173-
)
174-
) {
175-
return;
176-
}
177-
const { nodeId, file, baseHash } = params as {
178-
nodeId: string;
179-
file: ExecApprovalsFile;
180-
baseHash?: string;
181-
};
182-
const id = resolveNodeIdOrRespond(nodeId, respond);
183-
if (!id) {
184-
return;
185-
}
186-
await respondUnavailableOnThrow(respond, async () => {
187-
const res = await context.nodeRegistry.invoke({
188-
nodeId: id,
189-
command: "system.execApprovals.set",
190-
params: { file, baseHash },
191-
});
192-
if (!respondUnavailableOnNodeInvokeError(respond, res)) {
193-
return;
194-
}
174+
await respondWithExecApprovalsNodePayload({
175+
method: "exec.approvals.node.set",
176+
rawParams: params,
177+
validate: validateExecApprovalsNodeSetParams,
178+
context,
179+
respond,
180+
command: "system.execApprovals.set",
181+
commandParams: (parsedParams) => ({
182+
file: parsedParams.file,
183+
baseHash: parsedParams.baseHash,
184+
}),
195185
// node.set returns JSON on the command channel; keep the gateway response
196186
// shape aligned with local exec.approvals.set.
197-
const payload = safeParseJson(res.payloadJSON ?? null);
198-
respond(true, payload, undefined);
187+
readPayload: (res) => safeParseJson(res.payloadJSON ?? null),
199188
});
200189
},
201190
};

0 commit comments

Comments
 (0)