Gateway: ack skipped hook transforms with 204

This commit is contained in:
Jared Verdi
2026-01-02 19:59:52 -05:00
committed by Peter Steinberger
parent 7e9be3c28c
commit 12e27f9e5e
3 changed files with 64 additions and 1 deletions

View File

@@ -74,6 +74,61 @@ describe("hooks mapping", () => {
}
});
it("treats null transform as a handled skip", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "clawdis-hooks-skip-"));
const modPath = path.join(dir, "transform.mjs");
fs.writeFileSync(modPath, "export default () => null;");
const mappings = resolveHookMappings({
transformsDir: dir,
mappings: [
{
match: { path: "skip" },
action: "agent",
transform: { module: "transform.mjs" },
},
],
});
const result = await applyHookMappings(mappings, {
payload: {},
headers: {},
url: new URL("http://127.0.0.1:18789/hooks/skip"),
path: "skip",
});
expect(result?.ok).toBe(true);
if (result?.ok) {
expect(result.action).toBeNull();
expect("skipped" in result).toBe(true);
}
});
it("prefers explicit mappings over presets", async () => {
const mappings = resolveHookMappings({
presets: ["gmail"],
mappings: [
{
id: "override",
match: { path: "gmail" },
action: "agent",
messageTemplate: "Override subject: {{messages[0].subject}}",
},
],
});
const result = await applyHookMappings(mappings, {
payload: { messages: [{ subject: "Hello" }] },
headers: {},
url: baseUrl,
path: "gmail",
});
expect(result?.ok).toBe(true);
if (result?.ok) {
expect(result.action.kind).toBe("agent");
expect(result.action.message).toBe("Override subject: Hello");
}
});
it("rejects missing message", async () => {
const mappings = resolveHookMappings({
mappings: [{ match: { path: "noop" }, action: "agent" }],

View File

@@ -70,6 +70,7 @@ export type HookAction =
export type HookMappingResult =
| { ok: true; action: HookAction }
| { ok: true; action: null; skipped: true }
| { ok: false; error: string };
const hookPresetMappings: Record<string, HookMappingConfig[]> = {
@@ -145,7 +146,9 @@ export async function applyHookMappings(
if (mapping.transform) {
const transform = await loadTransform(mapping.transform);
override = await transform(ctx);
if (override === null) return null;
if (override === null) {
return { ok: true, action: null, skipped: true };
}
}
const merged = mergeAction(base.action, override, mapping.action);

View File

@@ -1706,6 +1706,11 @@ export async function startGatewayServer(
sendJson(res, 400, { ok: false, error: mapped.error });
return true;
}
if (mapped.action === null) {
res.statusCode = 204;
res.end();
return true;
}
if (mapped.action.kind === "wake") {
dispatchWakeHook({
text: mapped.action.text,