jagproject 26.3.23 → 26.3.26
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.
- package/WAProto/GenerateStatics.sh +3 -4
- package/WAProto/WAProto.proto +1215 -511
- package/WAProto/fix-imports.js +73 -0
- package/WAProto/index.d.ts +14017 -0
- package/WAProto/index.js +64857 -145167
- package/engine-requirements.js +4 -7
- package/lib/Defaults/index.d.ts +74 -0
- package/lib/Defaults/index.js +49 -35
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Defaults/wileys-version.json +2 -2
- package/lib/Signal/Group/ciphertext-message.d.ts +10 -0
- package/lib/Signal/Group/group-session-builder.d.ts +15 -0
- package/lib/Signal/Group/group-session-builder.js +5 -3
- package/lib/Signal/Group/group_cipher.d.ts +17 -0
- package/lib/Signal/Group/group_cipher.js +35 -46
- package/lib/Signal/Group/index.d.ts +12 -0
- package/lib/Signal/Group/index.js +21 -21
- package/lib/Signal/Group/keyhelper.d.ts +11 -0
- package/lib/Signal/Group/keyhelper.js +2 -2
- package/lib/Signal/Group/sender-chain-key.d.ts +14 -0
- package/lib/Signal/Group/sender-chain-key.js +5 -10
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +17 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
- package/lib/Signal/Group/sender-key-message.d.ts +19 -0
- package/lib/Signal/Group/sender-key-message.js +8 -8
- package/lib/Signal/Group/sender-key-name.d.ts +18 -0
- package/lib/Signal/Group/sender-key-record.d.ts +31 -0
- package/lib/Signal/Group/sender-key-record.js +7 -16
- package/lib/Signal/Group/sender-key-state.d.ts +39 -0
- package/lib/Signal/Group/sender-key-state.js +25 -37
- package/lib/Signal/Group/sender-message-key.d.ts +12 -0
- package/lib/Signal/Group/sender-message-key.js +2 -2
- package/lib/Signal/libsignal.d.ts +5 -0
- package/lib/Signal/libsignal.js +358 -54
- package/lib/Signal/lid-mapping.d.ts +19 -0
- package/lib/Signal/lid-mapping.js +274 -0
- package/lib/Socket/Client/index.d.ts +3 -0
- package/lib/Socket/Client/index.js +2 -2
- package/lib/Socket/Client/types.d.ts +16 -0
- package/lib/Socket/Client/types.js +1 -0
- package/lib/Socket/Client/websocket.d.ts +13 -0
- package/lib/Socket/Client/websocket.js +18 -30
- package/lib/Socket/business.d.ts +202 -0
- package/lib/Socket/business.js +160 -38
- package/lib/Socket/chats.d.ts +111 -0
- package/lib/Socket/chats.js +497 -314
- package/lib/Socket/communities.d.ts +258 -0
- package/lib/Socket/communities.js +438 -0
- package/lib/Socket/community.js +333 -0
- package/lib/Socket/groups.d.ts +150 -0
- package/lib/Socket/groups.js +229 -91
- package/lib/Socket/index.d.ts +245 -0
- package/lib/Socket/index.js +9 -6
- package/lib/Socket/messages-recv.d.ts +187 -0
- package/lib/Socket/messages-recv.js +1105 -501
- package/lib/Socket/messages-send.d.ts +183 -0
- package/lib/Socket/messages-send.js +1181 -501
- package/lib/Socket/mex.d.ts +3 -0
- package/lib/Socket/mex.js +45 -0
- package/lib/Socket/newsletter.d.ts +160 -0
- package/lib/Socket/newsletter.js +227 -200
- package/lib/Socket/socket.d.ts +55 -0
- package/lib/Socket/socket.js +507 -206
- package/lib/Socket/usync.js +6 -6
- package/lib/Store/index.js +17 -5
- package/lib/Store/make-cache-manager-store.js +83 -0
- package/lib/Store/make-in-memory-store.js +48 -89
- package/lib/Store/make-ordered-dictionary.js +1 -1
- package/lib/Types/Auth.d.ts +116 -0
- package/lib/Types/Bussines.d.ts +25 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.d.ts +15 -0
- package/lib/Types/Chat.d.ts +123 -0
- package/lib/Types/Chat.js +7 -1
- package/lib/Types/Contact.d.ts +24 -0
- package/lib/Types/Events.d.ts +237 -0
- package/lib/Types/Events.js +1 -0
- package/lib/Types/GroupMetadata.d.ts +67 -0
- package/lib/Types/Label.d.ts +47 -0
- package/lib/Types/Label.js +1 -3
- package/lib/Types/LabelAssociation.d.ts +30 -0
- package/lib/Types/LabelAssociation.js +1 -3
- package/lib/Types/Message.d.ts +305 -0
- package/lib/Types/Message.js +9 -5
- package/lib/Types/MexUpdates.js +11 -0
- package/lib/Types/Newsletter.d.ts +135 -0
- package/lib/Types/Newsletter.js +36 -11
- package/lib/Types/Product.d.ts +79 -0
- package/lib/Types/Signal.d.ts +76 -0
- package/lib/Types/Signal.js +1 -0
- package/lib/Types/Socket.d.ts +133 -0
- package/lib/Types/Socket.js +1 -0
- package/lib/Types/State.d.ts +39 -0
- package/lib/Types/State.js +12 -0
- package/lib/Types/USync.d.ts +26 -0
- package/lib/Types/USync.js +1 -0
- package/lib/Types/index.d.ts +65 -0
- package/lib/Types/index.js +14 -14
- package/lib/Utils/audioToBuffer.js +31 -0
- package/lib/Utils/auth-utils.d.ts +19 -0
- package/lib/Utils/auth-utils.js +222 -123
- package/lib/Utils/baileys-event-stream.js +60 -0
- package/lib/Utils/bridge-runtime.d.ts +1 -0
- package/lib/Utils/bridge-runtime.js +14 -0
- package/lib/Utils/browser-utils.d.ts +4 -0
- package/lib/Utils/browser-utils.js +38 -29
- package/lib/Utils/business.d.ts +23 -0
- package/lib/Utils/business.js +54 -48
- package/lib/Utils/chat-utils.d.ts +70 -0
- package/lib/Utils/chat-utils.js +284 -189
- package/lib/Utils/crypto.d.ts +37 -0
- package/lib/Utils/crypto.js +16 -41
- package/lib/Utils/decode-wa-message.d.ts +48 -0
- package/lib/Utils/decode-wa-message.js +128 -48
- package/lib/Utils/event-buffer.d.ts +34 -0
- package/lib/Utils/event-buffer.js +124 -62
- package/lib/Utils/generics.d.ts +91 -0
- package/lib/Utils/generics.js +154 -138
- package/lib/Utils/history.d.ts +22 -0
- package/lib/Utils/history.js +77 -34
- package/lib/Utils/identity-change-handler.d.ts +37 -0
- package/lib/Utils/identity-change-handler.js +54 -0
- package/lib/Utils/index.d.ts +22 -0
- package/lib/Utils/index.js +32 -19
- package/lib/Utils/link-preview.d.ts +21 -0
- package/lib/Utils/link-preview.js +12 -17
- package/lib/Utils/logger.d.ts +13 -0
- package/lib/Utils/lt-hash.d.ts +8 -0
- package/lib/Utils/lt-hash.js +2 -43
- package/lib/Utils/make-mutex.d.ts +9 -0
- package/lib/Utils/make-mutex.js +21 -27
- package/lib/Utils/message-retry-manager.d.ts +110 -0
- package/lib/Utils/message-retry-manager.js +143 -45
- package/lib/Utils/messages-media.d.ts +130 -0
- package/lib/Utils/messages-media.js +429 -502
- package/lib/Utils/messages-newsletter.d.ts +84 -0
- package/lib/Utils/messages-newsletter.js +295 -0
- package/lib/Utils/messages.d.ts +92 -0
- package/lib/Utils/messages.js +1025 -674
- package/lib/Utils/noise-handler.d.ts +20 -0
- package/lib/Utils/noise-handler.js +145 -91
- package/lib/Utils/pre-key-manager.d.ts +28 -0
- package/lib/Utils/pre-key-manager.js +112 -0
- package/lib/Utils/process-message.d.ts +60 -0
- package/lib/Utils/process-message.js +316 -184
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.js +262 -0
- package/lib/Utils/resolve-jid.d.ts +43 -0
- package/lib/Utils/resolve-jid.js +95 -0
- package/lib/Utils/rust-bridge-shim.d.ts +22 -0
- package/lib/Utils/rust-bridge-shim.js +70 -0
- package/lib/Utils/serial-task-queue.js +29 -0
- package/lib/Utils/signal.d.ts +34 -0
- package/lib/Utils/signal.js +56 -39
- package/lib/Utils/streamToBuffer.js +17 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.js +52 -0
- package/lib/Utils/tc-token-utils.d.ts +12 -0
- package/lib/Utils/tc-token-utils.js +20 -0
- package/lib/Utils/use-mongo-file-auth-state.js +71 -0
- package/lib/Utils/use-multi-file-auth-state.d.ts +13 -0
- package/lib/Utils/use-multi-file-auth-state.js +11 -12
- package/lib/Utils/use-single-file-auth-state.js +73 -0
- package/lib/Utils/validate-connection.d.ts +11 -0
- package/lib/Utils/validate-connection.js +59 -82
- package/lib/Utils/wileys-event-stream.js +1 -61
- package/lib/WABinary/constants.d.ts +28 -0
- package/lib/WABinary/decode.d.ts +7 -0
- package/lib/WABinary/decode.js +39 -4
- package/lib/WABinary/encode.d.ts +3 -0
- package/lib/WABinary/encode.js +17 -11
- package/lib/WABinary/generic-utils.d.ts +15 -0
- package/lib/WABinary/generic-utils.js +46 -18
- package/lib/WABinary/index.d.ts +6 -0
- package/lib/WABinary/index.js +9 -5
- package/lib/WABinary/jid-utils.d.ts +48 -0
- package/lib/WABinary/jid-utils.js +67 -37
- package/lib/WABinary/types.d.ts +19 -0
- package/lib/WABinary/types.js +34 -0
- package/lib/WAM/BinaryInfo.d.ts +9 -0
- package/lib/WAM/constants.d.ts +40 -0
- package/lib/WAM/constants.js +19183 -11678
- package/lib/WAM/encode.d.ts +3 -0
- package/lib/WAM/encode.js +15 -17
- package/lib/WAM/index.d.ts +4 -0
- package/lib/WAM/index.js +3 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +6 -6
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +23 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +9 -9
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +13 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +6 -6
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +13 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +7 -8
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +26 -0
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +18 -17
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +10 -0
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +11 -3
- package/lib/WAUSync/Protocols/index.d.ts +5 -0
- package/lib/WAUSync/Protocols/index.js +6 -4
- package/lib/WAUSync/USyncQuery.d.ts +29 -0
- package/lib/WAUSync/USyncQuery.js +38 -30
- package/lib/WAUSync/USyncUser.d.ts +13 -0
- package/lib/WAUSync/index.d.ts +4 -0
- package/lib/WAUSync/index.js +3 -3
- package/lib/index.d.ts +12 -0
- package/lib/index.js +3 -5
- package/package.json +7 -4
- package/LICENSE +0 -21
package/lib/Utils/messages.js
CHANGED
|
@@ -1,43 +1,164 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
|
|
36
|
+
exports.getQuotedMsg = exports.prepareAlbumMessageContent = exports.patchMessageForMdIfRequired = exports.assertMediaContent = exports.downloadMediaMessage = exports.aggregateMessageKeysNotFromMe = exports.updateMessageWithEventResponse = exports.updateMessageWithPollUpdate = exports.updateMessageWithReaction = exports.updateMessageWithReceipt = exports.getDevice = exports.extractMessageContent = exports.normalizeMessageContent = exports.getMediaTypeFromContentType = exports.getContentType = exports.generateWAMessage = exports.generateWAMessageFromContent = exports.generateWAMessageContent = exports.hasNonNullishProperty = exports.generateForwardMessageContent = exports.prepareDisappearingMessageSettingContent = exports.prepareWAMessageMedia = exports.generateLinkPreviewIfRequired = exports.extractUrlFromText = void 0;
|
|
7
37
|
exports.getAggregateVotesInPollMessage = getAggregateVotesInPollMessage;
|
|
38
|
+
exports.getAggregateResponsesInEventMessage = getAggregateResponsesInEventMessage;
|
|
8
39
|
const boom_1 = require("@hapi/boom");
|
|
9
|
-
const axios_1 = __importDefault(require("axios"));
|
|
10
40
|
const crypto_1 = require("crypto");
|
|
11
41
|
const fs_1 = require("fs");
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
42
|
+
const index_js_1 = require("../../WAProto/index.js");
|
|
43
|
+
const index_js_2 = require("../Defaults/index.js");
|
|
44
|
+
const index_js_3 = require("../Types/index.js");
|
|
45
|
+
const index_js_4 = require("../WABinary/index.js");
|
|
46
|
+
const crypto_js_1 = require("./crypto.js");
|
|
47
|
+
const generics_js_1 = require("./generics.js");
|
|
48
|
+
const messages_media_js_1 = require("./messages-media.js");
|
|
49
|
+
const _require = require;
|
|
50
|
+
const reporting_utils_js_1 = require("./reporting-utils.js");
|
|
19
51
|
const MIMETYPE_MAP = {
|
|
20
52
|
image: 'image/jpeg',
|
|
21
53
|
video: 'video/mp4',
|
|
22
54
|
document: 'application/pdf',
|
|
23
55
|
audio: 'audio/ogg; codecs=opus',
|
|
24
56
|
sticker: 'image/webp',
|
|
25
|
-
'product-catalog-image': 'image/jpeg'
|
|
57
|
+
'product-catalog-image': 'image/jpeg'
|
|
58
|
+
};
|
|
59
|
+
/** Map ekstensi audio ke mimetype */
|
|
60
|
+
const AUDIO_MIMETYPE_MAP = {
|
|
61
|
+
ogg: 'audio/ogg; codecs=opus',
|
|
62
|
+
oga: 'audio/ogg; codecs=opus',
|
|
63
|
+
opus: 'audio/ogg; codecs=opus',
|
|
64
|
+
mp3: 'audio/mpeg',
|
|
65
|
+
mpeg: 'audio/mpeg',
|
|
66
|
+
mp4: 'audio/mp4',
|
|
67
|
+
m4a: 'audio/mp4',
|
|
68
|
+
aac: 'audio/aac',
|
|
69
|
+
wav: 'audio/wav',
|
|
70
|
+
wave: 'audio/wav',
|
|
71
|
+
flac: 'audio/flac',
|
|
72
|
+
webm: 'audio/webm',
|
|
73
|
+
amr: 'audio/amr',
|
|
74
|
+
'3gp': 'audio/3gpp',
|
|
75
|
+
'3gpp': 'audio/3gpp',
|
|
76
|
+
wma: 'audio/x-ms-wma',
|
|
77
|
+
caf: 'audio/x-caf',
|
|
78
|
+
aiff: 'audio/aiff',
|
|
79
|
+
aif: 'audio/aiff',
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Deteksi mimetype audio dari magic bytes buffer.
|
|
83
|
+
* Return null jika tidak dikenali.
|
|
84
|
+
*/
|
|
85
|
+
const detectAudioMimetypeFromBuffer = (buf) => {
|
|
86
|
+
if (!buf || buf.length < 12)
|
|
87
|
+
return null;
|
|
88
|
+
// OGG
|
|
89
|
+
if (buf[0] === 0x4F && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53)
|
|
90
|
+
return 'audio/ogg; codecs=opus';
|
|
91
|
+
// MP3 (ID3 tag atau sync bits)
|
|
92
|
+
if ((buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) ||
|
|
93
|
+
(buf[0] === 0xFF && (buf[1] & 0xE0) === 0xE0))
|
|
94
|
+
return 'audio/mpeg';
|
|
95
|
+
// MP4/M4A (ftyp box)
|
|
96
|
+
if (buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70)
|
|
97
|
+
return 'audio/mp4';
|
|
98
|
+
// RIFF/WAV
|
|
99
|
+
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
|
|
100
|
+
buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45)
|
|
101
|
+
return 'audio/wav';
|
|
102
|
+
// FLAC
|
|
103
|
+
if (buf[0] === 0x66 && buf[1] === 0x4C && buf[2] === 0x61 && buf[3] === 0x43)
|
|
104
|
+
return 'audio/flac';
|
|
105
|
+
// WEBM/MKV
|
|
106
|
+
if (buf[0] === 0x1A && buf[1] === 0x45 && buf[2] === 0xDF && buf[3] === 0xA3)
|
|
107
|
+
return 'audio/webm';
|
|
108
|
+
// AMR
|
|
109
|
+
if (buf[0] === 0x23 && buf[1] === 0x21 && buf[2] === 0x41 && buf[3] === 0x4D &&
|
|
110
|
+
buf[4] === 0x52)
|
|
111
|
+
return 'audio/amr';
|
|
112
|
+
return null;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Deteksi mimetype audio secara otomatis dari media input.
|
|
116
|
+
* Cek: 1) ekstensi URL/path, 2) magic bytes buffer, 3) fallback ke ogg/opus.
|
|
117
|
+
*/
|
|
118
|
+
const detectAudioMimetype = async (media) => {
|
|
119
|
+
// Cek ekstensi dari URL atau path string
|
|
120
|
+
if (typeof media === 'string' || (media && typeof media === 'object' && 'url' in media)) {
|
|
121
|
+
const urlStr = typeof media === 'string' ? media : media.url?.toString?.() ?? '';
|
|
122
|
+
// Ambil path tanpa query string, lalu cari semua ekstensi
|
|
123
|
+
const pathOnly = urlStr.split('?')[0];
|
|
124
|
+
// Cek ekstensi terakhir (.m4a, .mp3, dst)
|
|
125
|
+
const extMatch = pathOnly.match(/\.([a-zA-Z0-9]{2,5})(?:[^/]*)?$/);
|
|
126
|
+
if (extMatch) {
|
|
127
|
+
const ext = extMatch[1].toLowerCase();
|
|
128
|
+
if (AUDIO_MIMETYPE_MAP[ext])
|
|
129
|
+
return AUDIO_MIMETYPE_MAP[ext];
|
|
130
|
+
}
|
|
131
|
+
// Fallback: scan semua segmen path untuk ekstensi audio yang dikenal
|
|
132
|
+
// Contoh: ".plus.aac.ep.m4a" → cek tiap segment dari belakang
|
|
133
|
+
const segments = pathOnly.split('.');
|
|
134
|
+
for (let i = segments.length - 1; i >= 0; i--) {
|
|
135
|
+
const seg = segments[i].toLowerCase().split('/')[0].split('?')[0];
|
|
136
|
+
if (AUDIO_MIMETYPE_MAP[seg])
|
|
137
|
+
return AUDIO_MIMETYPE_MAP[seg];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// Cek magic bytes jika Buffer
|
|
141
|
+
if (Buffer.isBuffer(media)) {
|
|
142
|
+
const detected = detectAudioMimetypeFromBuffer(media);
|
|
143
|
+
if (detected)
|
|
144
|
+
return detected;
|
|
145
|
+
}
|
|
146
|
+
// Fallback: default ogg/opus
|
|
147
|
+
return MIMETYPE_MAP.audio;
|
|
26
148
|
};
|
|
27
149
|
const MessageTypeProto = {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
150
|
+
image: index_js_3.WAProto.Message.ImageMessage,
|
|
151
|
+
video: index_js_3.WAProto.Message.VideoMessage,
|
|
152
|
+
audio: index_js_3.WAProto.Message.AudioMessage,
|
|
153
|
+
sticker: index_js_3.WAProto.Message.StickerMessage,
|
|
154
|
+
document: index_js_3.WAProto.Message.DocumentMessage
|
|
33
155
|
};
|
|
34
|
-
const ButtonType = WAProto_1.proto.Message.ButtonsMessage.HeaderType;
|
|
35
156
|
/**
|
|
36
157
|
* Uses a regex to test whether the string contains a URL, and returns the URL if it does.
|
|
37
158
|
* @param text eg. hello https://google.com
|
|
38
159
|
* @returns the URL, eg. https://google.com
|
|
39
160
|
*/
|
|
40
|
-
const extractUrlFromText = (text) =>
|
|
161
|
+
const extractUrlFromText = (text) => text.match(index_js_2.URL_REGEX)?.[0];
|
|
41
162
|
exports.extractUrlFromText = extractUrlFromText;
|
|
42
163
|
const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
43
164
|
const url = (0, exports.extractUrlFromText)(text);
|
|
@@ -46,8 +167,9 @@ const generateLinkPreviewIfRequired = async (text, getUrlInfo, logger) => {
|
|
|
46
167
|
const urlInfo = await getUrlInfo(url);
|
|
47
168
|
return urlInfo;
|
|
48
169
|
}
|
|
49
|
-
catch (error) {
|
|
50
|
-
|
|
170
|
+
catch (error) {
|
|
171
|
+
// ignore if fails
|
|
172
|
+
logger?.warn({ trace: error.stack }, 'url generation failed');
|
|
51
173
|
}
|
|
52
174
|
}
|
|
53
175
|
};
|
|
@@ -69,7 +191,7 @@ const assertColor = async (color) => {
|
|
|
69
191
|
const prepareWAMessageMedia = async (message, options) => {
|
|
70
192
|
const logger = options.logger;
|
|
71
193
|
let mediaType;
|
|
72
|
-
for (const key of
|
|
194
|
+
for (const key of index_js_2.MEDIA_KEYS) {
|
|
73
195
|
if (key in message) {
|
|
74
196
|
mediaType = key;
|
|
75
197
|
}
|
|
@@ -84,113 +206,144 @@ const prepareWAMessageMedia = async (message, options) => {
|
|
|
84
206
|
delete uploadData[mediaType];
|
|
85
207
|
// check if cacheable + generate cache key
|
|
86
208
|
const cacheableKey = typeof uploadData.media === 'object' &&
|
|
87
|
-
|
|
209
|
+
'url' in uploadData.media &&
|
|
88
210
|
!!uploadData.media.url &&
|
|
89
|
-
!!options.mediaCache &&
|
|
90
|
-
|
|
91
|
-
mediaType + ':' + uploadData.media.url.toString());
|
|
211
|
+
!!options.mediaCache &&
|
|
212
|
+
mediaType + ':' + uploadData.media.url.toString();
|
|
92
213
|
if (mediaType === 'document' && !uploadData.fileName) {
|
|
93
214
|
uploadData.fileName = 'file';
|
|
94
215
|
}
|
|
95
216
|
if (!uploadData.mimetype) {
|
|
96
217
|
uploadData.mimetype = MIMETYPE_MAP[mediaType];
|
|
97
218
|
}
|
|
98
|
-
// check for cache hit
|
|
99
219
|
if (cacheableKey) {
|
|
100
|
-
const mediaBuff = options.mediaCache.get(cacheableKey);
|
|
220
|
+
const mediaBuff = await options.mediaCache.get(cacheableKey);
|
|
101
221
|
if (mediaBuff) {
|
|
102
|
-
logger
|
|
103
|
-
const obj =
|
|
222
|
+
logger?.debug({ cacheableKey }, 'got media cache hit');
|
|
223
|
+
const obj = index_js_1.proto.Message.decode(mediaBuff);
|
|
104
224
|
const key = `${mediaType}Message`;
|
|
105
225
|
Object.assign(obj[key], { ...uploadData, media: undefined });
|
|
106
226
|
return obj;
|
|
107
227
|
}
|
|
108
228
|
}
|
|
229
|
+
const isNewsletter = !!options.jid && (0, index_js_4.isJidNewsletter)(options.jid);
|
|
230
|
+
if (isNewsletter)
|
|
231
|
+
options.newsletter = true;
|
|
109
232
|
const requiresDurationComputation = mediaType === 'audio' && typeof uploadData.seconds === 'undefined';
|
|
110
|
-
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') &&
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
233
|
+
const requiresThumbnailComputation = (mediaType === 'image' || mediaType === 'video') && typeof uploadData['jpegThumbnail'] === 'undefined';
|
|
234
|
+
const requiresWaveformProcessing = mediaType === 'audio' && (uploadData.ptt === true || !!options.backgroundColor);
|
|
235
|
+
const requiresAudioBackground = options.backgroundColor && mediaType === 'audio';
|
|
236
|
+
const requiresOriginalForSomeProcessing = requiresDurationComputation || requiresThumbnailComputation || requiresWaveformProcessing;
|
|
237
|
+
let streamResult;
|
|
238
|
+
try {
|
|
239
|
+
streamResult = await (options.newsletter ? messages_media_js_1.prepareStream : messages_media_js_1.encryptedStream)(uploadData.media, options.mediaTypeOverride || mediaType, {
|
|
240
|
+
logger,
|
|
241
|
+
saveOriginalFileIfRequired: requiresOriginalForSomeProcessing,
|
|
242
|
+
opts: options.options,
|
|
243
|
+
isPtt: uploadData.ptt,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch (streamErr) {
|
|
247
|
+
throw streamErr;
|
|
248
|
+
}
|
|
249
|
+
const { mediaKey, encWriteStream, bodyPath, fileEncSha256, fileSha256, fileLength, didSaveToTmpPath } = streamResult;
|
|
250
|
+
const fileEncSha256B64 = (options.newsletter ? fileSha256 : fileEncSha256 ?? fileSha256).toString('base64');
|
|
251
|
+
const [{ mediaUrl, directPath, handle: uploadHandle }] = await Promise.all([
|
|
123
252
|
(async () => {
|
|
124
|
-
const result = await options.upload(encWriteStream, {
|
|
125
|
-
|
|
253
|
+
const result = await options.upload(encWriteStream, {
|
|
254
|
+
fileEncSha256B64,
|
|
255
|
+
mediaType,
|
|
256
|
+
timeoutMs: options.mediaUploadTimeoutMs,
|
|
257
|
+
newsletter: !!options.newsletter
|
|
258
|
+
});
|
|
126
259
|
return result;
|
|
127
260
|
})(),
|
|
128
261
|
(async () => {
|
|
129
262
|
try {
|
|
130
263
|
if (requiresThumbnailComputation) {
|
|
131
|
-
const { thumbnail, originalImageDimensions } = await (0,
|
|
264
|
+
const { thumbnail, originalImageDimensions } = await (0, messages_media_js_1.generateThumbnail)(bodyPath, mediaType, options);
|
|
132
265
|
uploadData.jpegThumbnail = thumbnail;
|
|
133
266
|
if (!uploadData.width && originalImageDimensions) {
|
|
134
267
|
uploadData.width = originalImageDimensions.width;
|
|
135
268
|
uploadData.height = originalImageDimensions.height;
|
|
136
|
-
logger
|
|
269
|
+
logger?.debug('set dimensions');
|
|
137
270
|
}
|
|
138
|
-
logger
|
|
271
|
+
logger?.debug('generated thumbnail');
|
|
139
272
|
}
|
|
140
273
|
if (requiresDurationComputation) {
|
|
141
|
-
|
|
142
|
-
|
|
274
|
+
try {
|
|
275
|
+
if (bodyPath) {
|
|
276
|
+
uploadData.seconds = await (0, messages_media_js_1.getAudioDuration)(bodyPath, uploadData.mimetype);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
catch (err) {
|
|
280
|
+
uploadData.seconds = 0;
|
|
281
|
+
}
|
|
282
|
+
// Pastikan seconds valid — NaN/undefined bikin WhatsApp tampilkan Loading...
|
|
283
|
+
if (typeof uploadData.seconds !== 'number' || isNaN(uploadData.seconds)) {
|
|
284
|
+
uploadData.seconds = 0;
|
|
285
|
+
}
|
|
286
|
+
logger?.debug('computed audio duration');
|
|
143
287
|
}
|
|
144
288
|
if (requiresWaveformProcessing) {
|
|
145
|
-
|
|
146
|
-
|
|
289
|
+
try {
|
|
290
|
+
uploadData.waveform = await (0, messages_media_js_1.getAudioWaveform)(bodyPath || encWriteStream, logger);
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
}
|
|
294
|
+
if (!uploadData.waveform) {
|
|
295
|
+
uploadData.waveform = new Uint8Array([0, 99, 0, 99, 0, 99, 0, 99, 88, 99, 0, 99, 0, 55, 0, 99, 0, 99, 0, 99, 0, 99, 0, 99, 88, 99, 0, 99, 0, 55, 0, 99]);
|
|
296
|
+
}
|
|
147
297
|
}
|
|
148
298
|
if (requiresAudioBackground) {
|
|
149
299
|
uploadData.backgroundArgb = await assertColor(options.backgroundColor);
|
|
150
|
-
logger
|
|
300
|
+
logger?.debug('computed backgroundColor audio status');
|
|
151
301
|
}
|
|
152
302
|
}
|
|
153
303
|
catch (error) {
|
|
154
|
-
logger
|
|
304
|
+
logger?.warn({ trace: error.stack }, 'failed to obtain extra info');
|
|
155
305
|
}
|
|
156
|
-
})()
|
|
157
|
-
])
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
// remove tmp files
|
|
163
|
-
if (didSaveToTmpPath && bodyPath) {
|
|
164
|
-
try {
|
|
165
|
-
await fs_1.promises.access(bodyPath);
|
|
166
|
-
await fs_1.promises.unlink(bodyPath);
|
|
167
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('removed tmp file');
|
|
306
|
+
})()
|
|
307
|
+
]).finally(async () => {
|
|
308
|
+
try {
|
|
309
|
+
if (!Buffer.isBuffer(encWriteStream)) {
|
|
310
|
+
encWriteStream.destroy?.();
|
|
168
311
|
}
|
|
169
|
-
|
|
170
|
-
|
|
312
|
+
if (didSaveToTmpPath && bodyPath) {
|
|
313
|
+
await fs_1.promises.unlink(bodyPath).catch(() => { });
|
|
171
314
|
}
|
|
172
315
|
}
|
|
316
|
+
catch (error) {
|
|
317
|
+
logger?.warn('failed to remove tmp file');
|
|
318
|
+
}
|
|
173
319
|
});
|
|
174
|
-
const obj =
|
|
320
|
+
const obj = index_js_3.WAProto.Message.fromObject({
|
|
175
321
|
[`${mediaType}Message`]: MessageTypeProto[mediaType].fromObject({
|
|
176
|
-
url:
|
|
322
|
+
url: uploadHandle ? undefined : mediaUrl,
|
|
177
323
|
directPath,
|
|
178
324
|
mediaKey: mediaKey,
|
|
179
325
|
fileEncSha256: fileEncSha256,
|
|
180
326
|
fileSha256,
|
|
181
327
|
fileLength,
|
|
182
|
-
mediaKeyTimestamp:
|
|
328
|
+
mediaKeyTimestamp: uploadHandle ? undefined : (0, generics_js_1.unixTimestampSeconds)(),
|
|
183
329
|
...uploadData,
|
|
184
|
-
media: undefined
|
|
330
|
+
media: undefined,
|
|
331
|
+
...(options?.contextInfo ? { contextInfo: options.contextInfo } : {})
|
|
185
332
|
})
|
|
186
333
|
});
|
|
187
334
|
if (uploadData.ptv) {
|
|
188
335
|
obj.ptvMessage = obj.videoMessage;
|
|
189
336
|
delete obj.videoMessage;
|
|
190
337
|
}
|
|
338
|
+
// Attach uploadHandle so sendMessage can use it as media_id
|
|
339
|
+
if (uploadHandle) {
|
|
340
|
+
obj._uploadHandle = uploadHandle;
|
|
341
|
+
}
|
|
342
|
+
if (mediaType === 'audio') {
|
|
343
|
+
}
|
|
191
344
|
if (cacheableKey) {
|
|
192
|
-
logger
|
|
193
|
-
options.mediaCache.set(cacheableKey,
|
|
345
|
+
logger?.debug({ cacheableKey }, 'set cache');
|
|
346
|
+
await options.mediaCache.set(cacheableKey, index_js_3.WAProto.Message.encode(obj).finish());
|
|
194
347
|
}
|
|
195
348
|
return obj;
|
|
196
349
|
};
|
|
@@ -201,13 +354,13 @@ const prepareDisappearingMessageSettingContent = (ephemeralExpiration) => {
|
|
|
201
354
|
ephemeralMessage: {
|
|
202
355
|
message: {
|
|
203
356
|
protocolMessage: {
|
|
204
|
-
type:
|
|
357
|
+
type: index_js_3.WAProto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING,
|
|
205
358
|
ephemeralExpiration
|
|
206
359
|
}
|
|
207
360
|
}
|
|
208
361
|
}
|
|
209
362
|
};
|
|
210
|
-
return
|
|
363
|
+
return index_js_3.WAProto.Message.fromObject(content);
|
|
211
364
|
};
|
|
212
365
|
exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSettingContent;
|
|
213
366
|
/**
|
|
@@ -216,36 +369,46 @@ exports.prepareDisappearingMessageSettingContent = prepareDisappearingMessageSet
|
|
|
216
369
|
* @param options.forceForward will show the message as forwarded even if it is from you
|
|
217
370
|
*/
|
|
218
371
|
const generateForwardMessageContent = (message, forceForward) => {
|
|
219
|
-
var _a;
|
|
220
372
|
let content = message.message;
|
|
221
373
|
if (!content) {
|
|
222
374
|
throw new boom_1.Boom('no content in message', { statusCode: 400 });
|
|
223
375
|
}
|
|
224
376
|
// hacky copy
|
|
225
377
|
content = (0, exports.normalizeMessageContent)(content);
|
|
226
|
-
content =
|
|
378
|
+
content = index_js_1.proto.Message.decode(index_js_1.proto.Message.encode(content).finish());
|
|
227
379
|
let key = Object.keys(content)[0];
|
|
228
|
-
let score =
|
|
380
|
+
let score = content?.[key]?.contextInfo?.forwardingScore || 0;
|
|
229
381
|
score += message.key.fromMe && !forceForward ? 0 : 1;
|
|
230
382
|
if (key === 'conversation') {
|
|
231
383
|
content.extendedTextMessage = { text: content[key] };
|
|
232
384
|
delete content.conversation;
|
|
233
385
|
key = 'extendedTextMessage';
|
|
234
386
|
}
|
|
387
|
+
const key_ = content?.[key];
|
|
235
388
|
if (score > 0) {
|
|
236
|
-
|
|
389
|
+
key_.contextInfo = { forwardingScore: score, isForwarded: true };
|
|
237
390
|
}
|
|
238
391
|
else {
|
|
239
|
-
|
|
392
|
+
key_.contextInfo = {};
|
|
240
393
|
}
|
|
241
394
|
return content;
|
|
242
395
|
};
|
|
243
396
|
exports.generateForwardMessageContent = generateForwardMessageContent;
|
|
397
|
+
const hasNonNullishProperty = (message, key) => {
|
|
398
|
+
return (typeof message === 'object' &&
|
|
399
|
+
message !== null &&
|
|
400
|
+
key in message &&
|
|
401
|
+
message[key] !== null &&
|
|
402
|
+
message[key] !== undefined);
|
|
403
|
+
};
|
|
404
|
+
exports.hasNonNullishProperty = hasNonNullishProperty;
|
|
405
|
+
function hasOptionalProperty(obj, key) {
|
|
406
|
+
return typeof obj === 'object' && obj !== null && key in obj && obj[key] !== null;
|
|
407
|
+
}
|
|
244
408
|
const generateWAMessageContent = async (message, options) => {
|
|
245
|
-
var _a, _b
|
|
246
|
-
var _p, _q;
|
|
409
|
+
var _a, _b;
|
|
247
410
|
let m = {};
|
|
248
|
-
if ('text'
|
|
411
|
+
if ((0, exports.hasNonNullishProperty)(message, 'text')) {
|
|
249
412
|
const extContent = { text: message.text };
|
|
250
413
|
let urlInfo = message.linkPreview;
|
|
251
414
|
if (typeof urlInfo === 'undefined') {
|
|
@@ -276,43 +439,57 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
276
439
|
}
|
|
277
440
|
m.extendedTextMessage = extContent;
|
|
278
441
|
}
|
|
279
|
-
else if ('contacts'
|
|
442
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'contacts')) {
|
|
280
443
|
const contactLen = message.contacts.contacts.length;
|
|
281
444
|
if (!contactLen) {
|
|
282
445
|
throw new boom_1.Boom('require atleast 1 contact', { statusCode: 400 });
|
|
283
446
|
}
|
|
284
447
|
if (contactLen === 1) {
|
|
285
|
-
m.contactMessage =
|
|
448
|
+
m.contactMessage = index_js_3.WAProto.Message.ContactMessage.create(message.contacts.contacts[0]);
|
|
286
449
|
}
|
|
287
450
|
else {
|
|
288
|
-
m.contactsArrayMessage =
|
|
451
|
+
m.contactsArrayMessage = index_js_3.WAProto.Message.ContactsArrayMessage.create(message.contacts);
|
|
289
452
|
}
|
|
290
453
|
}
|
|
291
|
-
else if ('location'
|
|
292
|
-
|
|
454
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'location')) {
|
|
455
|
+
if (message.live) {
|
|
456
|
+
m.liveLocationMessage = index_js_3.WAProto.Message.LiveLocationMessage.create(message.location);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
m.locationMessage = index_js_3.WAProto.Message.LocationMessage.create(message.location);
|
|
460
|
+
}
|
|
461
|
+
const locType = message.live ? 'liveLocationMessage' : 'locationMessage';
|
|
462
|
+
if (m[locType]) {
|
|
463
|
+
m[locType].contextInfo = {
|
|
464
|
+
...(message.contextInfo || {}),
|
|
465
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
466
|
+
};
|
|
467
|
+
}
|
|
293
468
|
}
|
|
294
|
-
else if ('react'
|
|
469
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'react')) {
|
|
295
470
|
if (!message.react.senderTimestampMs) {
|
|
296
471
|
message.react.senderTimestampMs = Date.now();
|
|
297
472
|
}
|
|
298
|
-
m.reactionMessage =
|
|
473
|
+
m.reactionMessage = index_js_3.WAProto.Message.ReactionMessage.create(message.react);
|
|
299
474
|
}
|
|
300
|
-
else if ('delete'
|
|
475
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'delete')) {
|
|
301
476
|
m.protocolMessage = {
|
|
302
477
|
key: message.delete,
|
|
303
|
-
type:
|
|
478
|
+
type: index_js_3.WAProto.Message.ProtocolMessage.Type.REVOKE
|
|
304
479
|
};
|
|
305
480
|
}
|
|
306
|
-
else if ('forward'
|
|
481
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'forward')) {
|
|
307
482
|
m = (0, exports.generateForwardMessageContent)(message.forward, message.force);
|
|
308
483
|
}
|
|
309
|
-
else if ('disappearingMessagesInChat'
|
|
310
|
-
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
311
|
-
|
|
312
|
-
|
|
484
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'disappearingMessagesInChat')) {
|
|
485
|
+
const exp = typeof message.disappearingMessagesInChat === 'boolean'
|
|
486
|
+
? message.disappearingMessagesInChat
|
|
487
|
+
? index_js_2.WA_DEFAULT_EPHEMERAL
|
|
488
|
+
: 0
|
|
489
|
+
: message.disappearingMessagesInChat;
|
|
313
490
|
m = (0, exports.prepareDisappearingMessageSettingContent)(exp);
|
|
314
491
|
}
|
|
315
|
-
else if ('groupInvite'
|
|
492
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'groupInvite')) {
|
|
316
493
|
m.groupInviteMessage = {};
|
|
317
494
|
m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode;
|
|
318
495
|
m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration;
|
|
@@ -324,110 +501,207 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
324
501
|
if (options.getProfilePicUrl) {
|
|
325
502
|
const pfpUrl = await options.getProfilePicUrl(message.groupInvite.jid, 'preview');
|
|
326
503
|
if (pfpUrl) {
|
|
327
|
-
const resp = await
|
|
328
|
-
if (resp.
|
|
329
|
-
|
|
504
|
+
const resp = await fetch(pfpUrl, { method: 'GET', dispatcher: options?.options?.dispatcher });
|
|
505
|
+
if (resp.ok) {
|
|
506
|
+
const buf = Buffer.from(await resp.arrayBuffer());
|
|
507
|
+
m.groupInviteMessage.jpegThumbnail = buf;
|
|
330
508
|
}
|
|
331
509
|
}
|
|
332
510
|
}
|
|
333
511
|
}
|
|
334
|
-
else if ('pin'
|
|
512
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'pin')) {
|
|
335
513
|
m.pinInChatMessage = {};
|
|
336
514
|
m.messageContextInfo = {};
|
|
337
|
-
m.pinInChatMessage.key = message.pin;
|
|
338
|
-
m.pinInChatMessage.type = message.type;
|
|
339
|
-
m.pinInChatMessage.senderTimestampMs = Date.now();
|
|
340
|
-
m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0;
|
|
515
|
+
m.pinInChatMessage.key = message.pin.key;
|
|
516
|
+
m.pinInChatMessage.type = message.pin?.type || 1;
|
|
517
|
+
m.pinInChatMessage.senderTimestampMs = message.pin?.time || Date.now();
|
|
518
|
+
m.messageContextInfo.messageAddOnDurationInSecs = message.pin.type === 1 ? message.pin.time || 86400 : 0;
|
|
519
|
+
m.messageContextInfo.messageAddOnExpiryType = index_js_1.proto.MessageContextInfo.MessageAddonExpiryType.STATIC;
|
|
341
520
|
}
|
|
342
|
-
else if ('keep'
|
|
521
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'keep')) {
|
|
343
522
|
m.keepInChatMessage = {};
|
|
344
|
-
m.keepInChatMessage.key = message.keep;
|
|
345
|
-
m.keepInChatMessage.keepType = message.type;
|
|
346
|
-
m.keepInChatMessage.timestampMs = Date.now();
|
|
347
|
-
}
|
|
348
|
-
else if ('call'
|
|
349
|
-
m = {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
523
|
+
m.keepInChatMessage.key = message.keep.key;
|
|
524
|
+
m.keepInChatMessage.keepType = message.keep?.type || 1;
|
|
525
|
+
m.keepInChatMessage.timestampMs = message.keep?.time || Date.now();
|
|
526
|
+
}
|
|
527
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'call')) {
|
|
528
|
+
m.scheduledCallCreationMessage = {};
|
|
529
|
+
m.scheduledCallCreationMessage.scheduledTimestampMs = message.call?.time || Date.now();
|
|
530
|
+
m.scheduledCallCreationMessage.callType = message.call?.type || 1;
|
|
531
|
+
m.scheduledCallCreationMessage.title = message.call?.name || 'Call Creation';
|
|
532
|
+
m.scheduledCallCreationMessage.contextInfo = {
|
|
533
|
+
...(message.contextInfo || {}),
|
|
534
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
355
535
|
};
|
|
356
536
|
}
|
|
357
|
-
else if ('paymentInvite'
|
|
358
|
-
m.
|
|
359
|
-
|
|
360
|
-
|
|
537
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'paymentInvite')) {
|
|
538
|
+
m.messageContextInfo = {};
|
|
539
|
+
m.paymentInviteMessage = {};
|
|
540
|
+
m.paymentInviteMessage.expiryTimestamp = message.paymentInvite?.expiry || 0;
|
|
541
|
+
m.paymentInviteMessage.serviceType = message.paymentInvite?.type || 2;
|
|
542
|
+
m.paymentInviteMessage.contextInfo = {
|
|
543
|
+
...(message.contextInfo || {}),
|
|
544
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
361
545
|
};
|
|
362
546
|
}
|
|
363
|
-
else if ('buttonReply'
|
|
547
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'buttonReply')) {
|
|
364
548
|
switch (message.type) {
|
|
549
|
+
case 'list':
|
|
550
|
+
m.listResponseMessage = {
|
|
551
|
+
title: message.buttonReply.title,
|
|
552
|
+
description: message.buttonReply.description,
|
|
553
|
+
singleSelectReply: {
|
|
554
|
+
selectedRowId: message.buttonReply.rowId
|
|
555
|
+
},
|
|
556
|
+
listType: index_js_1.proto.Message.ListResponseMessage.ListType.SINGLE_SELECT
|
|
557
|
+
};
|
|
558
|
+
break;
|
|
365
559
|
case 'template':
|
|
366
560
|
m.templateButtonReplyMessage = {
|
|
367
561
|
selectedDisplayText: message.buttonReply.displayText,
|
|
368
562
|
selectedId: message.buttonReply.id,
|
|
369
|
-
selectedIndex: message.buttonReply.index
|
|
563
|
+
selectedIndex: message.buttonReply.index
|
|
370
564
|
};
|
|
371
565
|
break;
|
|
372
566
|
case 'plain':
|
|
373
567
|
m.buttonsResponseMessage = {
|
|
374
568
|
selectedButtonId: message.buttonReply.id,
|
|
375
569
|
selectedDisplayText: message.buttonReply.displayText,
|
|
376
|
-
type:
|
|
570
|
+
type: index_js_1.proto.Message.ButtonsResponseMessage.Type.DISPLAY_TEXT
|
|
571
|
+
};
|
|
572
|
+
break;
|
|
573
|
+
case 'interactive':
|
|
574
|
+
m.interactiveResponseMessage = {
|
|
575
|
+
body: {
|
|
576
|
+
text: message.buttonReply.displayText,
|
|
577
|
+
format: index_js_1.proto.Message.InteractiveResponseMessage.Body.Format.EXTENSIONS_1
|
|
578
|
+
},
|
|
579
|
+
nativeFlowResponseMessage: {
|
|
580
|
+
name: message.buttonReply.nativeFlows.name,
|
|
581
|
+
paramsJson: message.buttonReply.nativeFlows.paramsJson,
|
|
582
|
+
version: message.buttonReply.nativeFlows.version
|
|
583
|
+
}
|
|
377
584
|
};
|
|
378
585
|
break;
|
|
379
586
|
}
|
|
380
587
|
}
|
|
381
|
-
else if (
|
|
588
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'album')) {
|
|
589
|
+
const imageMessages = message.album.filter(item => 'image' in item);
|
|
590
|
+
const videoMessages = message.album.filter(item => 'video' in item);
|
|
591
|
+
m.albumMessage = index_js_3.WAProto.Message.AlbumMessage.fromObject({
|
|
592
|
+
expectedImageCount: imageMessages.length,
|
|
593
|
+
expectedVideoCount: videoMessages.length
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'order')) {
|
|
597
|
+
m.orderMessage = index_js_3.WAProto.Message.OrderMessage.fromObject(message.order);
|
|
598
|
+
m.orderMessage.contextInfo = {
|
|
599
|
+
...(message.contextInfo || {}),
|
|
600
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'payment')) {
|
|
604
|
+
const requestPaymentMessage = {
|
|
605
|
+
amount: {
|
|
606
|
+
currencyCode: message.payment?.currency || 'IDR',
|
|
607
|
+
offset: message.payment?.offset || 0,
|
|
608
|
+
value: message.payment?.amount || 999999999
|
|
609
|
+
},
|
|
610
|
+
expiryTimestamp: message.payment?.expiry || 0,
|
|
611
|
+
amount1000: (message.payment?.amount || 999999999) * 1000,
|
|
612
|
+
currencyCodeIso4217: message.payment?.currency || 'IDR',
|
|
613
|
+
requestFrom: message.payment?.from || '0@s.whatsapp.net',
|
|
614
|
+
noteMessage: {
|
|
615
|
+
extendedTextMessage: {
|
|
616
|
+
text: message.payment?.note || 'Notes'
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
background: {
|
|
620
|
+
placeholderArgb: message.payment?.image?.placeholderArgb || 4278190080,
|
|
621
|
+
textArgb: message.payment?.image?.textArgb || 4294967295,
|
|
622
|
+
subtextArgb: message.payment?.image?.subtextArgb || 4294967295,
|
|
623
|
+
type: 1
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
requestPaymentMessage.noteMessage.extendedTextMessage.contextInfo = {
|
|
627
|
+
...(message.contextInfo || {}),
|
|
628
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
629
|
+
};
|
|
630
|
+
m.requestPaymentMessage = requestPaymentMessage;
|
|
631
|
+
}
|
|
632
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'pollResult')) {
|
|
633
|
+
if (!Array.isArray(message.pollResult.values)) {
|
|
634
|
+
throw new boom_1.Boom('Invalid pollResult values', { statusCode: 400 });
|
|
635
|
+
}
|
|
636
|
+
const pollResultSnapshotMessage = {
|
|
637
|
+
name: message.pollResult.name,
|
|
638
|
+
pollVotes: message.pollResult.values.map(([optionName, optionVoteCount]) => ({
|
|
639
|
+
optionName,
|
|
640
|
+
optionVoteCount
|
|
641
|
+
}))
|
|
642
|
+
};
|
|
643
|
+
pollResultSnapshotMessage.contextInfo = {
|
|
644
|
+
...(message.contextInfo || {}),
|
|
645
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
646
|
+
};
|
|
647
|
+
m.pollResultSnapshotMessage = pollResultSnapshotMessage;
|
|
648
|
+
}
|
|
649
|
+
else if (hasOptionalProperty(message, 'ptv') && message.ptv) {
|
|
382
650
|
const { videoMessage } = await (0, exports.prepareWAMessageMedia)({ video: message.video }, options);
|
|
383
651
|
m.ptvMessage = videoMessage;
|
|
384
652
|
}
|
|
385
|
-
else if ('product'
|
|
653
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'product')) {
|
|
386
654
|
const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: message.product.productImage }, options);
|
|
387
|
-
m.productMessage =
|
|
655
|
+
m.productMessage = index_js_3.WAProto.Message.ProductMessage.create({
|
|
388
656
|
...message,
|
|
389
657
|
product: {
|
|
390
658
|
...message.product,
|
|
391
|
-
productImage: imageMessage
|
|
659
|
+
productImage: imageMessage
|
|
392
660
|
}
|
|
393
661
|
});
|
|
394
662
|
}
|
|
395
|
-
else if ('
|
|
396
|
-
m.orderMessage = Types_1.WAProto.Message.OrderMessage.fromObject({
|
|
397
|
-
orderId: message.order.id,
|
|
398
|
-
thumbnail: message.order.thumbnail,
|
|
399
|
-
itemCount: message.order.itemCount,
|
|
400
|
-
status: message.order.status,
|
|
401
|
-
surface: message.order.surface,
|
|
402
|
-
orderTitle: message.order.title,
|
|
403
|
-
message: message.order.text,
|
|
404
|
-
sellerJid: message.order.seller,
|
|
405
|
-
token: message.order.token,
|
|
406
|
-
totalAmount1000: message.order.amount,
|
|
407
|
-
totalCurrencyCode: message.order.currency
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
else if ('listReply' in message) {
|
|
663
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'listReply')) {
|
|
411
664
|
m.listResponseMessage = { ...message.listReply };
|
|
412
665
|
}
|
|
413
|
-
else if ('
|
|
414
|
-
|
|
415
|
-
|
|
666
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'event')) {
|
|
667
|
+
m.eventMessage = {};
|
|
668
|
+
const startTime = Math.floor(message.event.startDate.getTime() / 1000);
|
|
669
|
+
if (message.event.call && options.getCallLink) {
|
|
670
|
+
const token = await options.getCallLink(message.event.call, { startTime });
|
|
671
|
+
m.eventMessage.joinLink = (message.event.call === 'audio' ? index_js_2.CALL_AUDIO_PREFIX : index_js_2.CALL_VIDEO_PREFIX) + token;
|
|
672
|
+
}
|
|
673
|
+
m.messageContextInfo = {
|
|
674
|
+
// encKey
|
|
675
|
+
messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32)
|
|
676
|
+
};
|
|
677
|
+
m.eventMessage.name = message.event.name;
|
|
678
|
+
m.eventMessage.description = message.event.description;
|
|
679
|
+
m.eventMessage.startTime = startTime;
|
|
680
|
+
m.eventMessage.endTime = message.event.endDate ? message.event.endDate.getTime() / 1000 : undefined;
|
|
681
|
+
m.eventMessage.isCanceled = message.event.isCancelled ?? false;
|
|
682
|
+
m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed;
|
|
683
|
+
m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false;
|
|
684
|
+
m.eventMessage.location = message.event.location;
|
|
685
|
+
}
|
|
686
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'poll')) {
|
|
687
|
+
(_a = message.poll).selectableCount || (_a.selectableCount = 0);
|
|
688
|
+
(_b = message.poll).toAnnouncementGroup || (_b.toAnnouncementGroup = false);
|
|
416
689
|
if (!Array.isArray(message.poll.values)) {
|
|
417
690
|
throw new boom_1.Boom('Invalid poll values', { statusCode: 400 });
|
|
418
691
|
}
|
|
419
|
-
if (message.poll.selectableCount < 0
|
|
420
|
-
|
|
421
|
-
|
|
692
|
+
if (message.poll.selectableCount < 0 || message.poll.selectableCount > message.poll.values.length) {
|
|
693
|
+
throw new boom_1.Boom(`poll.selectableCount in poll should be >= 0 and <= ${message.poll.values.length}`, {
|
|
694
|
+
statusCode: 400
|
|
695
|
+
});
|
|
422
696
|
}
|
|
423
697
|
m.messageContextInfo = {
|
|
424
698
|
// encKey
|
|
425
|
-
messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32)
|
|
699
|
+
messageSecret: message.poll.messageSecret || (0, crypto_1.randomBytes)(32)
|
|
426
700
|
};
|
|
427
701
|
const pollCreationMessage = {
|
|
428
702
|
name: message.poll.name,
|
|
429
703
|
selectableOptionsCount: message.poll.selectableCount,
|
|
430
|
-
options: message.poll.values.map(optionName => ({ optionName }))
|
|
704
|
+
options: message.poll.values.map(optionName => ({ optionName }))
|
|
431
705
|
};
|
|
432
706
|
if (message.poll.toAnnouncementGroup) {
|
|
433
707
|
// poll v2 is for community announcement groups (single select and multiple)
|
|
@@ -435,7 +709,7 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
435
709
|
}
|
|
436
710
|
else {
|
|
437
711
|
if (message.poll.selectableCount === 1) {
|
|
438
|
-
//
|
|
712
|
+
//poll v3 is for single select polls
|
|
439
713
|
m.pollCreationMessageV3 = pollCreationMessage;
|
|
440
714
|
}
|
|
441
715
|
else {
|
|
@@ -444,55 +718,37 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
444
718
|
}
|
|
445
719
|
}
|
|
446
720
|
}
|
|
447
|
-
else if (
|
|
448
|
-
const { zip } =
|
|
721
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'stickerPack')) {
|
|
722
|
+
const { zip } = _require('fflate');
|
|
449
723
|
const { stickers, cover, name, publisher, packId, description } = message.stickerPack;
|
|
450
|
-
|
|
451
|
-
if (!Array.isArray(stickers)) {
|
|
452
|
-
throw new boom_1.Boom('stickerPack.stickers must be an array', { statusCode: 400 });
|
|
453
|
-
}
|
|
724
|
+
// ── Validasi jumlah sticker ───────────────────────────────────────────
|
|
454
725
|
if (stickers.length > 60) {
|
|
455
726
|
throw new boom_1.Boom('Sticker pack exceeds the maximum limit of 60 stickers', { statusCode: 400 });
|
|
456
727
|
}
|
|
457
728
|
if (stickers.length === 0) {
|
|
458
729
|
throw new boom_1.Boom('Sticker pack must contain at least one sticker', { statusCode: 400 });
|
|
459
730
|
}
|
|
460
|
-
const stickerPackId = packId || (0,
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
catch (_jimpError) { }
|
|
471
|
-
if (!sharpLib && !jimpLib) {
|
|
472
|
-
throw new boom_1.Boom('No image processing library available (install sharp or jimp)', { statusCode: 400 });
|
|
473
|
-
}
|
|
474
|
-
const isWebPBuffer = (buf) => (buf.length >= 12
|
|
475
|
-
&& buf[0] === 0x52
|
|
476
|
-
&& buf[1] === 0x49
|
|
477
|
-
&& buf[2] === 0x46
|
|
478
|
-
&& buf[3] === 0x46
|
|
479
|
-
&& buf[8] === 0x57
|
|
480
|
-
&& buf[9] === 0x45
|
|
481
|
-
&& buf[10] === 0x42
|
|
482
|
-
&& buf[11] === 0x50);
|
|
731
|
+
const stickerPackId = packId || (0, generics_js_1.generateMessageIDV2)();
|
|
732
|
+
const [_sharp, _jimp] = await Promise.all([Promise.resolve().then(() => __importStar(require('sharp'))).catch(() => null), Promise.resolve().then(() => __importStar(require('jimp'))).catch(() => null)]);
|
|
733
|
+
const lib = _sharp ? { sharp: _sharp } : _jimp ? { jimp: _jimp } : null;
|
|
734
|
+
if (!lib)
|
|
735
|
+
throw new boom_1.Boom('No image processing library available (install sharp or jimp)');
|
|
736
|
+
// ── Helper: deteksi WebP dari magic bytes ─────────────────────────────
|
|
737
|
+
const isWebPBuffer = (buf) => (buf.length >= 12 &&
|
|
738
|
+
buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
|
|
739
|
+
buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50);
|
|
740
|
+
// ── Helper: deteksi animasi WebP (VP8X/ANIM/ANMF chunks) ─────────────
|
|
483
741
|
const isAnimatedWebP = (buf) => {
|
|
484
|
-
if (!isWebPBuffer(buf))
|
|
742
|
+
if (!isWebPBuffer(buf))
|
|
485
743
|
return false;
|
|
486
|
-
}
|
|
487
744
|
let offset = 12;
|
|
488
745
|
while (offset < buf.length - 8) {
|
|
489
746
|
const fourCC = buf.toString('ascii', offset, offset + 4);
|
|
490
747
|
const chunkSize = buf.readUInt32LE(offset + 4);
|
|
491
748
|
if (fourCC === 'VP8X') {
|
|
492
749
|
const flagsOffset = offset + 8;
|
|
493
|
-
if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02))
|
|
750
|
+
if (flagsOffset < buf.length && (buf[flagsOffset] & 0x02))
|
|
494
751
|
return true;
|
|
495
|
-
}
|
|
496
752
|
}
|
|
497
753
|
else if (fourCC === 'ANIM' || fourCC === 'ANMF') {
|
|
498
754
|
return true;
|
|
@@ -501,247 +757,81 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
501
757
|
}
|
|
502
758
|
return false;
|
|
503
759
|
};
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
reject(err);
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
resolve(result);
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
});
|
|
518
|
-
};
|
|
519
|
-
const { spawn } = require('child_process');
|
|
520
|
-
const { promises: fsPromises } = require('fs');
|
|
521
|
-
const { join } = require('path');
|
|
522
|
-
const { tmpdir } = require('os');
|
|
523
|
-
const isPngBuffer = (buf) => (buf.length >= 8
|
|
524
|
-
&& buf[0] === 0x89
|
|
525
|
-
&& buf[1] === 0x50
|
|
526
|
-
&& buf[2] === 0x4e
|
|
527
|
-
&& buf[3] === 0x47);
|
|
528
|
-
const isJpegBuffer = (buf) => (buf.length >= 3
|
|
529
|
-
&& buf[0] === 0xff
|
|
530
|
-
&& buf[1] === 0xd8
|
|
531
|
-
&& buf[2] === 0xff);
|
|
532
|
-
const isGifBuffer = (buf) => (buf.length >= 4 && buf.slice(0, 4).toString() === 'GIF8');
|
|
533
|
-
const isWebmBuffer = (buf) => (buf.length >= 4
|
|
534
|
-
&& buf[0] === 0x1a
|
|
535
|
-
&& buf[1] === 0x45
|
|
536
|
-
&& buf[2] === 0xdf
|
|
537
|
-
&& buf[3] === 0xa3);
|
|
538
|
-
const isMp4Buffer = (buf) => (buf.length >= 8
|
|
539
|
-
&& buf[4] === 0x66
|
|
540
|
-
&& buf[5] === 0x74
|
|
541
|
-
&& buf[6] === 0x79
|
|
542
|
-
&& buf[7] === 0x70);
|
|
543
|
-
const looksLikeGzip = (buf) => (buf.length >= 2 && buf[0] === 0x1f && buf[1] === 0x8b);
|
|
544
|
-
const inferSourceKind = (buffer, source, stickerItem) => {
|
|
545
|
-
var _c, _d, _e, _f;
|
|
546
|
-
if (isAnimatedWebP(buffer)) {
|
|
547
|
-
return 'animated-webp';
|
|
548
|
-
}
|
|
549
|
-
if (isWebPBuffer(buffer)) {
|
|
550
|
-
return 'webp';
|
|
551
|
-
}
|
|
552
|
-
if (isPngBuffer(buffer)) {
|
|
553
|
-
return 'png';
|
|
554
|
-
}
|
|
555
|
-
if (isJpegBuffer(buffer)) {
|
|
556
|
-
return 'jpg';
|
|
557
|
-
}
|
|
558
|
-
if (isGifBuffer(buffer)) {
|
|
559
|
-
return 'gif';
|
|
560
|
-
}
|
|
561
|
-
if (isWebmBuffer(buffer)) {
|
|
562
|
-
return 'webm';
|
|
563
|
-
}
|
|
564
|
-
if (isMp4Buffer(buffer)) {
|
|
565
|
-
return 'mp4';
|
|
566
|
-
}
|
|
567
|
-
if (looksLikeGzip(buffer)) {
|
|
568
|
-
return 'tgs';
|
|
569
|
-
}
|
|
570
|
-
const hint = String(((_c = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.format) !== null && _c !== void 0 ? _c : ((_d = stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.mimetype) !== null && _d !== void 0 ? _d : ((_f = (_e = source) === null || _e === void 0 ? void 0 : _e.url) === null || _f === void 0 ? void 0 : _f.toString()))) || '').toLowerCase();
|
|
571
|
-
if (hint.includes('webm')) {
|
|
572
|
-
return 'webm';
|
|
573
|
-
}
|
|
574
|
-
if (hint.includes('mp4') || hint.includes('mov') || hint.includes('mkv') || hint.includes('avi')) {
|
|
575
|
-
return 'mp4';
|
|
576
|
-
}
|
|
577
|
-
if (hint.includes('gif')) {
|
|
578
|
-
return 'gif';
|
|
579
|
-
}
|
|
580
|
-
if (hint.includes('png')) {
|
|
581
|
-
return 'png';
|
|
582
|
-
}
|
|
583
|
-
if (hint.includes('jpg') || hint.includes('jpeg')) {
|
|
584
|
-
return 'jpg';
|
|
585
|
-
}
|
|
586
|
-
if (hint.includes('tgs') || hint.includes('lottie') || hint.includes('json')) {
|
|
587
|
-
return 'tgs';
|
|
588
|
-
}
|
|
589
|
-
return 'unknown';
|
|
590
|
-
};
|
|
591
|
-
const convertStaticToWebp = async (buffer, label) => {
|
|
760
|
+
// ── Step 1: proses & zip semua sticker ────────────────────────────────
|
|
761
|
+
const stickerData = {};
|
|
762
|
+
const stickerPromises = stickers.map(async (s, i) => {
|
|
763
|
+
const { stream } = await (0, messages_media_js_1.getStream)(s.data || s.sticker);
|
|
764
|
+
const buffer = await (0, messages_media_js_1.toBuffer)(stream);
|
|
765
|
+
let webpBuffer;
|
|
766
|
+
let isAnimated = false;
|
|
592
767
|
if (isWebPBuffer(buffer)) {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
if (sharpLib) {
|
|
596
|
-
return await sharpLib(buffer)
|
|
597
|
-
.resize(512, 512, { fit: 'contain', background: { r: 0, g: 0, b: 0, alpha: 0 } })
|
|
598
|
-
.webp({ quality: 80, lossless: false })
|
|
599
|
-
.toBuffer();
|
|
600
|
-
}
|
|
601
|
-
if (jimpLib) {
|
|
602
|
-
const JimpCtor = jimpLib.Jimp || jimpLib.default || jimpLib;
|
|
603
|
-
const image = await JimpCtor.read(buffer);
|
|
604
|
-
image.contain(512, 512);
|
|
605
|
-
return await getJimpBuffer(image, 'image/webp');
|
|
606
|
-
}
|
|
607
|
-
throw new boom_1.Boom(`No image processing library available for converting ${label} to WebP`, { statusCode: 400 });
|
|
608
|
-
};
|
|
609
|
-
const runFfmpegToWebp = async (inputBuffer, inputExt, animated, label) => {
|
|
610
|
-
const baseName = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
611
|
-
const inputPath = join(tmpdir(), `sticker-pack-${baseName}.${inputExt || 'bin'}`);
|
|
612
|
-
const outputPath = join(tmpdir(), `sticker-pack-${baseName}.webp`);
|
|
613
|
-
await fsPromises.writeFile(inputPath, inputBuffer);
|
|
614
|
-
const args = animated
|
|
615
|
-
? [
|
|
616
|
-
'-y',
|
|
617
|
-
'-i', inputPath,
|
|
618
|
-
'-vf', 'fps=12,scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
|
|
619
|
-
'-loop', '0',
|
|
620
|
-
'-an',
|
|
621
|
-
'-vsync', '0',
|
|
622
|
-
'-s', '512:512',
|
|
623
|
-
'-vcodec', 'libwebp_anim',
|
|
624
|
-
'-lossless', '0',
|
|
625
|
-
'-compression_level', '6',
|
|
626
|
-
'-q:v', '55',
|
|
627
|
-
outputPath,
|
|
628
|
-
]
|
|
629
|
-
: [
|
|
630
|
-
'-y',
|
|
631
|
-
'-i', inputPath,
|
|
632
|
-
'-vf', 'scale=512:512:force_original_aspect_ratio=decrease:flags=lanczos,pad=512:512:-1:-1:color=0x00000000',
|
|
633
|
-
'-frames:v', '1',
|
|
634
|
-
'-vcodec', 'libwebp',
|
|
635
|
-
'-lossless', '0',
|
|
636
|
-
'-compression_level', '6',
|
|
637
|
-
'-q:v', '70',
|
|
638
|
-
outputPath,
|
|
639
|
-
];
|
|
640
|
-
await new Promise((resolve, reject) => {
|
|
641
|
-
const ff = spawn('ffmpeg', args);
|
|
642
|
-
let stderr = '';
|
|
643
|
-
ff.stderr.on('data', (chunk) => {
|
|
644
|
-
stderr += chunk.toString();
|
|
645
|
-
});
|
|
646
|
-
ff.on('error', (err) => reject(new boom_1.Boom(`ffmpeg not available for ${label}: ${err.message}`, { statusCode: 400 })));
|
|
647
|
-
ff.on('close', (code) => {
|
|
648
|
-
if (code === 0) {
|
|
649
|
-
resolve(undefined);
|
|
650
|
-
}
|
|
651
|
-
else {
|
|
652
|
-
reject(new boom_1.Boom(`ffmpeg failed while converting ${label} (code ${code})\n${stderr}`, { statusCode: 400 }));
|
|
653
|
-
}
|
|
654
|
-
});
|
|
655
|
-
});
|
|
656
|
-
try {
|
|
657
|
-
return await fsPromises.readFile(outputPath);
|
|
768
|
+
webpBuffer = buffer;
|
|
769
|
+
isAnimated = isAnimatedWebP(buffer);
|
|
658
770
|
}
|
|
659
|
-
|
|
660
|
-
await
|
|
661
|
-
fsPromises.unlink(inputPath),
|
|
662
|
-
fsPromises.unlink(outputPath)
|
|
663
|
-
]);
|
|
771
|
+
else if ('sharp' in lib && lib.sharp) {
|
|
772
|
+
webpBuffer = await lib.sharp.default(buffer).webp().toBuffer();
|
|
664
773
|
}
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
if (sourceKind === 'animated-webp' || sourceKind === 'webp') {
|
|
669
|
-
return buffer;
|
|
670
|
-
}
|
|
671
|
-
if (sourceKind === 'png' || sourceKind === 'jpg') {
|
|
672
|
-
return await convertStaticToWebp(buffer, label);
|
|
673
|
-
}
|
|
674
|
-
if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4') {
|
|
675
|
-
return await runFfmpegToWebp(buffer, sourceKind, true, label);
|
|
676
|
-
}
|
|
677
|
-
if (sourceKind === 'tgs') {
|
|
678
|
-
throw new boom_1.Boom(`TGS/Lottie source for ${label} is not supported in this runtime`, { statusCode: 400 });
|
|
679
|
-
}
|
|
680
|
-
return await convertStaticToWebp(buffer, label);
|
|
681
|
-
};
|
|
682
|
-
const toStaticWebpCoverBuffer = async (buffer, label, source, stickerItem) => {
|
|
683
|
-
const sourceKind = inferSourceKind(buffer, source, stickerItem);
|
|
684
|
-
if (sourceKind === 'gif' || sourceKind === 'webm' || sourceKind === 'mp4' || sourceKind === 'animated-webp') {
|
|
685
|
-
return await runFfmpegToWebp(buffer, sourceKind === 'animated-webp' ? 'webp' : sourceKind, false, label);
|
|
686
|
-
}
|
|
687
|
-
return await convertStaticToWebp(buffer, label);
|
|
688
|
-
};
|
|
689
|
-
const stickerData = {};
|
|
690
|
-
const stickerMetadata = await Promise.all(stickers.map(async (stickerItem, index) => {
|
|
691
|
-
const mediaSource = (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.data) || (stickerItem === null || stickerItem === void 0 ? void 0 : stickerItem.sticker);
|
|
692
|
-
if (!mediaSource) {
|
|
693
|
-
throw new boom_1.Boom(`Sticker at index ${index} is missing data/sticker`, { statusCode: 400 });
|
|
774
|
+
else {
|
|
775
|
+
throw new boom_1.Boom('No image processing library (sharp) available for converting sticker to WebP. ' +
|
|
776
|
+
'Either install sharp or provide stickers in WebP format.');
|
|
694
777
|
}
|
|
695
|
-
const { stream } = await (0, messages_media_1.getStream)(mediaSource);
|
|
696
|
-
const buffer = await (0, messages_media_1.toBuffer)(stream);
|
|
697
|
-
const webpBuffer = await toWebpBuffer(buffer, `sticker at index ${index}`, mediaSource, stickerItem);
|
|
698
778
|
if (webpBuffer.length > 1024 * 1024) {
|
|
699
|
-
throw new boom_1.Boom(`Sticker at index ${
|
|
779
|
+
throw new boom_1.Boom(`Sticker at index ${i} exceeds the 1MB size limit`, { statusCode: 400 });
|
|
700
780
|
}
|
|
701
|
-
const hash = (0,
|
|
781
|
+
const hash = (0, crypto_js_1.sha256)(webpBuffer).toString('base64').replace(/\//g, '-');
|
|
702
782
|
const fileName = `${hash}.webp`;
|
|
703
783
|
stickerData[fileName] = [new Uint8Array(webpBuffer), { level: 0 }];
|
|
704
784
|
return {
|
|
705
785
|
fileName,
|
|
706
786
|
mimetype: 'image/webp',
|
|
707
|
-
isAnimated
|
|
708
|
-
emojis:
|
|
709
|
-
accessibilityLabel:
|
|
787
|
+
isAnimated,
|
|
788
|
+
emojis: s.emojis || [],
|
|
789
|
+
accessibilityLabel: s.accessibilityLabel || ''
|
|
710
790
|
};
|
|
711
|
-
})
|
|
791
|
+
});
|
|
792
|
+
const stickerMetadata = await Promise.all(stickerPromises);
|
|
793
|
+
// ── Step 2: proses cover & masukkan ke dalam ZIP ──────────────────────
|
|
712
794
|
const trayIconFileName = `${stickerPackId}.webp`;
|
|
713
|
-
|
|
714
|
-
|
|
795
|
+
const coverBuffer = await (0, messages_media_js_1.toBuffer)((await (0, messages_media_js_1.getStream)(cover)).stream);
|
|
796
|
+
let coverWebpBuffer;
|
|
797
|
+
if (isWebPBuffer(coverBuffer)) {
|
|
798
|
+
coverWebpBuffer = coverBuffer;
|
|
799
|
+
}
|
|
800
|
+
else if ('sharp' in lib && lib.sharp) {
|
|
801
|
+
coverWebpBuffer = await lib.sharp.default(coverBuffer).webp().toBuffer();
|
|
802
|
+
}
|
|
803
|
+
else {
|
|
804
|
+
throw new boom_1.Boom('No image processing library (sharp) available for converting cover to WebP. ' +
|
|
805
|
+
'Either install sharp or provide cover in WebP format.');
|
|
715
806
|
}
|
|
716
|
-
const { stream: coverStream } = await (0, messages_media_1.getStream)(coverSource);
|
|
717
|
-
const coverBuffer = await (0, messages_media_1.toBuffer)(coverStream);
|
|
718
|
-
const coverWebpBuffer = await toStaticWebpCoverBuffer(coverBuffer, 'cover', coverSource, stickers[0]);
|
|
719
807
|
stickerData[trayIconFileName] = [new Uint8Array(coverWebpBuffer), { level: 0 }];
|
|
808
|
+
// ── Step 3: buat ZIP buffer ───────────────────────────────────────────
|
|
720
809
|
const zipBuffer = await new Promise((resolve, reject) => {
|
|
721
810
|
zip(stickerData, (err, data) => {
|
|
722
|
-
if (err)
|
|
811
|
+
if (err)
|
|
723
812
|
reject(err);
|
|
724
|
-
|
|
725
|
-
else {
|
|
813
|
+
else
|
|
726
814
|
resolve(Buffer.from(data));
|
|
727
|
-
}
|
|
728
815
|
});
|
|
729
816
|
});
|
|
730
|
-
|
|
817
|
+
// ── Step 4: encrypt ZIP (generate random mediaKey) ────────────────────
|
|
818
|
+
const stickerPackUpload = await (0, messages_media_js_1.encryptedStream)(zipBuffer, 'sticker-pack', {
|
|
731
819
|
logger: options.logger,
|
|
732
820
|
opts: options.options
|
|
733
821
|
});
|
|
822
|
+
// ── Step 5: upload ZIP ────────────────────────────────────────────────
|
|
734
823
|
const stickerPackUploadResult = await options.upload(stickerPackUpload.encWriteStream, {
|
|
735
824
|
fileEncSha256B64: stickerPackUpload.fileEncSha256.toString('base64'),
|
|
736
825
|
mediaType: 'sticker-pack',
|
|
737
826
|
timeoutMs: options.mediaUploadTimeoutMs
|
|
738
827
|
});
|
|
828
|
+
// ── Step 6: build stickerPackMessage ──────────────────────────────────
|
|
739
829
|
m.stickerPackMessage = {
|
|
740
830
|
name,
|
|
741
831
|
publisher,
|
|
742
832
|
stickerPackId,
|
|
743
833
|
packDescription: description,
|
|
744
|
-
stickerPackOrigin:
|
|
834
|
+
stickerPackOrigin: index_js_3.WAProto.Message.StickerPackMessage.StickerPackOrigin.THIRD_PARTY,
|
|
745
835
|
stickerPackSize: zipBuffer.length,
|
|
746
836
|
stickers: stickerMetadata,
|
|
747
837
|
fileSha256: stickerPackUpload.fileSha256,
|
|
@@ -749,212 +839,219 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
749
839
|
mediaKey: stickerPackUpload.mediaKey,
|
|
750
840
|
directPath: stickerPackUploadResult.directPath,
|
|
751
841
|
fileLength: stickerPackUpload.fileLength,
|
|
752
|
-
mediaKeyTimestamp: (0,
|
|
842
|
+
mediaKeyTimestamp: (0, generics_js_1.unixTimestampSeconds)(),
|
|
753
843
|
trayIconFileName
|
|
754
844
|
};
|
|
845
|
+
// ── Step 7: generate & upload thumbnail (pakai mediaKey yang sama) ────
|
|
755
846
|
try {
|
|
756
847
|
let thumbnailBuffer;
|
|
757
|
-
if (
|
|
758
|
-
thumbnailBuffer = await
|
|
848
|
+
if ('sharp' in lib && lib.sharp) {
|
|
849
|
+
thumbnailBuffer = await lib.sharp.default(coverBuffer).resize(252, 252).jpeg().toBuffer();
|
|
759
850
|
}
|
|
760
|
-
else if (
|
|
761
|
-
const
|
|
762
|
-
|
|
763
|
-
thumbnailBuffer = await getJimpBuffer(image.resize({ w: 252, h: 252 }), 'image/jpeg');
|
|
851
|
+
else if ('jimp' in lib && lib.jimp) {
|
|
852
|
+
const jimpImage = await (lib.jimp.Jimp || lib.jimp.default).read(coverBuffer);
|
|
853
|
+
thumbnailBuffer = await jimpImage.resize({ w: 252, h: 252 }).getBuffer('image/jpeg');
|
|
764
854
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
logger: options.logger,
|
|
768
|
-
opts: options.options,
|
|
769
|
-
mediaKey: stickerPackUpload.mediaKey
|
|
770
|
-
});
|
|
771
|
-
const thumbUploadResult = await options.upload(thumbUpload.encWriteStream, {
|
|
772
|
-
fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
|
|
773
|
-
mediaType: 'thumbnail-sticker-pack',
|
|
774
|
-
timeoutMs: options.mediaUploadTimeoutMs
|
|
775
|
-
});
|
|
776
|
-
Object.assign(m.stickerPackMessage, {
|
|
777
|
-
thumbnailDirectPath: thumbUploadResult.directPath,
|
|
778
|
-
thumbnailSha256: thumbUpload.fileSha256,
|
|
779
|
-
thumbnailEncSha256: thumbUpload.fileEncSha256,
|
|
780
|
-
thumbnailHeight: 252,
|
|
781
|
-
thumbnailWidth: 252,
|
|
782
|
-
imageDataHash: (0, crypto_2.sha256)(thumbnailBuffer).toString('base64')
|
|
783
|
-
});
|
|
855
|
+
else {
|
|
856
|
+
throw new Error('No image processing library available for thumbnail generation');
|
|
784
857
|
}
|
|
858
|
+
if (!thumbnailBuffer || thumbnailBuffer.length === 0) {
|
|
859
|
+
throw new Error('Failed to generate thumbnail buffer');
|
|
860
|
+
}
|
|
861
|
+
const thumbUpload = await (0, messages_media_js_1.encryptedStream)(thumbnailBuffer, 'thumbnail-sticker-pack', {
|
|
862
|
+
logger: options.logger,
|
|
863
|
+
opts: options.options,
|
|
864
|
+
mediaKey: stickerPackUpload.mediaKey
|
|
865
|
+
});
|
|
866
|
+
const thumbUploadResult = await options.upload(thumbUpload.encWriteStream, {
|
|
867
|
+
fileEncSha256B64: thumbUpload.fileEncSha256.toString('base64'),
|
|
868
|
+
mediaType: 'thumbnail-sticker-pack',
|
|
869
|
+
timeoutMs: options.mediaUploadTimeoutMs
|
|
870
|
+
});
|
|
871
|
+
Object.assign(m.stickerPackMessage, {
|
|
872
|
+
thumbnailDirectPath: thumbUploadResult.directPath,
|
|
873
|
+
thumbnailSha256: thumbUpload.fileSha256,
|
|
874
|
+
thumbnailEncSha256: thumbUpload.fileEncSha256,
|
|
875
|
+
thumbnailHeight: 252,
|
|
876
|
+
thumbnailWidth: 252,
|
|
877
|
+
imageDataHash: (0, crypto_js_1.sha256)(thumbnailBuffer).toString('base64')
|
|
878
|
+
});
|
|
785
879
|
}
|
|
786
|
-
catch (
|
|
787
|
-
|
|
788
|
-
(_s = (_r = options.logger) === null || _r === void 0 ? void 0 : _r.warn) === null || _s === void 0 ? void 0 : _s.call(_r, { err: error }, 'sticker pack thumbnail generation failed');
|
|
880
|
+
catch (e) {
|
|
881
|
+
options.logger?.warn?.(`Thumbnail generation failed: ${e}`);
|
|
789
882
|
}
|
|
790
883
|
m.stickerPackMessage.contextInfo = {
|
|
791
|
-
...(
|
|
792
|
-
...(
|
|
884
|
+
...(message.contextInfo || {}),
|
|
885
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
793
886
|
};
|
|
794
887
|
}
|
|
795
|
-
else if ('
|
|
796
|
-
m.messageContextInfo = {
|
|
797
|
-
messageSecret: message.event.messageSecret || (0, crypto_1.randomBytes)(32),
|
|
798
|
-
};
|
|
799
|
-
m.eventMessage = { ...message.event };
|
|
800
|
-
}
|
|
801
|
-
else if ('inviteAdmin' in message) {
|
|
888
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'adminInvite')) {
|
|
802
889
|
m.newsletterAdminInviteMessage = {};
|
|
803
|
-
m.newsletterAdminInviteMessage.
|
|
804
|
-
m.newsletterAdminInviteMessage.
|
|
805
|
-
m.newsletterAdminInviteMessage.
|
|
806
|
-
m.newsletterAdminInviteMessage.
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
stickerMessage: {
|
|
817
|
-
...sticker === null || sticker === void 0 ? void 0 : sticker.stickerMessage,
|
|
818
|
-
contextInfo: (_f = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _f === void 0 ? void 0 : _f.contextInfo
|
|
819
|
-
}
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
else if (message.requestPayment.note) {
|
|
823
|
-
notes = {
|
|
824
|
-
extendedTextMessage: {
|
|
825
|
-
text: message.requestPayment.note,
|
|
826
|
-
contextInfo: (_g = message === null || message === void 0 ? void 0 : message.requestPayment) === null || _g === void 0 ? void 0 : _g.contextInfo,
|
|
890
|
+
m.newsletterAdminInviteMessage.newsletterJid = message.adminInvite.jid;
|
|
891
|
+
m.newsletterAdminInviteMessage.newsletterName = message.adminInvite.name;
|
|
892
|
+
m.newsletterAdminInviteMessage.caption = message.adminInvite.caption;
|
|
893
|
+
m.newsletterAdminInviteMessage.inviteExpiration = message.adminInvite.expiration;
|
|
894
|
+
if (message.adminInvite.jpegThumbnail) {
|
|
895
|
+
m.newsletterAdminInviteMessage.jpegThumbnail = message.adminInvite.jpegThumbnail;
|
|
896
|
+
}
|
|
897
|
+
else if (options.getProfilePicUrl) {
|
|
898
|
+
try {
|
|
899
|
+
const pfpUrl = await options.getProfilePicUrl(message.adminInvite.jid);
|
|
900
|
+
if (pfpUrl) {
|
|
901
|
+
const { thumbnail } = await (0, messages_media_js_1.generateThumbnail)(pfpUrl, 'image');
|
|
902
|
+
m.newsletterAdminInviteMessage.jpegThumbnail = thumbnail;
|
|
827
903
|
}
|
|
828
|
-
}
|
|
904
|
+
}
|
|
905
|
+
catch (_) { }
|
|
829
906
|
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
expiryTimestamp: message.requestPayment.expiry,
|
|
835
|
-
amount1000: message.requestPayment.amount,
|
|
836
|
-
currencyCodeIso4217: message.requestPayment.currency,
|
|
837
|
-
requestFrom: message.requestPayment.from,
|
|
838
|
-
noteMessage: { ...notes },
|
|
839
|
-
background: (_h = message.requestPayment.background) !== null && _h !== void 0 ? _h : null,
|
|
840
|
-
});
|
|
907
|
+
m.newsletterAdminInviteMessage.contextInfo = {
|
|
908
|
+
...(message.contextInfo || {}),
|
|
909
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
910
|
+
};
|
|
841
911
|
}
|
|
842
|
-
else if ('sharePhoneNumber'
|
|
912
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'sharePhoneNumber')) {
|
|
843
913
|
m.protocolMessage = {
|
|
844
|
-
type:
|
|
914
|
+
type: index_js_1.proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER
|
|
845
915
|
};
|
|
846
916
|
}
|
|
847
|
-
else if ('requestPhoneNumber'
|
|
917
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'requestPhoneNumber')) {
|
|
848
918
|
m.requestPhoneNumberMessage = {};
|
|
849
919
|
}
|
|
850
|
-
else if ('
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
920
|
+
else if ((0, exports.hasNonNullishProperty)(message, 'limitSharing')) {
|
|
921
|
+
m.protocolMessage = {
|
|
922
|
+
type: index_js_1.proto.Message.ProtocolMessage.Type.LIMIT_SHARING,
|
|
923
|
+
limitSharing: {
|
|
924
|
+
sharingLimited: message.limitSharing === true,
|
|
925
|
+
trigger: 1,
|
|
926
|
+
limitSharingSettingTimestamp: Date.now(),
|
|
927
|
+
initiatedByMe: true
|
|
928
|
+
}
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
else if ('interactiveMessage' in message && !!message.interactiveMessage) {
|
|
932
|
+
// ── Passthrough interactiveMessage raw object ──────────────────────
|
|
933
|
+
// Must be BEFORE the else block to avoid hitting prepareWAMessageMedia
|
|
934
|
+
// which throws 'Invalid media type' for interactiveMessage keys.
|
|
935
|
+
m = { interactiveMessage: message.interactiveMessage };
|
|
857
936
|
}
|
|
858
937
|
else {
|
|
859
938
|
m = await (0, exports.prepareWAMessageMedia)(message, options);
|
|
860
939
|
}
|
|
861
|
-
if ('
|
|
940
|
+
if ('sections' in message && !!message.sections) {
|
|
941
|
+
const listMessage = {
|
|
942
|
+
title: message.title,
|
|
943
|
+
buttonText: message.buttonText,
|
|
944
|
+
footerText: message.footer,
|
|
945
|
+
description: message.text,
|
|
946
|
+
sections: message.sections,
|
|
947
|
+
listType: index_js_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
|
|
948
|
+
};
|
|
949
|
+
listMessage.contextInfo = {
|
|
950
|
+
...(message.contextInfo || {}),
|
|
951
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
952
|
+
};
|
|
953
|
+
m = { listMessage };
|
|
954
|
+
}
|
|
955
|
+
else if ('productList' in message && !!message.productList) {
|
|
956
|
+
const thumbnail = message.thumbnail ? await (0, messages_media_js_1.generateThumbnail)(message.thumbnail, 'image') : null;
|
|
957
|
+
const listMessage = {
|
|
958
|
+
title: message.title,
|
|
959
|
+
buttonText: message.buttonText,
|
|
960
|
+
footerText: message.footer,
|
|
961
|
+
description: message.text,
|
|
962
|
+
productListInfo: {
|
|
963
|
+
productSections: message.productList,
|
|
964
|
+
headerImage: {
|
|
965
|
+
productId: message.productList[0].products[0].productId,
|
|
966
|
+
jpegThumbnail: thumbnail?.thumbnail || null
|
|
967
|
+
},
|
|
968
|
+
businessOwnerJid: message.businessOwnerJid
|
|
969
|
+
},
|
|
970
|
+
listType: index_js_1.proto.Message.ListMessage.ListType.PRODUCT_LIST
|
|
971
|
+
};
|
|
972
|
+
listMessage.contextInfo = {
|
|
973
|
+
...(message.contextInfo || {}),
|
|
974
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
975
|
+
};
|
|
976
|
+
m = { listMessage };
|
|
977
|
+
}
|
|
978
|
+
else if ('buttons' in message && !!message.buttons) {
|
|
862
979
|
const buttonsMessage = {
|
|
863
|
-
buttons: message.buttons.map(b => ({ ...b, type:
|
|
980
|
+
buttons: message.buttons.map(b => ({ ...b, type: index_js_1.proto.Message.ButtonsMessage.Button.Type.RESPONSE }))
|
|
864
981
|
};
|
|
865
982
|
if ('text' in message) {
|
|
866
983
|
buttonsMessage.contentText = message.text;
|
|
867
|
-
buttonsMessage.headerType =
|
|
984
|
+
buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType.EMPTY;
|
|
868
985
|
}
|
|
869
986
|
else {
|
|
870
987
|
if ('caption' in message) {
|
|
871
988
|
buttonsMessage.contentText = message.caption;
|
|
872
989
|
}
|
|
873
990
|
const type = Object.keys(m)[0].replace('Message', '').toUpperCase();
|
|
874
|
-
buttonsMessage.headerType =
|
|
991
|
+
buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType[type];
|
|
875
992
|
Object.assign(buttonsMessage, m);
|
|
876
993
|
}
|
|
877
|
-
if ('title' in message && !!message.title) {
|
|
878
|
-
buttonsMessage.text = message.title,
|
|
879
|
-
buttonsMessage.headerType = ButtonType.TEXT;
|
|
880
|
-
}
|
|
881
994
|
if ('footer' in message && !!message.footer) {
|
|
882
995
|
buttonsMessage.footerText = message.footer;
|
|
883
996
|
}
|
|
884
|
-
if ('
|
|
885
|
-
buttonsMessage.
|
|
886
|
-
|
|
887
|
-
if ('mentions' in message && !!message.mentions) {
|
|
888
|
-
buttonsMessage.contextInfo = { mentionedJid: message.mentions };
|
|
997
|
+
if ('title' in message && !!message.title) {
|
|
998
|
+
buttonsMessage.text = message.title;
|
|
999
|
+
buttonsMessage.headerType = index_js_1.proto.Message.ButtonsMessage.HeaderType.TEXT;
|
|
889
1000
|
}
|
|
1001
|
+
buttonsMessage.contextInfo = {
|
|
1002
|
+
...(message.contextInfo || {}),
|
|
1003
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
1004
|
+
};
|
|
890
1005
|
m = { buttonsMessage };
|
|
891
1006
|
}
|
|
892
1007
|
else if ('templateButtons' in message && !!message.templateButtons) {
|
|
893
|
-
const
|
|
894
|
-
hydratedButtons: message.
|
|
1008
|
+
const hydratedTemplate = {
|
|
1009
|
+
hydratedButtons: message.templateButtons
|
|
895
1010
|
};
|
|
896
1011
|
if ('text' in message) {
|
|
897
|
-
|
|
1012
|
+
hydratedTemplate.hydratedContentText = message.text;
|
|
898
1013
|
}
|
|
899
1014
|
else {
|
|
900
1015
|
if ('caption' in message) {
|
|
901
|
-
|
|
1016
|
+
hydratedTemplate.hydratedContentText = message.caption;
|
|
902
1017
|
}
|
|
903
|
-
Object.assign(
|
|
1018
|
+
Object.assign(hydratedTemplate, m);
|
|
904
1019
|
}
|
|
905
1020
|
if ('footer' in message && !!message.footer) {
|
|
906
|
-
|
|
1021
|
+
hydratedTemplate.hydratedFooterText = message.footer;
|
|
907
1022
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
hydratedTemplate: msg
|
|
912
|
-
}
|
|
913
|
-
};
|
|
914
|
-
}
|
|
915
|
-
if ('sections' in message && !!message.sections) {
|
|
916
|
-
const listMessage = {
|
|
917
|
-
sections: message.sections,
|
|
918
|
-
buttonText: message.buttonText,
|
|
919
|
-
title: message.title,
|
|
920
|
-
footerText: message.footer,
|
|
921
|
-
description: message.text,
|
|
922
|
-
listType: WAProto_1.proto.Message.ListMessage.ListType.SINGLE_SELECT
|
|
1023
|
+
hydratedTemplate.contextInfo = {
|
|
1024
|
+
...(message.contextInfo || {}),
|
|
1025
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
923
1026
|
};
|
|
924
|
-
m = {
|
|
1027
|
+
m = { templateMessage: { fourRowTemplate: hydratedTemplate, hydratedTemplate } };
|
|
925
1028
|
}
|
|
926
|
-
if ('interactiveButtons' in message && !!message.interactiveButtons) {
|
|
1029
|
+
else if ('interactiveButtons' in message && !!message.interactiveButtons) {
|
|
927
1030
|
const interactiveMessage = {
|
|
928
|
-
nativeFlowMessage:
|
|
1031
|
+
nativeFlowMessage: index_js_1.proto.Message.InteractiveMessage.NativeFlowMessage.fromObject({
|
|
929
1032
|
buttons: message.interactiveButtons,
|
|
930
1033
|
})
|
|
931
1034
|
};
|
|
932
1035
|
if ('text' in message) {
|
|
933
|
-
interactiveMessage.body = {
|
|
934
|
-
text: message.text
|
|
935
|
-
};
|
|
1036
|
+
interactiveMessage.body = { text: message.text };
|
|
936
1037
|
}
|
|
937
1038
|
else if ('caption' in message) {
|
|
938
|
-
interactiveMessage.body = {
|
|
939
|
-
text: message.caption
|
|
940
|
-
};
|
|
1039
|
+
interactiveMessage.body = { text: message.caption };
|
|
941
1040
|
interactiveMessage.header = {
|
|
942
1041
|
title: message.title,
|
|
943
1042
|
subtitle: message.subtitle,
|
|
944
|
-
hasMediaAttachment:
|
|
1043
|
+
hasMediaAttachment: message?.media ?? false,
|
|
945
1044
|
};
|
|
946
1045
|
Object.assign(interactiveMessage.header, m);
|
|
947
1046
|
}
|
|
948
1047
|
if ('footer' in message && !!message.footer) {
|
|
949
|
-
interactiveMessage.footer = {
|
|
950
|
-
text: message.footer
|
|
951
|
-
};
|
|
1048
|
+
interactiveMessage.footer = { text: message.footer };
|
|
952
1049
|
}
|
|
953
1050
|
if ('title' in message && !!message.title) {
|
|
954
1051
|
interactiveMessage.header = {
|
|
955
1052
|
title: message.title,
|
|
956
1053
|
subtitle: message.subtitle,
|
|
957
|
-
hasMediaAttachment:
|
|
1054
|
+
hasMediaAttachment: message?.media ?? false,
|
|
958
1055
|
};
|
|
959
1056
|
Object.assign(interactiveMessage.header, m);
|
|
960
1057
|
}
|
|
@@ -966,39 +1063,33 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
966
1063
|
}
|
|
967
1064
|
m = { interactiveMessage };
|
|
968
1065
|
}
|
|
969
|
-
if ('shop' in message && !!message.shop) {
|
|
1066
|
+
else if ('shop' in message && !!message.shop) {
|
|
970
1067
|
const interactiveMessage = {
|
|
971
|
-
shopStorefrontMessage:
|
|
1068
|
+
shopStorefrontMessage: index_js_1.proto.Message.InteractiveMessage.ShopMessage.fromObject({
|
|
972
1069
|
surface: message.shop,
|
|
973
1070
|
id: message.id
|
|
974
1071
|
})
|
|
975
1072
|
};
|
|
976
1073
|
if ('text' in message) {
|
|
977
|
-
interactiveMessage.body = {
|
|
978
|
-
text: message.text
|
|
979
|
-
};
|
|
1074
|
+
interactiveMessage.body = { text: message.text };
|
|
980
1075
|
}
|
|
981
1076
|
else if ('caption' in message) {
|
|
982
|
-
interactiveMessage.body = {
|
|
983
|
-
text: message.caption
|
|
984
|
-
};
|
|
1077
|
+
interactiveMessage.body = { text: message.caption };
|
|
985
1078
|
interactiveMessage.header = {
|
|
986
1079
|
title: message.title,
|
|
987
1080
|
subtitle: message.subtitle,
|
|
988
|
-
hasMediaAttachment:
|
|
1081
|
+
hasMediaAttachment: message?.media ?? false,
|
|
989
1082
|
};
|
|
990
1083
|
Object.assign(interactiveMessage.header, m);
|
|
991
1084
|
}
|
|
992
1085
|
if ('footer' in message && !!message.footer) {
|
|
993
|
-
interactiveMessage.footer = {
|
|
994
|
-
text: message.footer
|
|
995
|
-
};
|
|
1086
|
+
interactiveMessage.footer = { text: message.footer };
|
|
996
1087
|
}
|
|
997
1088
|
if ('title' in message && !!message.title) {
|
|
998
1089
|
interactiveMessage.header = {
|
|
999
1090
|
title: message.title,
|
|
1000
1091
|
subtitle: message.subtitle,
|
|
1001
|
-
hasMediaAttachment:
|
|
1092
|
+
hasMediaAttachment: message?.media ?? false,
|
|
1002
1093
|
};
|
|
1003
1094
|
Object.assign(interactiveMessage.header, m);
|
|
1004
1095
|
}
|
|
@@ -1010,30 +1101,143 @@ const generateWAMessageContent = async (message, options) => {
|
|
|
1010
1101
|
}
|
|
1011
1102
|
m = { interactiveMessage };
|
|
1012
1103
|
}
|
|
1013
|
-
if ('
|
|
1014
|
-
|
|
1104
|
+
else if ('collection' in message && !!message.collection) {
|
|
1105
|
+
const interactiveMessage = {
|
|
1106
|
+
collectionMessage: {
|
|
1107
|
+
bizJid: message.collection.bizJid,
|
|
1108
|
+
id: message.collection.id,
|
|
1109
|
+
messageVersion: message?.collection?.version
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
if ('text' in message) {
|
|
1113
|
+
interactiveMessage.body = { text: message.text };
|
|
1114
|
+
interactiveMessage.header = {
|
|
1115
|
+
title: message.title,
|
|
1116
|
+
subtitle: message.subtitle,
|
|
1117
|
+
hasMediaAttachment: false
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
else {
|
|
1121
|
+
if ('caption' in message) {
|
|
1122
|
+
interactiveMessage.body = { text: message.caption };
|
|
1123
|
+
interactiveMessage.header = {
|
|
1124
|
+
title: message.title,
|
|
1125
|
+
subtitle: message.subtitle,
|
|
1126
|
+
hasMediaAttachment: message.hasMediaAttachment ? message.hasMediaAttachment : false,
|
|
1127
|
+
...Object.assign(interactiveMessage, m)
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
if ('footer' in message && !!message.footer) {
|
|
1132
|
+
interactiveMessage.footer = { text: message.footer };
|
|
1133
|
+
}
|
|
1134
|
+
interactiveMessage.contextInfo = {
|
|
1135
|
+
...(message.contextInfo || {}),
|
|
1136
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
1137
|
+
};
|
|
1138
|
+
m = { interactiveMessage };
|
|
1139
|
+
}
|
|
1140
|
+
else if ('cards' in message && !!message.cards) {
|
|
1141
|
+
const slides = await Promise.all(message.cards.map(async (slide) => {
|
|
1142
|
+
const { image, video, product, title, body, footer, buttons } = slide;
|
|
1143
|
+
let header;
|
|
1144
|
+
if (product) {
|
|
1145
|
+
const { imageMessage } = await (0, exports.prepareWAMessageMedia)({ image: product.productImage, ...options }, options);
|
|
1146
|
+
header = {
|
|
1147
|
+
productMessage: {
|
|
1148
|
+
product: {
|
|
1149
|
+
...product,
|
|
1150
|
+
productImage: imageMessage,
|
|
1151
|
+
},
|
|
1152
|
+
...slide
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
else if (image) {
|
|
1157
|
+
header = await (0, exports.prepareWAMessageMedia)({ image: image, ...options }, options);
|
|
1158
|
+
}
|
|
1159
|
+
else if (video) {
|
|
1160
|
+
header = await (0, exports.prepareWAMessageMedia)({ video: video, ...options }, options);
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
header: {
|
|
1164
|
+
title,
|
|
1165
|
+
hasMediaAttachment: true,
|
|
1166
|
+
...header
|
|
1167
|
+
},
|
|
1168
|
+
body: { text: body },
|
|
1169
|
+
footer: { text: footer },
|
|
1170
|
+
nativeFlowMessage: { buttons }
|
|
1171
|
+
};
|
|
1172
|
+
}));
|
|
1173
|
+
const interactiveMessage = {
|
|
1174
|
+
carouselMessage: { cards: slides }
|
|
1175
|
+
};
|
|
1176
|
+
if ('text' in message) {
|
|
1177
|
+
interactiveMessage.body = { text: message.text };
|
|
1178
|
+
interactiveMessage.header = {
|
|
1179
|
+
title: message.title,
|
|
1180
|
+
subtitle: message.subtitle,
|
|
1181
|
+
hasMediaAttachment: false
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
if ('footer' in message && !!message.footer) {
|
|
1185
|
+
interactiveMessage.footer = { text: message.footer };
|
|
1186
|
+
}
|
|
1187
|
+
interactiveMessage.contextInfo = {
|
|
1188
|
+
...(message.contextInfo || {}),
|
|
1189
|
+
...(message.mentions ? { mentionedJid: message.mentions } : {})
|
|
1190
|
+
};
|
|
1191
|
+
m = { interactiveMessage };
|
|
1192
|
+
}
|
|
1193
|
+
if (hasOptionalProperty(message, 'ephemeral') && !!message.ephemeral) {
|
|
1194
|
+
m = { ephemeralMessage: { message: m } };
|
|
1015
1195
|
}
|
|
1016
|
-
if ('
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1196
|
+
if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) {
|
|
1197
|
+
m = { viewOnceMessageV2: { message: m } };
|
|
1198
|
+
}
|
|
1199
|
+
if (hasOptionalProperty(message, 'viewOnceExt') && !!message.viewOnceExt) {
|
|
1200
|
+
m = { viewOnceMessageV2Extension: { message: m } };
|
|
1201
|
+
}
|
|
1202
|
+
if (hasOptionalProperty(message, 'mentions') && message.mentions?.length) {
|
|
1203
|
+
const messageType = Object.keys(m)[0];
|
|
1204
|
+
const key = m[messageType];
|
|
1205
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1206
|
+
key.contextInfo.mentionedJid = message.mentions;
|
|
1207
|
+
}
|
|
1208
|
+
else if (key) {
|
|
1209
|
+
key.contextInfo = {
|
|
1210
|
+
mentionedJid: message.mentions
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1020
1213
|
}
|
|
1021
|
-
if ('edit'
|
|
1214
|
+
if (hasOptionalProperty(message, 'edit')) {
|
|
1022
1215
|
m = {
|
|
1023
1216
|
protocolMessage: {
|
|
1024
1217
|
key: message.edit,
|
|
1025
1218
|
editedMessage: m,
|
|
1026
1219
|
timestampMs: Date.now(),
|
|
1027
|
-
type:
|
|
1220
|
+
type: index_js_3.WAProto.Message.ProtocolMessage.Type.MESSAGE_EDIT
|
|
1028
1221
|
}
|
|
1029
1222
|
};
|
|
1030
1223
|
}
|
|
1031
|
-
if ('contextInfo'
|
|
1032
|
-
const
|
|
1033
|
-
|
|
1034
|
-
|
|
1224
|
+
if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) {
|
|
1225
|
+
const messageType = Object.keys(m)[0];
|
|
1226
|
+
const key = m[messageType];
|
|
1227
|
+
if ('contextInfo' in key && !!key.contextInfo) {
|
|
1228
|
+
key.contextInfo = { ...key.contextInfo, ...message.contextInfo };
|
|
1229
|
+
}
|
|
1230
|
+
else if (key) {
|
|
1231
|
+
key.contextInfo = message.contextInfo;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
if ((0, reporting_utils_js_1.shouldIncludeReportingToken)(m) && !options.newsletter) {
|
|
1235
|
+
m.messageContextInfo = m.messageContextInfo || {};
|
|
1236
|
+
if (!m.messageContextInfo.messageSecret) {
|
|
1237
|
+
m.messageContextInfo.messageSecret = (0, crypto_1.randomBytes)(32);
|
|
1238
|
+
}
|
|
1035
1239
|
}
|
|
1036
|
-
return
|
|
1240
|
+
return index_js_3.WAProto.Message.create(m);
|
|
1037
1241
|
};
|
|
1038
1242
|
exports.generateWAMessageContent = generateWAMessageContent;
|
|
1039
1243
|
const generateWAMessageFromContent = (jid, message, options) => {
|
|
@@ -1044,68 +1248,72 @@ const generateWAMessageFromContent = (jid, message, options) => {
|
|
|
1044
1248
|
}
|
|
1045
1249
|
const innerMessage = (0, exports.normalizeMessageContent)(message);
|
|
1046
1250
|
const key = (0, exports.getContentType)(innerMessage);
|
|
1047
|
-
const timestamp = (0,
|
|
1251
|
+
const timestamp = (0, generics_js_1.unixTimestampSeconds)(options.timestamp);
|
|
1048
1252
|
const { quoted, userJid } = options;
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1253
|
+
if (quoted && !(0, index_js_4.isJidNewsletter)(jid)) {
|
|
1254
|
+
const participant = quoted.key.fromMe
|
|
1255
|
+
? userJid // TODO: Add support for LIDs
|
|
1256
|
+
: quoted.participant || quoted.key.participant || quoted.key.remoteJid;
|
|
1052
1257
|
let quotedMsg = (0, exports.normalizeMessageContent)(quoted.message);
|
|
1053
1258
|
const msgType = (0, exports.getContentType)(quotedMsg);
|
|
1054
1259
|
// strip any redundant properties
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1260
|
+
quotedMsg = index_js_1.proto.Message.create({ [msgType]: quotedMsg[msgType] });
|
|
1261
|
+
const quotedContent = quotedMsg[msgType];
|
|
1262
|
+
if (typeof quotedContent === 'object' && quotedContent && 'contextInfo' in quotedContent) {
|
|
1263
|
+
delete quotedContent.contextInfo;
|
|
1264
|
+
}
|
|
1265
|
+
const contextInfo = ('contextInfo' in innerMessage[key] && innerMessage[key]?.contextInfo) || {};
|
|
1266
|
+
contextInfo.participant = (0, index_js_4.jidNormalizedUser)(participant);
|
|
1267
|
+
contextInfo.stanzaId = quoted.key.id;
|
|
1268
|
+
contextInfo.quotedMessage = quotedMsg;
|
|
1269
|
+
// if a participant is quoted, then it must be a group
|
|
1270
|
+
// hence, remoteJid of group must also be entered
|
|
1271
|
+
if (jid !== quoted.key.remoteJid) {
|
|
1272
|
+
contextInfo.remoteJid = quoted.key.remoteJid;
|
|
1273
|
+
}
|
|
1274
|
+
if (contextInfo && innerMessage[key]) {
|
|
1275
|
+
/* @ts-ignore */
|
|
1070
1276
|
innerMessage[key].contextInfo = contextInfo;
|
|
1071
1277
|
}
|
|
1072
1278
|
}
|
|
1073
1279
|
if (
|
|
1074
1280
|
// if we want to send a disappearing message
|
|
1075
|
-
!!
|
|
1281
|
+
!!options?.ephemeralExpiration &&
|
|
1076
1282
|
// and it's not a protocol message -- delete, toggle disappear message
|
|
1077
1283
|
key !== 'protocolMessage' &&
|
|
1078
1284
|
// already not converted to disappearing message
|
|
1079
1285
|
key !== 'ephemeralMessage' &&
|
|
1080
|
-
//
|
|
1081
|
-
!(0,
|
|
1286
|
+
// newsletters don't support ephemeral messages
|
|
1287
|
+
!(0, index_js_4.isJidNewsletter)(jid)) {
|
|
1288
|
+
/* @ts-ignore */
|
|
1082
1289
|
innerMessage[key].contextInfo = {
|
|
1083
1290
|
...(innerMessage[key].contextInfo || {}),
|
|
1084
|
-
expiration: options.ephemeralExpiration ||
|
|
1291
|
+
expiration: options.ephemeralExpiration || index_js_2.WA_DEFAULT_EPHEMERAL
|
|
1085
1292
|
//ephemeralSettingTimestamp: options.ephemeralOptions.eph_setting_ts?.toString()
|
|
1086
1293
|
};
|
|
1087
1294
|
}
|
|
1088
|
-
message =
|
|
1295
|
+
message = index_js_3.WAProto.Message.create(message);
|
|
1089
1296
|
const messageJSON = {
|
|
1090
1297
|
key: {
|
|
1091
1298
|
remoteJid: jid,
|
|
1092
1299
|
fromMe: true,
|
|
1093
|
-
id:
|
|
1300
|
+
id: options?.messageId || (0, generics_js_1.generateMessageIDV2)()
|
|
1094
1301
|
},
|
|
1095
1302
|
message: message,
|
|
1096
1303
|
messageTimestamp: timestamp,
|
|
1097
1304
|
messageStubParameters: [],
|
|
1098
|
-
participant: (0,
|
|
1099
|
-
status:
|
|
1305
|
+
participant: (0, index_js_4.isJidGroup)(jid) || (0, index_js_4.isJidStatusBroadcast)(jid) ? userJid : undefined, // TODO: Add support for LIDs
|
|
1306
|
+
status: index_js_3.WAMessageStatus.PENDING
|
|
1100
1307
|
};
|
|
1101
|
-
return
|
|
1308
|
+
return index_js_3.WAProto.WebMessageInfo.fromObject(messageJSON);
|
|
1102
1309
|
};
|
|
1103
1310
|
exports.generateWAMessageFromContent = generateWAMessageFromContent;
|
|
1104
1311
|
const generateWAMessage = async (jid, content, options) => {
|
|
1105
|
-
var _a;
|
|
1106
1312
|
// ensure msg ID is with every log
|
|
1107
|
-
options.logger =
|
|
1108
|
-
|
|
1313
|
+
options.logger = options?.logger?.child({ msgId: options.messageId });
|
|
1314
|
+
// Pass jid + newsletter flag to generateWAMessageContent (like wiley)
|
|
1315
|
+
const _isNewsletter = typeof jid === 'string' && jid.endsWith('@newsletter');
|
|
1316
|
+
return (0, exports.generateWAMessageFromContent)(jid, await (0, exports.generateWAMessageContent)(content, { newsletter: _isNewsletter, ...options, jid }), options);
|
|
1109
1317
|
};
|
|
1110
1318
|
exports.generateWAMessage = generateWAMessage;
|
|
1111
1319
|
/** Get the key to access the true type of content */
|
|
@@ -1117,6 +1325,22 @@ const getContentType = (content) => {
|
|
|
1117
1325
|
}
|
|
1118
1326
|
};
|
|
1119
1327
|
exports.getContentType = getContentType;
|
|
1328
|
+
/**
|
|
1329
|
+
* Maps a message content type key to its MediaType string.
|
|
1330
|
+
* Handles ptvMessage → 'ptv', audioMessage ptt → 'ptt', etc.
|
|
1331
|
+
*/
|
|
1332
|
+
const getMediaTypeFromContentType = (contentType, content) => {
|
|
1333
|
+
if (!contentType)
|
|
1334
|
+
return undefined;
|
|
1335
|
+
if (contentType === 'ptvMessage')
|
|
1336
|
+
return 'ptv';
|
|
1337
|
+
if (contentType === 'audioMessage' && content?.[contentType]?.ptt)
|
|
1338
|
+
return 'ptt';
|
|
1339
|
+
if (contentType === 'videoMessage' && content?.[contentType]?.gifPlayback)
|
|
1340
|
+
return 'gif';
|
|
1341
|
+
return contentType.replace('Message', '');
|
|
1342
|
+
};
|
|
1343
|
+
exports.getMediaTypeFromContentType = getMediaTypeFromContentType;
|
|
1120
1344
|
/**
|
|
1121
1345
|
* Normalizes ephemeral, view once messages to regular message content
|
|
1122
1346
|
* Eg. image messages in ephemeral messages, in view once messages etc.
|
|
@@ -1137,29 +1361,15 @@ const normalizeMessageContent = (content) => {
|
|
|
1137
1361
|
}
|
|
1138
1362
|
return content;
|
|
1139
1363
|
function getFutureProofMessage(message) {
|
|
1140
|
-
return (
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|| (message === null || message === void 0 ? void 0 : message.eventCoverImage)
|
|
1150
|
-
|| (message === null || message === void 0 ? void 0 : message.statusMentionMessage)
|
|
1151
|
-
|| (message === null || message === void 0 ? void 0 : message.pollCreationOptionImageMessage)
|
|
1152
|
-
|| (message === null || message === void 0 ? void 0 : message.associatedChildMessage)
|
|
1153
|
-
|| (message === null || message === void 0 ? void 0 : message.groupStatusMentionMessage)
|
|
1154
|
-
|| (message === null || message === void 0 ? void 0 : message.pollCreationMessageV4)
|
|
1155
|
-
|| (message === null || message === void 0 ? void 0 : message.pollCreationMessageV5)
|
|
1156
|
-
|| (message === null || message === void 0 ? void 0 : message.statusAddYours)
|
|
1157
|
-
|| (message === null || message === void 0 ? void 0 : message.groupStatusMessage)
|
|
1158
|
-
|| (message === null || message === void 0 ? void 0 : message.limitSharingMessage)
|
|
1159
|
-
|| (message === null || message === void 0 ? void 0 : message.botTaskMessage)
|
|
1160
|
-
|| (message === null || message === void 0 ? void 0 : message.questionMessage)
|
|
1161
|
-
|| (message === null || message === void 0 ? void 0 : message.groupStatusMessageV2)
|
|
1162
|
-
|| (message === null || message === void 0 ? void 0 : message.botForwardedMessage));
|
|
1364
|
+
return (message?.ephemeralMessage ||
|
|
1365
|
+
message?.viewOnceMessage ||
|
|
1366
|
+
message?.documentWithCaptionMessage ||
|
|
1367
|
+
message?.viewOnceMessageV2 ||
|
|
1368
|
+
message?.viewOnceMessageV2Extension ||
|
|
1369
|
+
message?.editedMessage ||
|
|
1370
|
+
message?.associatedChildMessage ||
|
|
1371
|
+
message?.groupStatusMessage ||
|
|
1372
|
+
message?.groupStatusMessageV2);
|
|
1163
1373
|
}
|
|
1164
1374
|
};
|
|
1165
1375
|
exports.normalizeMessageContent = normalizeMessageContent;
|
|
@@ -1168,7 +1378,6 @@ exports.normalizeMessageContent = normalizeMessageContent;
|
|
|
1168
1378
|
* Eg. extracts the inner message from a disappearing message/view once message
|
|
1169
1379
|
*/
|
|
1170
1380
|
const extractMessageContent = (content) => {
|
|
1171
|
-
var _a, _b, _c, _d, _e, _f;
|
|
1172
1381
|
const extractFromTemplateMessage = (msg) => {
|
|
1173
1382
|
if (msg.imageMessage) {
|
|
1174
1383
|
return { imageMessage: msg.imageMessage };
|
|
@@ -1184,24 +1393,22 @@ const extractMessageContent = (content) => {
|
|
|
1184
1393
|
}
|
|
1185
1394
|
else {
|
|
1186
1395
|
return {
|
|
1187
|
-
conversation: 'contentText' in msg
|
|
1188
|
-
? msg.contentText
|
|
1189
|
-
: ('hydratedContentText' in msg ? msg.hydratedContentText : '')
|
|
1396
|
+
conversation: 'contentText' in msg ? msg.contentText : 'hydratedContentText' in msg ? msg.hydratedContentText : ''
|
|
1190
1397
|
};
|
|
1191
1398
|
}
|
|
1192
1399
|
};
|
|
1193
1400
|
content = (0, exports.normalizeMessageContent)(content);
|
|
1194
|
-
if (content
|
|
1401
|
+
if (content?.buttonsMessage) {
|
|
1195
1402
|
return extractFromTemplateMessage(content.buttonsMessage);
|
|
1196
1403
|
}
|
|
1197
|
-
if (
|
|
1198
|
-
return extractFromTemplateMessage(
|
|
1404
|
+
if (content?.templateMessage?.hydratedFourRowTemplate) {
|
|
1405
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedFourRowTemplate);
|
|
1199
1406
|
}
|
|
1200
|
-
if (
|
|
1201
|
-
return extractFromTemplateMessage(
|
|
1407
|
+
if (content?.templateMessage?.hydratedTemplate) {
|
|
1408
|
+
return extractFromTemplateMessage(content?.templateMessage?.hydratedTemplate);
|
|
1202
1409
|
}
|
|
1203
|
-
if (
|
|
1204
|
-
return extractFromTemplateMessage(
|
|
1410
|
+
if (content?.templateMessage?.fourRowTemplate) {
|
|
1411
|
+
return extractFromTemplateMessage(content?.templateMessage?.fourRowTemplate);
|
|
1205
1412
|
}
|
|
1206
1413
|
return content;
|
|
1207
1414
|
};
|
|
@@ -1209,11 +1416,15 @@ exports.extractMessageContent = extractMessageContent;
|
|
|
1209
1416
|
/**
|
|
1210
1417
|
* Returns the device predicted by message ID
|
|
1211
1418
|
*/
|
|
1212
|
-
const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1419
|
+
const getDevice = (id) => /^3A.{18}$/.test(id)
|
|
1420
|
+
? 'ios'
|
|
1421
|
+
: /^3E.{20}$/.test(id)
|
|
1422
|
+
? 'web'
|
|
1423
|
+
: /^(.{21}|.{32})$/.test(id)
|
|
1424
|
+
? 'android'
|
|
1425
|
+
: /^(3F|.{18}$)/.test(id)
|
|
1426
|
+
? 'desktop'
|
|
1427
|
+
: 'unknown';
|
|
1217
1428
|
exports.getDevice = getDevice;
|
|
1218
1429
|
/** Upserts a receipt in the message */
|
|
1219
1430
|
const updateMessageWithReceipt = (msg, receipt) => {
|
|
@@ -1229,9 +1440,8 @@ const updateMessageWithReceipt = (msg, receipt) => {
|
|
|
1229
1440
|
exports.updateMessageWithReceipt = updateMessageWithReceipt;
|
|
1230
1441
|
/** Update the message with a new reaction */
|
|
1231
1442
|
const updateMessageWithReaction = (msg, reaction) => {
|
|
1232
|
-
const authorID = (0,
|
|
1233
|
-
const reactions = (msg.reactions || [])
|
|
1234
|
-
.filter(r => (0, generics_1.getKeyAuthor)(r.key) !== authorID);
|
|
1443
|
+
const authorID = (0, generics_js_1.getKeyAuthor)(reaction.key);
|
|
1444
|
+
const reactions = (msg.reactions || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.key) !== authorID);
|
|
1235
1445
|
reaction.text = reaction.text || '';
|
|
1236
1446
|
reactions.push(reaction);
|
|
1237
1447
|
msg.reactions = reactions;
|
|
@@ -1239,16 +1449,22 @@ const updateMessageWithReaction = (msg, reaction) => {
|
|
|
1239
1449
|
exports.updateMessageWithReaction = updateMessageWithReaction;
|
|
1240
1450
|
/** Update the message with a new poll update */
|
|
1241
1451
|
const updateMessageWithPollUpdate = (msg, update) => {
|
|
1242
|
-
|
|
1243
|
-
const
|
|
1244
|
-
|
|
1245
|
-
.filter(r => (0, generics_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
|
|
1246
|
-
if ((_b = (_a = update.vote) === null || _a === void 0 ? void 0 : _a.selectedOptions) === null || _b === void 0 ? void 0 : _b.length) {
|
|
1452
|
+
const authorID = (0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey);
|
|
1453
|
+
const reactions = (msg.pollUpdates || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.pollUpdateMessageKey) !== authorID);
|
|
1454
|
+
if (update.vote?.selectedOptions?.length) {
|
|
1247
1455
|
reactions.push(update);
|
|
1248
1456
|
}
|
|
1249
1457
|
msg.pollUpdates = reactions;
|
|
1250
1458
|
};
|
|
1251
1459
|
exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
|
|
1460
|
+
/** Update the message with a new event response */
|
|
1461
|
+
const updateMessageWithEventResponse = (msg, update) => {
|
|
1462
|
+
const authorID = (0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey);
|
|
1463
|
+
const responses = (msg.eventResponses || []).filter(r => (0, generics_js_1.getKeyAuthor)(r.eventResponseMessageKey) !== authorID);
|
|
1464
|
+
responses.push(update);
|
|
1465
|
+
msg.eventResponses = responses;
|
|
1466
|
+
};
|
|
1467
|
+
exports.updateMessageWithEventResponse = updateMessageWithEventResponse;
|
|
1252
1468
|
/**
|
|
1253
1469
|
* Aggregates all poll updates in a poll.
|
|
1254
1470
|
* @param msg the poll creation message
|
|
@@ -1256,10 +1472,12 @@ exports.updateMessageWithPollUpdate = updateMessageWithPollUpdate;
|
|
|
1256
1472
|
* @returns A list of options & their voters
|
|
1257
1473
|
*/
|
|
1258
1474
|
function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
1259
|
-
|
|
1260
|
-
|
|
1475
|
+
const opts = message?.pollCreationMessage?.options ||
|
|
1476
|
+
message?.pollCreationMessageV2?.options ||
|
|
1477
|
+
message?.pollCreationMessageV3?.options ||
|
|
1478
|
+
[];
|
|
1261
1479
|
const voteHashMap = opts.reduce((acc, opt) => {
|
|
1262
|
-
const hash = (0,
|
|
1480
|
+
const hash = (0, crypto_js_1.sha256)(Buffer.from(opt.optionName || '')).toString();
|
|
1263
1481
|
acc[hash] = {
|
|
1264
1482
|
name: opt.optionName || '',
|
|
1265
1483
|
voters: []
|
|
@@ -1281,11 +1499,34 @@ function getAggregateVotesInPollMessage({ message, pollUpdates }, meId) {
|
|
|
1281
1499
|
};
|
|
1282
1500
|
data = voteHashMap[hash];
|
|
1283
1501
|
}
|
|
1284
|
-
voteHashMap[hash].voters.push((0,
|
|
1502
|
+
voteHashMap[hash].voters.push((0, generics_js_1.getKeyAuthor)(update.pollUpdateMessageKey, meId));
|
|
1285
1503
|
}
|
|
1286
1504
|
}
|
|
1287
1505
|
return Object.values(voteHashMap);
|
|
1288
1506
|
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Aggregates all event responses in an event message.
|
|
1509
|
+
* @param msg the event creation message
|
|
1510
|
+
* @param meId your jid
|
|
1511
|
+
* @returns A list of response types & their responders
|
|
1512
|
+
*/
|
|
1513
|
+
function getAggregateResponsesInEventMessage({ eventResponses }, meId) {
|
|
1514
|
+
const responseTypes = ['GOING', 'NOT_GOING', 'MAYBE'];
|
|
1515
|
+
const responseMap = {};
|
|
1516
|
+
for (const type of responseTypes) {
|
|
1517
|
+
responseMap[type] = {
|
|
1518
|
+
response: type,
|
|
1519
|
+
responders: []
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
for (const update of eventResponses || []) {
|
|
1523
|
+
const responseType = update.eventResponse || 'UNKNOWN';
|
|
1524
|
+
if (responseType !== 'UNKNOWN' && responseMap[responseType]) {
|
|
1525
|
+
responseMap[responseType].responders.push((0, generics_js_1.getKeyAuthor)(update.eventResponseMessageKey, meId));
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
return Object.values(responseMap);
|
|
1529
|
+
}
|
|
1289
1530
|
/** Given a list of message keys, aggregates them by chat & sender. Useful for sending read receipts in bulk */
|
|
1290
1531
|
const aggregateMessageKeysNotFromMe = (keys) => {
|
|
1291
1532
|
const keyMap = {};
|
|
@@ -1310,20 +1551,15 @@ const REUPLOAD_REQUIRED_STATUS = [410, 404];
|
|
|
1310
1551
|
* Downloads the given message. Throws an error if it's not a media message
|
|
1311
1552
|
*/
|
|
1312
1553
|
const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
1313
|
-
const result = await downloadMsg()
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
message = await ctx.reuploadRequest(message);
|
|
1323
|
-
const result = await downloadMsg();
|
|
1324
|
-
return result;
|
|
1325
|
-
}
|
|
1326
|
-
}
|
|
1554
|
+
const result = await downloadMsg().catch(async (error) => {
|
|
1555
|
+
if (ctx &&
|
|
1556
|
+
typeof error?.status === 'number' && // treat errors with status as HTTP failures requiring reupload
|
|
1557
|
+
REUPLOAD_REQUIRED_STATUS.includes(error.status)) {
|
|
1558
|
+
ctx.logger.info({ key: message.key }, 'sending reupload media request...');
|
|
1559
|
+
// request reupload
|
|
1560
|
+
message = await ctx.reuploadRequest(message);
|
|
1561
|
+
const result = await downloadMsg();
|
|
1562
|
+
return result;
|
|
1327
1563
|
}
|
|
1328
1564
|
throw error;
|
|
1329
1565
|
});
|
|
@@ -1334,7 +1570,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
1334
1570
|
throw new boom_1.Boom('No message present', { statusCode: 400, data: message });
|
|
1335
1571
|
}
|
|
1336
1572
|
const contentType = (0, exports.getContentType)(mContent);
|
|
1337
|
-
let mediaType =
|
|
1573
|
+
let mediaType = (0, exports.getMediaTypeFromContentType)(contentType, mContent);
|
|
1338
1574
|
const media = mContent[contentType];
|
|
1339
1575
|
if (!media || typeof media !== 'object' || (!('url' in media) && !('thumbnailDirectPath' in media))) {
|
|
1340
1576
|
throw new boom_1.Boom(`"${contentType}" message is not a media message`);
|
|
@@ -1350,7 +1586,7 @@ const downloadMediaMessage = async (message, type, options, ctx) => {
|
|
|
1350
1586
|
else {
|
|
1351
1587
|
download = media;
|
|
1352
1588
|
}
|
|
1353
|
-
const stream = await (0,
|
|
1589
|
+
const stream = await (0, messages_media_js_1.downloadContentFromMessage)(download, mediaType, options);
|
|
1354
1590
|
if (type === 'buffer') {
|
|
1355
1591
|
const bufferArray = [];
|
|
1356
1592
|
for await (const chunk of stream) {
|
|
@@ -1365,33 +1601,148 @@ exports.downloadMediaMessage = downloadMediaMessage;
|
|
|
1365
1601
|
/** Checks whether the given message is a media message; if it is returns the inner content */
|
|
1366
1602
|
const assertMediaContent = (content) => {
|
|
1367
1603
|
content = (0, exports.extractMessageContent)(content);
|
|
1368
|
-
const mediaContent =
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1604
|
+
const mediaContent = content?.documentMessage ||
|
|
1605
|
+
content?.imageMessage ||
|
|
1606
|
+
content?.videoMessage ||
|
|
1607
|
+
content?.audioMessage ||
|
|
1608
|
+
content?.stickerMessage;
|
|
1373
1609
|
if (!mediaContent) {
|
|
1374
1610
|
throw new boom_1.Boom('given message is not a media message', { statusCode: 400, data: content });
|
|
1375
1611
|
}
|
|
1376
1612
|
return mediaContent;
|
|
1377
1613
|
};
|
|
1378
1614
|
exports.assertMediaContent = assertMediaContent;
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1615
|
+
const patchMessageForMdIfRequired = (message) => {
|
|
1616
|
+
if (message?.buttonsMessage ||
|
|
1617
|
+
message?.templateMessage ||
|
|
1618
|
+
message?.listMessage ||
|
|
1619
|
+
message?.interactiveMessage?.nativeFlowMessage) {
|
|
1620
|
+
message = {
|
|
1621
|
+
viewOnceMessageV2Extension: {
|
|
1622
|
+
message: {
|
|
1623
|
+
messageContextInfo: {
|
|
1624
|
+
deviceListMetadataVersion: 2,
|
|
1625
|
+
deviceListMetadata: {}
|
|
1626
|
+
},
|
|
1627
|
+
...message
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
return message;
|
|
1388
1633
|
};
|
|
1389
|
-
exports.
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
const
|
|
1394
|
-
|
|
1395
|
-
|
|
1634
|
+
exports.patchMessageForMdIfRequired = patchMessageForMdIfRequired;
|
|
1635
|
+
const prepareAlbumMessageContent = async (jid, albums, options) => {
|
|
1636
|
+
let mediaHandle;
|
|
1637
|
+
let mediaMsg;
|
|
1638
|
+
const message = [];
|
|
1639
|
+
const albumMsg = (0, exports.generateWAMessageFromContent)(jid, {
|
|
1640
|
+
albumMessage: {
|
|
1641
|
+
expectedImageCount: albums.filter(item => 'image' in item).length,
|
|
1642
|
+
expectedVideoCount: albums.filter(item => 'video' in item).length
|
|
1643
|
+
}
|
|
1644
|
+
}, options);
|
|
1645
|
+
await options.sock.relayMessage(jid, albumMsg.message, { messageId: albumMsg.key.id });
|
|
1646
|
+
for (const i in albums) {
|
|
1647
|
+
const media = albums[i];
|
|
1648
|
+
if ('image' in media) {
|
|
1649
|
+
mediaMsg = await (0, exports.generateWAMessage)(jid, { image: media.image, ...media, ...options }, {
|
|
1650
|
+
userJid: options.userJid,
|
|
1651
|
+
upload: async (encFilePath, opts) => {
|
|
1652
|
+
const up = await options.sock.waUploadToServer(encFilePath, { ...opts, newsletter: (0, index_js_4.isJidNewsletter)(jid) });
|
|
1653
|
+
mediaHandle = up.handle;
|
|
1654
|
+
return up;
|
|
1655
|
+
},
|
|
1656
|
+
...options
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
else if ('video' in media) {
|
|
1660
|
+
mediaMsg = await (0, exports.generateWAMessage)(jid, { video: media.video, ...media, ...options }, {
|
|
1661
|
+
userJid: options.userJid,
|
|
1662
|
+
upload: async (encFilePath, opts) => {
|
|
1663
|
+
const up = await options.sock.waUploadToServer(encFilePath, { ...opts, newsletter: (0, index_js_4.isJidNewsletter)(jid) });
|
|
1664
|
+
mediaHandle = up.handle;
|
|
1665
|
+
return up;
|
|
1666
|
+
},
|
|
1667
|
+
...options
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
if (mediaMsg) {
|
|
1671
|
+
mediaMsg.message.messageContextInfo = {
|
|
1672
|
+
messageSecret: (0, crypto_1.randomBytes)(32),
|
|
1673
|
+
messageAssociation: {
|
|
1674
|
+
associationType: 1,
|
|
1675
|
+
parentMessageKey: albumMsg.key
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1679
|
+
message.push(mediaMsg);
|
|
1680
|
+
}
|
|
1681
|
+
return message;
|
|
1682
|
+
};
|
|
1683
|
+
exports.prepareAlbumMessageContent = prepareAlbumMessageContent;
|
|
1684
|
+
/**
|
|
1685
|
+
* Ekstrak quoted message dari contextInfo pesan.
|
|
1686
|
+
* Return object yang sudah dinormalisasi, termasuk debug info LID/PN.
|
|
1687
|
+
*
|
|
1688
|
+
* @param {object} msg - WAMessage object dari event messages.upsert
|
|
1689
|
+
* @param {object} [options]
|
|
1690
|
+
* @param {boolean} [options.debug] - jika true, log info ke console
|
|
1691
|
+
* @returns {object|null} quoted message info atau null jika tidak ada
|
|
1692
|
+
*/
|
|
1693
|
+
const getQuotedMsg = (msg, options = {}) => {
|
|
1694
|
+
const { debug = false } = options;
|
|
1695
|
+
const msgContent = (0, exports.normalizeMessageContent)(msg?.message);
|
|
1696
|
+
if (!msgContent)
|
|
1697
|
+
return null;
|
|
1698
|
+
const msgType = (0, exports.getContentType)(msgContent);
|
|
1699
|
+
if (!msgType)
|
|
1700
|
+
return null;
|
|
1701
|
+
const innerMsg = msgContent[msgType];
|
|
1702
|
+
if (!innerMsg)
|
|
1703
|
+
return null;
|
|
1704
|
+
const contextInfo = innerMsg.contextInfo;
|
|
1705
|
+
if (!contextInfo?.stanzaId || !contextInfo?.quotedMessage)
|
|
1706
|
+
return null;
|
|
1707
|
+
// Normalisasi participant (sender quoted message)
|
|
1708
|
+
const participant = contextInfo.participant || msg.key?.participant || msg.key?.remoteJid || '';
|
|
1709
|
+
// Normalisasi mentionedJid di quoted message
|
|
1710
|
+
const quotedMsgContent = (0, exports.normalizeMessageContent)(contextInfo.quotedMessage);
|
|
1711
|
+
const quotedMsgType = (0, exports.getContentType)(quotedMsgContent);
|
|
1712
|
+
const quotedInnerMsg = quotedMsgType ? quotedMsgContent?.[quotedMsgType] : null;
|
|
1713
|
+
const quotedMentionedJid = quotedInnerMsg?.contextInfo?.mentionedJid || [];
|
|
1714
|
+
const quotedText = quotedInnerMsg?.text || quotedInnerMsg?.caption || quotedInnerMsg?.conversation || '';
|
|
1715
|
+
const result = {
|
|
1716
|
+
key: {
|
|
1717
|
+
id: contextInfo.stanzaId,
|
|
1718
|
+
remoteJid: contextInfo.remoteJid || msg.key?.remoteJid || '',
|
|
1719
|
+
participant: participant,
|
|
1720
|
+
fromMe: false
|
|
1721
|
+
},
|
|
1722
|
+
message: contextInfo.quotedMessage,
|
|
1723
|
+
participant,
|
|
1724
|
+
sender: participant,
|
|
1725
|
+
text: quotedText,
|
|
1726
|
+
type: quotedMsgType || '',
|
|
1727
|
+
mentionedJid: quotedMentionedJid,
|
|
1728
|
+
// Debug info
|
|
1729
|
+
_rawContextInfo: debug ? contextInfo : undefined
|
|
1730
|
+
};
|
|
1731
|
+
if (debug) {
|
|
1732
|
+
const hasLidInText = typeof quotedText === 'string' && /@\d{13,20}/.test(quotedText);
|
|
1733
|
+
const hasLidInMentioned = quotedMentionedJid.some(j => j?.endsWith('@lid'));
|
|
1734
|
+
const hasLidParticipant = participant?.endsWith('@lid');
|
|
1735
|
+
console.log('[getQuotedMsg DEBUG]', JSON.stringify({
|
|
1736
|
+
stanzaId: contextInfo.stanzaId,
|
|
1737
|
+
participant,
|
|
1738
|
+
participantIsLid: hasLidParticipant,
|
|
1739
|
+
quotedText,
|
|
1740
|
+
textHasLid: hasLidInText,
|
|
1741
|
+
mentionedJid: quotedMentionedJid,
|
|
1742
|
+
mentionedHasLid: hasLidInMentioned,
|
|
1743
|
+
quotedMsgType
|
|
1744
|
+
}, null, 2));
|
|
1745
|
+
}
|
|
1746
|
+
return result;
|
|
1396
1747
|
};
|
|
1397
|
-
exports.
|
|
1748
|
+
exports.getQuotedMsg = getQuotedMsg;
|