@manybot/manybot 5.4.1 → 5.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -26,11 +26,15 @@ function denormalizeJid(jid) {
|
|
|
26
26
|
return jid.replace(/@c\.us$/, "@s.whatsapp.net");
|
|
27
27
|
}
|
|
28
28
|
import { mkdirSync } from "fs";
|
|
29
|
-
import { readFile, writeFile } from "fs/promises";
|
|
29
|
+
import { readFile, writeFile, unlink, mkdtemp, rm } from "fs/promises";
|
|
30
30
|
import { readFileSync } from "fs";
|
|
31
31
|
import path from "path";
|
|
32
|
+
import os from "os";
|
|
33
|
+
import { spawn } from "child_process";
|
|
34
|
+
import { randomUUID } from "crypto";
|
|
32
35
|
import { waitForSendSlot, simulateState, typingDuration, mediaDuration } from "#sendguard";
|
|
33
36
|
import { buildSettingsApi } from "#settingsdb";
|
|
37
|
+
import WebP from "node-webpmux";
|
|
34
38
|
import { downloadMediaMessage, getAggregateVotesInPollMessage, decryptPollVote, jidNormalizedUser, normalizeMessageContent } from "@whiskeysockets/baileys";
|
|
35
39
|
// ── Message body / type helpers ───────────────────────────────────────────────
|
|
36
40
|
// WhatsApp wraps media in ephemeralMessage/viewOnceMessage/etc when sent as
|
|
@@ -206,6 +210,26 @@ const MIME_MAP = {
|
|
|
206
210
|
function mimeFromPath(filePath) {
|
|
207
211
|
return MIME_MAP[path.extname(filePath).toLowerCase()] ?? "application/octet-stream";
|
|
208
212
|
}
|
|
213
|
+
// ── Media source resolution (path or Buffer) ────────────────────────────────
|
|
214
|
+
/**
|
|
215
|
+
* Resolves a media source to a Buffer. Every ctx.send.* / msg.reply.*
|
|
216
|
+
* media method accepts either a filesystem path (string) or an
|
|
217
|
+
* already-loaded Buffer — this is what auto-detects which one it got.
|
|
218
|
+
*/
|
|
219
|
+
async function resolveMediaBuffer(source) {
|
|
220
|
+
return Buffer.isBuffer(source) ? source : await readFile(source);
|
|
221
|
+
}
|
|
222
|
+
const GIF_MAGIC = Buffer.from("GIF8");
|
|
223
|
+
/** True if the buffer's magic bytes identify it as a raw .gif image. */
|
|
224
|
+
function isGifBuffer(buffer) {
|
|
225
|
+
return buffer.length >= 4 && buffer.subarray(0, 4).equals(GIF_MAGIC);
|
|
226
|
+
}
|
|
227
|
+
/** True if a gif() source needs ffmpeg conversion to mp4 before sending. */
|
|
228
|
+
function needsGifConversion(source) {
|
|
229
|
+
return Buffer.isBuffer(source)
|
|
230
|
+
? isGifBuffer(source)
|
|
231
|
+
: path.extname(source).toLowerCase() === ".gif";
|
|
232
|
+
}
|
|
209
233
|
// ── Storage API ───────────────────────────────────────────────────────────────
|
|
210
234
|
export function buildStorageApi(pluginName) {
|
|
211
235
|
if (typeof pluginName !== "string" || pluginName.trim() === "") {
|
|
@@ -435,7 +459,6 @@ function buildContactsApi(sock, store, botJid) {
|
|
|
435
459
|
* Get a normalized contact object by JID.
|
|
436
460
|
* @param {string} contactId
|
|
437
461
|
* @param {{groupId?: string}} [opts] — when `contactId` is a raw `@lid`, this
|
|
438
|
-
|
|
439
462
|
* always cross-checks it against Baileys' own protocol-level
|
|
440
463
|
* `sock.signalRepository.lidMapping` first (populated from real Signal
|
|
441
464
|
* session/identity resolution — not a heuristic, and doesn't need a
|
|
@@ -652,11 +675,16 @@ export function buildMessageContext(msg, sock, store, guardOptions = {}) {
|
|
|
652
675
|
},
|
|
653
676
|
hasMedia: msgHasMedia(msg),
|
|
654
677
|
isGif: msgIsGif(msg),
|
|
655
|
-
async downloadMedia() {
|
|
678
|
+
async downloadMedia(opts = {}) {
|
|
656
679
|
try {
|
|
657
680
|
const buffer = await downloadMediaMessage(msg, "buffer", {});
|
|
658
681
|
if (!buffer || !Buffer.isBuffer(buffer))
|
|
659
682
|
return null;
|
|
683
|
+
const isAnimatedSticker = !!unwrap(msg)?.stickerMessage?.isAnimated;
|
|
684
|
+
if (opts.asMp4 && isAnimatedSticker) {
|
|
685
|
+
const mp4 = await stickerToMp4(buffer);
|
|
686
|
+
return { mimetype: "video/mp4", data: mp4.toString("base64") };
|
|
687
|
+
}
|
|
660
688
|
return { mimetype: getMsgMimetype(msg), data: buffer.toString("base64") };
|
|
661
689
|
}
|
|
662
690
|
catch {
|
|
@@ -678,6 +706,12 @@ export function buildMessageContext(msg, sock, store, guardOptions = {}) {
|
|
|
678
706
|
return sock.sendMessage(rawJid, { delete: msg.key });
|
|
679
707
|
}
|
|
680
708
|
},
|
|
709
|
+
async edit(text) {
|
|
710
|
+
if (!msg.key.fromMe) {
|
|
711
|
+
throw new Error("[pluginApi] edit() can only be used on the bot's own messages");
|
|
712
|
+
}
|
|
713
|
+
return sock.sendMessage(rawJid, { text, edit: msg.key });
|
|
714
|
+
},
|
|
681
715
|
async pin(_duration) {
|
|
682
716
|
logger.warn("[pluginApi] pin() is not supported with Baileys");
|
|
683
717
|
},
|
|
@@ -764,8 +798,141 @@ class MessageHandle {
|
|
|
764
798
|
react: { text: emoji, key: msg.key },
|
|
765
799
|
});
|
|
766
800
|
}
|
|
801
|
+
/** Edit the sent message's text. Only works on the bot's own messages. */
|
|
802
|
+
async edit(text) {
|
|
803
|
+
const msg = await this.rawPromise;
|
|
804
|
+
if (!msg?.key)
|
|
805
|
+
return;
|
|
806
|
+
if (!msg.key.fromMe) {
|
|
807
|
+
throw new Error("[pluginApi] edit() can only be used on the bot's own messages");
|
|
808
|
+
}
|
|
809
|
+
return this._sock.sendMessage(msg.key.remoteJid, { text, edit: msg.key });
|
|
810
|
+
}
|
|
767
811
|
}
|
|
768
812
|
// ── Sender factory ────────────────────────────────────────────────────────────
|
|
813
|
+
function runFfmpeg(args) {
|
|
814
|
+
return new Promise((resolve, reject) => {
|
|
815
|
+
const proc = spawn("ffmpeg", args, { stdio: "ignore" });
|
|
816
|
+
proc.on("error", (err) => {
|
|
817
|
+
if (err.code === "ENOENT") {
|
|
818
|
+
reject(new Error("ffmpeg not found on PATH — required to send .gif files. Install ffmpeg, or pass an already mp4-encoded file to gif()."));
|
|
819
|
+
}
|
|
820
|
+
else {
|
|
821
|
+
reject(err);
|
|
822
|
+
}
|
|
823
|
+
});
|
|
824
|
+
proc.on("exit", (code) => (code === 0 ? resolve() : reject(new Error(`ffmpeg exited with code ${code}`))));
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Converts a raw .gif to an mp4 WhatsApp can actually decode as a video —
|
|
829
|
+
* sending GIF89a bytes labeled as video/mp4 leaves the client unable to
|
|
830
|
+
* play it (blurred placeholder + download button, no inline loop).
|
|
831
|
+
*/
|
|
832
|
+
async function gifToMp4(gifSource) {
|
|
833
|
+
const outPath = path.join(os.tmpdir(), `${randomUUID()}.mp4`);
|
|
834
|
+
const isBuffer = Buffer.isBuffer(gifSource);
|
|
835
|
+
const inPath = isBuffer ? path.join(os.tmpdir(), `${randomUUID()}.gif`) : gifSource;
|
|
836
|
+
try {
|
|
837
|
+
if (isBuffer)
|
|
838
|
+
await writeFile(inPath, gifSource);
|
|
839
|
+
await runFfmpeg([
|
|
840
|
+
"-y",
|
|
841
|
+
"-i", inPath,
|
|
842
|
+
"-movflags", "faststart",
|
|
843
|
+
"-pix_fmt", "yuv420p",
|
|
844
|
+
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
|
|
845
|
+
outPath,
|
|
846
|
+
]);
|
|
847
|
+
return await readFile(outPath);
|
|
848
|
+
}
|
|
849
|
+
finally {
|
|
850
|
+
await unlink(outPath).catch(() => { });
|
|
851
|
+
if (isBuffer)
|
|
852
|
+
await unlink(inPath).catch(() => { });
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Converts an animated-sticker WebP buffer to mp4.
|
|
857
|
+
*
|
|
858
|
+
* ffmpeg's own "webp" decoder cannot read animated WebP at all — it
|
|
859
|
+
* silently skips the ANIM/ANMF chunks ("skipping unsupported chunk: ANIM",
|
|
860
|
+
* "image data not found") and the whole conversion fails. This is a
|
|
861
|
+
* long-standing ffmpeg limitation (still true as of ffmpeg-devel
|
|
862
|
+
* discussion in mid-2025: "we have no [animated webp] decoder"), not
|
|
863
|
+
* anything specific to this bot — passing an animated .webp straight to
|
|
864
|
+
* `ffmpeg -i` always fails this way, no matter what you ask it to output.
|
|
865
|
+
*
|
|
866
|
+
* Workaround: use node-webpmux (already a project dependency, bundles its
|
|
867
|
+
* own libwebp via WASM) to demux the animation into individual
|
|
868
|
+
* single-frame WebP files — those decode fine with ffmpeg, since only the
|
|
869
|
+
* ANIM *container* trips it up, not the WebP codec itself — then hand
|
|
870
|
+
* ffmpeg a concat list with each frame's real delay so timing survives.
|
|
871
|
+
*
|
|
872
|
+
* Caveat: this assumes each ANMF frame is a full-canvas frame, which is
|
|
873
|
+
* true for the vast majority of sticker-maker output. Stickers authored
|
|
874
|
+
* with partial-frame deltas (a blend region smaller than the canvas)
|
|
875
|
+
* won't composite correctly here — that would need full RGBA canvas
|
|
876
|
+
* compositing via getFrameData() per frame, which isn't implemented.
|
|
877
|
+
*/
|
|
878
|
+
async function stickerToMp4(webpBuffer) {
|
|
879
|
+
const img = new WebP.Image();
|
|
880
|
+
await img.load(webpBuffer);
|
|
881
|
+
const outPath = path.join(os.tmpdir(), `${randomUUID()}.mp4`);
|
|
882
|
+
const scaleFilter = "scale=trunc(iw/2)*2:trunc(ih/2)*2";
|
|
883
|
+
if (!img.hasAnim) {
|
|
884
|
+
// Not actually animated — a plain static webp decodes fine on its own.
|
|
885
|
+
const inPath = path.join(os.tmpdir(), `${randomUUID()}.webp`);
|
|
886
|
+
try {
|
|
887
|
+
await writeFile(inPath, webpBuffer);
|
|
888
|
+
await runFfmpeg([
|
|
889
|
+
"-y",
|
|
890
|
+
"-i", inPath,
|
|
891
|
+
"-movflags", "faststart",
|
|
892
|
+
"-pix_fmt", "yuv420p",
|
|
893
|
+
"-vf", scaleFilter,
|
|
894
|
+
outPath,
|
|
895
|
+
]);
|
|
896
|
+
return await readFile(outPath);
|
|
897
|
+
}
|
|
898
|
+
finally {
|
|
899
|
+
await unlink(inPath).catch(() => { });
|
|
900
|
+
await unlink(outPath).catch(() => { });
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "sticker-"));
|
|
904
|
+
try {
|
|
905
|
+
const frameBuffers = await img.demux({ buffers: true });
|
|
906
|
+
const delays = (img.frames ?? []).map(f => (f.delay > 0 ? f.delay : 100)); // ms; WebP spec treats 0 as implementation-defined
|
|
907
|
+
const listLines = [];
|
|
908
|
+
for (let i = 0; i < frameBuffers.length; i++) {
|
|
909
|
+
const framePath = path.join(dir, `frame_${i}.webp`);
|
|
910
|
+
await writeFile(framePath, frameBuffers[i]);
|
|
911
|
+
listLines.push(`file '${framePath}'`);
|
|
912
|
+
listLines.push(`duration ${((delays[i] ?? 100) / 1000).toFixed(3)}`);
|
|
913
|
+
}
|
|
914
|
+
// The concat demuxer ignores the final `duration` line unless the last
|
|
915
|
+
// file is listed once more after it.
|
|
916
|
+
listLines.push(`file '${path.join(dir, `frame_${frameBuffers.length - 1}.webp`)}'`);
|
|
917
|
+
const listPath = path.join(dir, "list.txt");
|
|
918
|
+
await writeFile(listPath, listLines.join("\n"));
|
|
919
|
+
await runFfmpeg([
|
|
920
|
+
"-y",
|
|
921
|
+
"-f", "concat", "-safe", "0",
|
|
922
|
+
"-i", listPath,
|
|
923
|
+
"-vsync", "vfr",
|
|
924
|
+
"-pix_fmt", "yuv420p",
|
|
925
|
+
"-vf", scaleFilter,
|
|
926
|
+
"-movflags", "faststart",
|
|
927
|
+
outPath,
|
|
928
|
+
]);
|
|
929
|
+
return await readFile(outPath);
|
|
930
|
+
}
|
|
931
|
+
finally {
|
|
932
|
+
await rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
933
|
+
await unlink(outPath).catch(() => { });
|
|
934
|
+
}
|
|
935
|
+
}
|
|
769
936
|
/**
|
|
770
937
|
* Returns send methods bound to a specific JID.
|
|
771
938
|
*
|
|
@@ -809,13 +976,13 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
|
|
|
809
976
|
return sock.sendMessage(jid, messageContent, sendOpts);
|
|
810
977
|
})(), sock, store, { cooldown, jitter });
|
|
811
978
|
},
|
|
812
|
-
image(
|
|
979
|
+
image(source, caption = "", opts = {}) {
|
|
813
980
|
return new MessageHandle((async () => {
|
|
814
981
|
const quotedMsg = await resolveQuoted();
|
|
815
982
|
const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
|
|
816
983
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
817
984
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
|
|
818
|
-
const buffer = await
|
|
985
|
+
const buffer = await resolveMediaBuffer(source);
|
|
819
986
|
// viewOnce/mentions are part of the message CONTENT — see note above.
|
|
820
987
|
const messageContent = { image: buffer, caption };
|
|
821
988
|
if (opts.viewOnce) {
|
|
@@ -827,13 +994,13 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
|
|
|
827
994
|
return sock.sendMessage(jid, messageContent, sendOpts);
|
|
828
995
|
})(), sock, store, { cooldown, jitter });
|
|
829
996
|
},
|
|
830
|
-
video(
|
|
997
|
+
video(source, caption = "", opts = {}) {
|
|
831
998
|
return new MessageHandle((async () => {
|
|
832
999
|
const quotedMsg = await resolveQuoted();
|
|
833
1000
|
const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
|
|
834
1001
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
835
1002
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
|
|
836
|
-
const buffer = await
|
|
1003
|
+
const buffer = await resolveMediaBuffer(source);
|
|
837
1004
|
// viewOnce/mentions are part of the message CONTENT — see note above.
|
|
838
1005
|
const messageContent = { video: buffer, caption };
|
|
839
1006
|
if (opts.viewOnce) {
|
|
@@ -848,15 +1015,20 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
|
|
|
848
1015
|
/**
|
|
849
1016
|
* Send a GIF. WhatsApp has no native GIF format — this sends an mp4
|
|
850
1017
|
* with the `gifPlayback` flag, which the client auto-loops, muted.
|
|
851
|
-
*
|
|
1018
|
+
* Accepts a path or a Buffer. `.gif` input (detected by extension for
|
|
1019
|
+
* a path, or by magic bytes for a Buffer) is converted to mp4 via
|
|
1020
|
+
* ffmpeg automatically; already mp4-encoded input is sent as-is, no
|
|
1021
|
+
* conversion cost.
|
|
852
1022
|
*/
|
|
853
|
-
gif(
|
|
1023
|
+
gif(source, caption = "", opts = {}) {
|
|
854
1024
|
return new MessageHandle((async () => {
|
|
855
1025
|
const quotedMsg = await resolveQuoted();
|
|
856
1026
|
const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
|
|
857
1027
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
858
1028
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
|
|
859
|
-
const buffer =
|
|
1029
|
+
const buffer = needsGifConversion(source)
|
|
1030
|
+
? await gifToMp4(source)
|
|
1031
|
+
: await resolveMediaBuffer(source);
|
|
860
1032
|
const messageContent = { video: buffer, caption, gifPlayback: true };
|
|
861
1033
|
if (opts.viewOnce) {
|
|
862
1034
|
messageContent.viewOnce = true;
|
|
@@ -867,13 +1039,13 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
|
|
|
867
1039
|
return sock.sendMessage(jid, messageContent, sendOpts);
|
|
868
1040
|
})(), sock, store, { cooldown, jitter });
|
|
869
1041
|
},
|
|
870
|
-
audio(
|
|
1042
|
+
audio(source, { asVoice = true, viewOnce = false } = {}) {
|
|
871
1043
|
return new MessageHandle((async () => {
|
|
872
1044
|
const quotedMsg = await resolveQuoted();
|
|
873
1045
|
const sendOpts = quotedMsg ? { quoted: quotedMsg } : {};
|
|
874
1046
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
875
1047
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "recording");
|
|
876
|
-
const buffer = await
|
|
1048
|
+
const buffer = await resolveMediaBuffer(source);
|
|
877
1049
|
// viewOnce is part of the message CONTENT — see note above.
|
|
878
1050
|
const messageContent = { audio: buffer, mimetype: "audio/mp4", ptt: asVoice };
|
|
879
1051
|
if (viewOnce) {
|
|
@@ -888,22 +1060,28 @@ function makeSender(sock, store, jid, quoted = null, { cooldown = true, jitter =
|
|
|
888
1060
|
const qOpts = quotedMsg ? { quoted: quotedMsg } : undefined;
|
|
889
1061
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
890
1062
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
|
|
891
|
-
const buffer =
|
|
1063
|
+
const buffer = await resolveMediaBuffer(source);
|
|
892
1064
|
return sock.sendMessage(jid, { sticker: buffer }, qOpts);
|
|
893
1065
|
})(), sock, store, { cooldown, jitter });
|
|
894
1066
|
},
|
|
895
|
-
file(
|
|
1067
|
+
file(source, filename) {
|
|
896
1068
|
return new MessageHandle((async () => {
|
|
897
1069
|
const quotedMsg = await resolveQuoted();
|
|
898
1070
|
const qOpts = quotedMsg ? { quoted: quotedMsg } : undefined;
|
|
899
1071
|
await waitForSendSlot(normJid, { cooldown, jitter });
|
|
900
1072
|
await simulateState(toPresenceCapable(sock), jid, mediaDuration(), "typing");
|
|
901
|
-
const
|
|
902
|
-
const
|
|
1073
|
+
const isBuffer = Buffer.isBuffer(source);
|
|
1074
|
+
const buffer = await resolveMediaBuffer(source);
|
|
1075
|
+
// With a path we can always infer the mimetype/name from it. With a
|
|
1076
|
+
// raw Buffer there's no extension to read, so an explicit `filename`
|
|
1077
|
+
// is what lets us infer the mimetype too — otherwise we fall back to
|
|
1078
|
+
// a generic octet-stream document named "file".
|
|
1079
|
+
const mimetype = filename ? mimeFromPath(filename) : (isBuffer ? "application/octet-stream" : mimeFromPath(source));
|
|
1080
|
+
const resolvedFilename = filename ?? (isBuffer ? "file" : path.basename(source));
|
|
903
1081
|
return sock.sendMessage(jid, {
|
|
904
1082
|
document: buffer,
|
|
905
1083
|
mimetype,
|
|
906
|
-
fileName:
|
|
1084
|
+
fileName: resolvedFilename,
|
|
907
1085
|
}, qOpts);
|
|
908
1086
|
})(), sock, store, { cooldown, jitter });
|
|
909
1087
|
},
|
|
@@ -938,12 +1116,12 @@ function buildSendApi(sock, store, rawJid, guardOptions = {}) {
|
|
|
938
1116
|
return {
|
|
939
1117
|
send: {
|
|
940
1118
|
text: (text, opts) => current.text(text, opts),
|
|
941
|
-
image: (
|
|
942
|
-
video: (
|
|
943
|
-
gif: (
|
|
944
|
-
audio: (
|
|
1119
|
+
image: (source, caption, opts) => current.image(source, caption, opts),
|
|
1120
|
+
video: (source, caption, opts) => current.video(source, caption, opts),
|
|
1121
|
+
gif: (source, caption, opts) => current.gif(source, caption, opts),
|
|
1122
|
+
audio: (source, opts) => current.audio(source, opts),
|
|
945
1123
|
sticker: (source) => current.sticker(source),
|
|
946
|
-
file: (
|
|
1124
|
+
file: (source, filename) => current.file(source, filename),
|
|
947
1125
|
poll: (q, opts, cfg) => current.poll(q, opts, cfg),
|
|
948
1126
|
/**
|
|
949
1127
|
* Returns a sender bound to another chat.
|
|
@@ -1656,11 +1834,16 @@ export function buildApi({ msg, chat, sock, store, pluginRegistry, pluginName, g
|
|
|
1656
1834
|
sock,
|
|
1657
1835
|
store,
|
|
1658
1836
|
msg,
|
|
1659
|
-
downloadMedia: async () => {
|
|
1837
|
+
downloadMedia: async (opts = {}) => {
|
|
1660
1838
|
try {
|
|
1661
1839
|
const buffer = await downloadMediaMessage(msg, "buffer", {});
|
|
1662
1840
|
if (!buffer || !Buffer.isBuffer(buffer))
|
|
1663
1841
|
return null;
|
|
1842
|
+
const isAnimatedSticker = !!unwrap(msg)?.stickerMessage?.isAnimated;
|
|
1843
|
+
if (opts.asMp4 && isAnimatedSticker) {
|
|
1844
|
+
const mp4 = await stickerToMp4(buffer);
|
|
1845
|
+
return { mimetype: "video/mp4", data: mp4.toString("base64") };
|
|
1846
|
+
}
|
|
1664
1847
|
return { mimetype: getMsgMimetype(msg), data: buffer.toString("base64") };
|
|
1665
1848
|
}
|
|
1666
1849
|
catch {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Creates and returns a Baileys WASocket.
|
|
5
5
|
* Handles auth state persistence, QR/pairing-code display, and reconnection.
|
|
6
6
|
*/
|
|
7
|
-
import makeWASocket,
|
|
7
|
+
import { makeWASocket, useMultiFileAuthState, fetchLatestBaileysVersion, Browsers, WAProto, } from "@whiskeysockets/baileys";
|
|
8
8
|
import path from "path";
|
|
9
9
|
import qrcode from "qrcode-terminal";
|
|
10
10
|
import { CONFIG_DIR, CLIENT_ID } from "#config";
|
|
@@ -57,7 +57,7 @@ export async function createSocket(authDirName = CLIENT_ID) {
|
|
|
57
57
|
// https://github.com/WhiskeySockets/Baileys — SocketConfig docs).
|
|
58
58
|
// This keeps the initial/recent sync (needed for store.chats and
|
|
59
59
|
// LID→phone resolution) while still skipping the full download.
|
|
60
|
-
shouldSyncHistoryMessage: ({ syncType }) => syncType !==
|
|
60
|
+
shouldSyncHistoryMessage: ({ syncType }) => syncType !== WAProto.HistorySync.HistorySyncType.FULL,
|
|
61
61
|
// Required for Baileys to decrypt incoming poll votes (and to retry
|
|
62
62
|
// sends) — it looks up the original message by key internally.
|
|
63
63
|
// Without this, pollUpdates never resolve even though the vote event
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "SyntaxError!",
|
|
6
6
|
"email": "me@stxerr.dev"
|
|
7
7
|
},
|
|
8
|
-
"version": "5.
|
|
8
|
+
"version": "5.5.1",
|
|
9
9
|
"license": "GPL-3.0-only",
|
|
10
10
|
"private": false,
|
|
11
11
|
"engines": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@clack/prompts": "^0.10.1",
|
|
39
39
|
"@hapi/boom": "^10.0.1",
|
|
40
|
-
"@whiskeysockets/baileys": "^6.
|
|
40
|
+
"@whiskeysockets/baileys": "^6.17.16",
|
|
41
41
|
"node-cron": "^4.6.0",
|
|
42
42
|
"node-webpmux": "^3.2.1",
|
|
43
43
|
"pino": "^10.3.1",
|