refactor(extensions): dedupe connector helper usage

This commit is contained in:
Peter Steinberger
2026-02-16 14:51:55 +00:00
parent bc55ffb160
commit 544ffbcf7b
49 changed files with 854 additions and 1478 deletions

View File

@@ -5,6 +5,7 @@ import type {
} from "openclaw/plugin-sdk";
import {
createActionGate,
extractToolSend,
jsonResult,
readNumberParam,
readReactionParams,
@@ -64,16 +65,7 @@ export const googlechatMessageActions: ChannelMessageActionAdapter = {
return Array.from(actions);
},
extractToolSend: ({ args }) => {
const action = typeof args.action === "string" ? args.action.trim() : "";
if (action !== "sendMessage") {
return null;
}
const to = typeof args.to === "string" ? args.to : undefined;
if (!to) {
return null;
}
const accountId = typeof args.accountId === "string" ? args.accountId.trim() : undefined;
return { to, accountId };
return extractToolSend(args, "sendMessage");
},
handleAction: async ({ action, params, cfg, accountId }) => {
const account = resolveGoogleChatAccount({

View File

@@ -2,9 +2,11 @@ import type { IncomingMessage, ServerResponse } from "node:http";
import type { OpenClawConfig } from "openclaw/plugin-sdk";
import {
createReplyPrefixOptions,
normalizeWebhookPath,
readJsonBodyWithLimit,
registerWebhookTarget,
rejectNonPostWebhookRequest,
resolveWebhookPath,
resolveWebhookTargets,
requestBodyErrorToText,
resolveMentionGatingWithBypass,
} from "openclaw/plugin-sdk";
@@ -89,19 +91,7 @@ function warnDeprecatedUsersEmailEntries(
}
export function registerGoogleChatWebhookTarget(target: WebhookTarget): () => void {
const key = normalizeWebhookPath(target.path);
const normalizedTarget = { ...target, path: key };
const existing = webhookTargets.get(key) ?? [];
const next = [...existing, normalizedTarget];
webhookTargets.set(key, next);
return () => {
const updated = (webhookTargets.get(key) ?? []).filter((entry) => entry !== normalizedTarget);
if (updated.length > 0) {
webhookTargets.set(key, updated);
} else {
webhookTargets.delete(key);
}
};
return registerWebhookTarget(webhookTargets, target).unregister;
}
function normalizeAudienceType(value?: string | null): GoogleChatAudienceType | undefined {
@@ -123,17 +113,13 @@ export async function handleGoogleChatWebhookRequest(
req: IncomingMessage,
res: ServerResponse,
): Promise<boolean> {
const url = new URL(req.url ?? "/", "http://localhost");
const path = normalizeWebhookPath(url.pathname);
const targets = webhookTargets.get(path);
if (!targets || targets.length === 0) {
const resolved = resolveWebhookTargets(req, webhookTargets);
if (!resolved) {
return false;
}
const { targets } = resolved;
if (req.method !== "POST") {
res.statusCode = 405;
res.setHeader("Allow", "POST");
res.end("Method Not Allowed");
if (rejectNonPostWebhookRequest(req, res)) {
return true;
}

View File

@@ -1,8 +1,9 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { IncomingMessage } from "node:http";
import type { OpenClawConfig, PluginRuntime } from "openclaw/plugin-sdk";
import { EventEmitter } from "node:events";
import { describe, expect, it, vi } from "vitest";
import type { ResolvedGoogleChatAccount } from "./accounts.js";
import { createMockServerResponse } from "../../../src/test-utils/mock-http-response.js";
import { verifyGoogleChatRequest } from "./auth.js";
import { handleGoogleChatWebhookRequest, registerGoogleChatWebhookTarget } from "./monitor.js";
@@ -37,24 +38,6 @@ function createWebhookRequest(params: {
return req;
}
function createWebhookResponse(): ServerResponse & { body?: string } {
const headers: Record<string, string> = {};
const res = {
headersSent: false,
statusCode: 200,
setHeader: (key: string, value: string) => {
headers[key.toLowerCase()] = value;
return res;
},
end: (body?: string) => {
res.headersSent = true;
res.body = body;
return res;
},
} as unknown as ServerResponse & { body?: string };
return res;
}
const baseAccount = (accountId: string) =>
({
accountId,
@@ -105,7 +88,7 @@ describe("Google Chat webhook routing", () => {
const { sinkA, sinkB, unregister } = registerTwoTargets();
try {
const res = createWebhookResponse();
const res = createMockServerResponse();
const handled = await handleGoogleChatWebhookRequest(
createWebhookRequest({
authorization: "Bearer test-token",
@@ -131,7 +114,7 @@ describe("Google Chat webhook routing", () => {
const { sinkA, sinkB, unregister } = registerTwoTargets();
try {
const res = createWebhookResponse();
const res = createMockServerResponse();
const handled = await handleGoogleChatWebhookRequest(
createWebhookRequest({
authorization: "Bearer test-token",

View File

@@ -1,4 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import { installCommonResolveTargetErrorCases } from "../../shared/resolve-target-test-helpers.js";
vi.mock("openclaw/plugin-sdk", () => ({
getChatChannelMeta: () => ({ id: "googlechat", label: "Google Chat" }),
@@ -92,47 +93,8 @@ describe("googlechat resolveTarget", () => {
expect(result.to).toBe("users/user@example.com");
});
it("should error on normalization failure with allowlist (implicit mode)", () => {
const result = resolveTarget({
to: "invalid-target",
mode: "implicit",
allowFrom: ["spaces/BBB"],
});
expect(result.ok).toBe(false);
expect(result.error).toBeDefined();
});
it("should error when no target provided with allowlist", () => {
const result = resolveTarget({
to: undefined,
mode: "implicit",
allowFrom: ["spaces/BBB"],
});
expect(result.ok).toBe(false);
expect(result.error).toBeDefined();
});
it("should error when no target and no allowlist", () => {
const result = resolveTarget({
to: undefined,
mode: "explicit",
allowFrom: [],
});
expect(result.ok).toBe(false);
expect(result.error).toBeDefined();
});
it("should handle whitespace-only target", () => {
const result = resolveTarget({
to: " ",
mode: "explicit",
allowFrom: [],
});
expect(result.ok).toBe(false);
expect(result.error).toBeDefined();
installCommonResolveTargetErrorCases({
resolveTarget,
implicitAllowFrom: ["spaces/BBB"],
});
});