From 426ab5d58c10865e792f9cfe87e1e56778ed861c Mon Sep 17 00:00:00 2001 From: Frank Yang Date: Tue, 14 Apr 2026 17:03:03 +0800 Subject: [PATCH] fix: fail when Baileys dispatcher patch drifts --- scripts/postinstall-bundled-plugins.mjs | 18 ++--- .../stage-bundled-plugin-runtime-deps.test.ts | 66 +++++++++++++++---- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index 8c2c1e2d771..343b841147b 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -295,7 +295,8 @@ export function applyBaileysEncryptedStreamFinishHotfix(params = {}) { BAILEYS_MEDIA_HOTFIX_SEQUENTIAL_AWAITS_RE.test(patchedText))); const encryptedStreamPatchable = patchedText.includes(BAILEYS_MEDIA_HOTFIX_NEEDLE); - if (!encryptedStreamAlreadyPatched && encryptedStreamPatchable) { + let encryptedStreamResolved = encryptedStreamAlreadyPatched; + if (!encryptedStreamResolved && encryptedStreamPatchable) { if (!BAILEYS_MEDIA_ONCE_IMPORT_RE.test(patchedText)) { return { applied: false, reason: "missing_once_import", targetPath }; } @@ -307,6 +308,7 @@ export function applyBaileysEncryptedStreamFinishHotfix(params = {}) { BAILEYS_MEDIA_HOTFIX_REPLACEMENT, ); applied = true; + encryptedStreamResolved = true; } const dispatcherAlreadyPatched = patchedText.includes( @@ -315,8 +317,9 @@ export function applyBaileysEncryptedStreamFinishHotfix(params = {}) { const dispatcherPatchable = patchedText.includes(BAILEYS_MEDIA_DISPATCHER_NEEDLE) && patchedText.includes(BAILEYS_MEDIA_DISPATCHER_HEADER_NEEDLE); + let dispatcherResolved = dispatcherAlreadyPatched; - if (!dispatcherAlreadyPatched && dispatcherPatchable) { + if (!dispatcherResolved && dispatcherPatchable) { patchedText = patchedText .replace(BAILEYS_MEDIA_DISPATCHER_NEEDLE, BAILEYS_MEDIA_DISPATCHER_REPLACEMENT) .replace( @@ -324,15 +327,14 @@ export function applyBaileysEncryptedStreamFinishHotfix(params = {}) { BAILEYS_MEDIA_DISPATCHER_HEADER_REPLACEMENT, ); applied = true; + dispatcherResolved = true; + } + + if (!dispatcherResolved) { + return { applied: false, reason: "unexpected_content" }; } if (!applied) { - if ( - (!encryptedStreamAlreadyPatched && !encryptedStreamPatchable) || - (!dispatcherAlreadyPatched && !dispatcherPatchable) - ) { - return { applied: false, reason: "unexpected_content" }; - } return { applied: false, reason: "already_patched" }; } const tempPath = createTempPath(targetPath); diff --git a/src/plugins/stage-bundled-plugin-runtime-deps.test.ts b/src/plugins/stage-bundled-plugin-runtime-deps.test.ts index e928d9855c8..1dd34d6e69f 100644 --- a/src/plugins/stage-bundled-plugin-runtime-deps.test.ts +++ b/src/plugins/stage-bundled-plugin-runtime-deps.test.ts @@ -65,6 +65,7 @@ function writeRepoFile(repoRoot: string, relativePath: string, value: string) { function createBaileysMessagesMediaSource(params?: { dispatcherPatched?: boolean; + dispatcherHeaderDrifted?: boolean; encryptedStreamPatched?: boolean; encryptedStreamPatchedSequentially?: boolean; encryptedStreamPatchedSequentiallyWithComments?: boolean; @@ -137,18 +138,31 @@ function createBaileysMessagesMediaSource(params?: { " duplex: 'half',", " });", ] - : [ - " const response = await fetch(url, {", - " dispatcher: fetchAgent,", - " method: 'POST',", - " body: stream,", - " headers: {", - " 'Content-Type': 'application/octet-stream',", - " Origin: DEFAULT_ORIGIN", - " },", - " duplex: 'half',", - " });", - ]; + : params?.dispatcherHeaderDrifted + ? [ + " const response = await fetch(url, {", + " dispatcher: fetchAgent,", + " method: 'POST',", + " body: stream,", + " headers: {", + " Origin: DEFAULT_ORIGIN,", + " 'Content-Type': 'application/octet-stream'", + " },", + " duplex: 'half',", + " });", + ] + : [ + " const response = await fetch(url, {", + " dispatcher: fetchAgent,", + " method: 'POST',", + " body: stream,", + " headers: {", + " 'Content-Type': 'application/octet-stream',", + " Origin: DEFAULT_ORIGIN", + " },", + " duplex: 'half',", + " });", + ]; return [ "import { once } from 'events';", "const encryptedStream = async () => {", @@ -394,6 +408,34 @@ describe("stageBundledPluginRuntimeDeps", () => { ); }); + it("fails when the dispatcher block drifts even if encryptedStream is patchable", async () => { + const repoRoot = makeRepoRoot("openclaw-stage-bundled-runtime-hotfix-dispatcher-drifted-"); + const targetPath = path.join( + repoRoot, + "node_modules", + "@whiskeysockets", + "baileys", + "lib", + "Utils", + "messages-media.js", + ); + writeRepoFile( + repoRoot, + "node_modules/@whiskeysockets/baileys/lib/Utils/messages-media.js", + createBaileysMessagesMediaSource({ dispatcherHeaderDrifted: true }), + ); + + const originalText = fs.readFileSync(targetPath, "utf8"); + const { applyBaileysEncryptedStreamFinishHotfix } = await loadPostinstallBundledPluginsModule(); + const result = applyBaileysEncryptedStreamFinishHotfix({ packageRoot: repoRoot }); + + expect(result).toEqual({ + applied: false, + reason: "unexpected_content", + }); + expect(fs.readFileSync(targetPath, "utf8")).toBe(originalText); + }); + it("patches the Baileys dispatcher guard when sequential awaits include comments", async () => { const repoRoot = makeRepoRoot( "openclaw-stage-bundled-runtime-hotfix-dispatcher-sequential-comments-",