From 00e63da3360fd12a0b5981b67d0e5aca55da5609 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 19:35:48 +0000 Subject: [PATCH] refactor(webhooks): reuse plugin-sdk webhook path helpers --- extensions/googlechat/src/monitor.ts | 43 ++++++++-------------------- extensions/zalo/src/monitor.ts | 32 ++------------------- 2 files changed, 15 insertions(+), 60 deletions(-) diff --git a/extensions/googlechat/src/monitor.ts b/extensions/googlechat/src/monitor.ts index 34f62930ae..d4c9aef436 100644 --- a/extensions/googlechat/src/monitor.ts +++ b/extensions/googlechat/src/monitor.ts @@ -2,7 +2,9 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import type { OpenClawConfig } from "openclaw/plugin-sdk"; import { createReplyPrefixOptions, + normalizeWebhookPath, readJsonBodyWithLimit, + resolveWebhookPath, requestBodyErrorToText, resolveMentionGatingWithBypass, } from "openclaw/plugin-sdk"; @@ -86,34 +88,6 @@ function warnDeprecatedUsersEmailEntries( ); } -function normalizeWebhookPath(raw: string): string { - const trimmed = raw.trim(); - if (!trimmed) { - return "/"; - } - const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`; - if (withSlash.length > 1 && withSlash.endsWith("/")) { - return withSlash.slice(0, -1); - } - return withSlash; -} - -function resolveWebhookPath(webhookPath?: string, webhookUrl?: string): string | null { - const trimmedPath = webhookPath?.trim(); - if (trimmedPath) { - return normalizeWebhookPath(trimmedPath); - } - if (webhookUrl?.trim()) { - try { - const parsed = new URL(webhookUrl); - return normalizeWebhookPath(parsed.pathname || "/"); - } catch { - return null; - } - } - return "/googlechat"; -} - export function registerGoogleChatWebhookTarget(target: WebhookTarget): () => void { const key = normalizeWebhookPath(target.path); const normalizedTarget = { ...target, path: key }; @@ -933,7 +907,11 @@ async function uploadAttachmentForReply(params: { export function monitorGoogleChatProvider(options: GoogleChatMonitorOptions): () => void { const core = getGoogleChatRuntime(); - const webhookPath = resolveWebhookPath(options.webhookPath, options.webhookUrl); + const webhookPath = resolveWebhookPath({ + webhookPath: options.webhookPath, + webhookUrl: options.webhookUrl, + defaultPath: "/googlechat", + }); if (!webhookPath) { options.runtime.error?.(`[${options.account.accountId}] invalid webhook path`); return () => {}; @@ -968,8 +946,11 @@ export function resolveGoogleChatWebhookPath(params: { account: ResolvedGoogleChatAccount; }): string { return ( - resolveWebhookPath(params.account.config.webhookPath, params.account.config.webhookUrl) ?? - "/googlechat" + resolveWebhookPath({ + webhookPath: params.account.config.webhookPath, + webhookUrl: params.account.config.webhookUrl, + defaultPath: "/googlechat", + }) ?? "/googlechat" ); } diff --git a/extensions/zalo/src/monitor.ts b/extensions/zalo/src/monitor.ts index 2c41d8262c..1ee2efb531 100644 --- a/extensions/zalo/src/monitor.ts +++ b/extensions/zalo/src/monitor.ts @@ -2,7 +2,9 @@ import type { IncomingMessage, ServerResponse } from "node:http"; import type { OpenClawConfig, MarkdownTableMode } from "openclaw/plugin-sdk"; import { createReplyPrefixOptions, + normalizeWebhookPath, readJsonBodyWithLimit, + resolveWebhookPath, requestBodyErrorToText, } from "openclaw/plugin-sdk"; import type { ResolvedZaloAccount } from "./accounts.js"; @@ -80,34 +82,6 @@ type WebhookTarget = { const webhookTargets = new Map(); -function normalizeWebhookPath(raw: string): string { - const trimmed = raw.trim(); - if (!trimmed) { - return "/"; - } - const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`; - if (withSlash.length > 1 && withSlash.endsWith("/")) { - return withSlash.slice(0, -1); - } - return withSlash; -} - -function resolveWebhookPath(webhookPath?: string, webhookUrl?: string): string | null { - const trimmedPath = webhookPath?.trim(); - if (trimmedPath) { - return normalizeWebhookPath(trimmedPath); - } - if (webhookUrl?.trim()) { - try { - const parsed = new URL(webhookUrl); - return normalizeWebhookPath(parsed.pathname || "/"); - } catch { - return null; - } - } - return null; -} - export function registerZaloWebhookTarget(target: WebhookTarget): () => void { const key = normalizeWebhookPath(target.path); const normalizedTarget = { ...target, path: key }; @@ -700,7 +674,7 @@ export async function monitorZaloProvider(options: ZaloMonitorOptions): Promise< throw new Error("Zalo webhook secret must be 8-256 characters"); } - const path = resolveWebhookPath(webhookPath, webhookUrl); + const path = resolveWebhookPath({ webhookPath, webhookUrl, defaultPath: null }); if (!path) { throw new Error("Zalo webhookPath could not be derived"); }