From 762fdfb1b32036ffb86ed1e33862b7828c5b5c7b Mon Sep 17 00:00:00 2001 From: Frank Yang Date: Tue, 14 Apr 2026 14:40:19 +0800 Subject: [PATCH] fix: accept sequential Baileys hotfix variant --- scripts/postinstall-bundled-plugins.mjs | 17 ++++- .../stage-bundled-plugin-runtime-deps.test.ts | 63 ++++++++++++++++--- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index ca6d9e4e5d3..56b8fc4df89 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -55,6 +55,17 @@ const BAILEYS_MEDIA_HOTFIX_REPLACEMENT = [ " await Promise.all([encFinishPromise, originalFinishPromise]);", " logger?.debug('encrypted data successfully');", ].join("\n"); +const BAILEYS_MEDIA_HOTFIX_SEQUENTIAL_REPLACEMENT = [ + " encFileWriteStream.write(mac);", + " const encFinishPromise = once(encFileWriteStream, 'finish');", + " const originalFinishPromise = originalFileStream ? once(originalFileStream, 'finish') : Promise.resolve();", + " encFileWriteStream.end();", + " originalFileStream?.end?.();", + " stream.destroy();", + " await encFinishPromise;", + " await originalFinishPromise;", + " logger?.debug('encrypted data successfully');", +].join("\n"); const BAILEYS_MEDIA_DISPATCHER_NEEDLE = [ " const response = await fetch(url, {", " dispatcher: fetchAgent,", @@ -270,7 +281,11 @@ export function applyBaileysEncryptedStreamFinishHotfix(params = {}) { let patchedText = currentText; let applied = false; - if (!patchedText.includes(BAILEYS_MEDIA_HOTFIX_REPLACEMENT)) { + const encryptedStreamAlreadyPatched = + patchedText.includes(BAILEYS_MEDIA_HOTFIX_REPLACEMENT) || + patchedText.includes(BAILEYS_MEDIA_HOTFIX_SEQUENTIAL_REPLACEMENT); + + if (!encryptedStreamAlreadyPatched) { if (!patchedText.includes(BAILEYS_MEDIA_HOTFIX_NEEDLE)) { return { applied: false, reason: "unexpected_content" }; } diff --git a/src/plugins/stage-bundled-plugin-runtime-deps.test.ts b/src/plugins/stage-bundled-plugin-runtime-deps.test.ts index 5c3a44ce6a1..cd65a87cb03 100644 --- a/src/plugins/stage-bundled-plugin-runtime-deps.test.ts +++ b/src/plugins/stage-bundled-plugin-runtime-deps.test.ts @@ -66,8 +66,9 @@ function writeRepoFile(repoRoot: string, relativePath: string, value: string) { function createBaileysMessagesMediaSource(params?: { dispatcherPatched?: boolean; encryptedStreamPatched?: boolean; + encryptedStreamPatchedSequentially?: boolean; }) { - const encryptedLines = params?.encryptedStreamPatched + const encryptedLines = params?.encryptedStreamPatchedSequentially ? [ " encFileWriteStream.write(mac);", " const encFinishPromise = once(encFileWriteStream, 'finish');", @@ -75,16 +76,28 @@ function createBaileysMessagesMediaSource(params?: { " encFileWriteStream.end();", " originalFileStream?.end?.();", " stream.destroy();", - " await Promise.all([encFinishPromise, originalFinishPromise]);", + " await encFinishPromise;", + " await originalFinishPromise;", " logger?.debug('encrypted data successfully');", ] - : [ - " encFileWriteStream.write(mac);", - " encFileWriteStream.end();", - " originalFileStream?.end?.();", - " stream.destroy();", - " logger?.debug('encrypted data successfully');", - ]; + : params?.encryptedStreamPatched + ? [ + " encFileWriteStream.write(mac);", + " const encFinishPromise = once(encFileWriteStream, 'finish');", + " const originalFinishPromise = originalFileStream ? once(originalFileStream, 'finish') : Promise.resolve();", + " encFileWriteStream.end();", + " originalFileStream?.end?.();", + " stream.destroy();", + " await Promise.all([encFinishPromise, originalFinishPromise]);", + " logger?.debug('encrypted data successfully');", + ] + : [ + " encFileWriteStream.write(mac);", + " encFileWriteStream.end();", + " originalFileStream?.end?.();", + " stream.destroy();", + " logger?.debug('encrypted data successfully');", + ]; const dispatcherLines = params?.dispatcherPatched ? [ " const response = await fetch(url, {", @@ -326,6 +339,38 @@ describe("stageBundledPluginRuntimeDeps", () => { ); }); + it("patches the Baileys dispatcher guard when the flush hotfix uses sequential awaits", async () => { + const repoRoot = makeRepoRoot("openclaw-stage-bundled-runtime-hotfix-dispatcher-sequential-"); + 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({ encryptedStreamPatchedSequentially: true }), + ); + + const { applyBaileysEncryptedStreamFinishHotfix } = await loadPostinstallBundledPluginsModule(); + const result = applyBaileysEncryptedStreamFinishHotfix({ packageRoot: repoRoot }); + + expect(result).toEqual({ + applied: true, + reason: "patched", + targetPath, + }); + expect(fs.readFileSync(targetPath, "utf8")).toContain("await encFinishPromise;"); + expect(fs.readFileSync(targetPath, "utf8")).toContain("await originalFinishPromise;"); + expect(fs.readFileSync(targetPath, "utf8")).toContain( + "...(fetchAgent?.dispatch ? { dispatcher: fetchAgent } : {}),", + ); + }); + it("preserves the original module read mode when replacing Baileys", async () => { const repoRoot = makeRepoRoot("openclaw-stage-bundled-runtime-hotfix-mode-"); const targetPath = path.join(