@nexustechpro/baileys 2.0.5 → 2.1.0
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/README.md +71 -0
- package/WAProto/index.js +22 -18
- package/lib/Defaults/baileys-version.json +1 -1
- package/lib/Defaults/index.js +9 -8
- package/lib/Signal/libsignal.js +551 -342
- package/lib/Socket/chats.js +83 -65
- package/lib/Socket/index.js +2 -3
- package/lib/Socket/messages-recv.js +227 -41
- package/lib/Socket/messages-send.js +97 -117
- package/lib/Socket/newsletter.js +87 -36
- package/lib/Socket/nexus-handler.js +326 -89
- package/lib/Socket/registration.js +50 -33
- package/lib/Socket/socket.js +245 -69
- package/lib/Store/make-in-memory-store.js +29 -20
- package/lib/Types/Newsletter.js +37 -29
- package/lib/Types/State.js +43 -0
- package/lib/Utils/auth-utils.js +2 -2
- package/lib/Utils/chat-utils.js +48 -16
- package/lib/Utils/companion-reg-client-utils.js +34 -0
- package/lib/Utils/decode-wa-message.js +39 -22
- package/lib/Utils/generics.js +5 -7
- package/lib/Utils/index.js +4 -0
- package/lib/Utils/key-store.js +1 -1
- package/lib/Utils/link-preview.js +134 -61
- package/lib/Utils/messages-media.js +496 -381
- package/lib/Utils/messages.js +699 -706
- package/lib/Utils/process-message.js +53 -35
- package/lib/Utils/reporting-utils.js +155 -0
- package/lib/Utils/signal.js +134 -104
- package/lib/Utils/sync-action-utils.js +33 -0
- package/lib/Utils/tc-token-utils.js +162 -0
- package/lib/Utils/use-multi-file-auth-state.js +174 -91
- package/lib/WABinary/constants.js +6 -0
- package/lib/WABinary/index.js +1 -0
- package/lib/index.js +2 -3
- package/package.json +13 -9
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { proto } from '../../WAProto/index.js'
|
|
1
2
|
import axios from 'axios'
|
|
2
3
|
import crypto from 'crypto'
|
|
3
4
|
|
|
@@ -27,23 +28,24 @@ class NexusHandler {
|
|
|
27
28
|
// ─── TYPE DETECTION ───────────────────────────────────────────────────────
|
|
28
29
|
detectType(content) {
|
|
29
30
|
if (content.carouselMessage || content.carousel) return 'CAROUSEL'
|
|
30
|
-
|
|
31
|
+
if (content.carouselProto) return 'CAROUSEL_PROTO'
|
|
32
|
+
const map = {
|
|
31
33
|
requestPaymentMessage: 'PAYMENT', productMessage: 'PRODUCT',
|
|
32
34
|
interactiveMessage: 'INTERACTIVE', interactive: 'INTERACTIVE',
|
|
33
|
-
albumMessage: 'ALBUM', eventMessage: 'EVENT',
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
albumMessage: 'ALBUM', eventMessage: 'EVENT',
|
|
36
|
+
pollResultMessage: 'POLL_RESULT', statusMentionMessage: 'STATUS_MENTION',
|
|
37
|
+
orderMessage: 'ORDER', stickerPack: 'STICKER_PACK', groupStatus: 'GROUP_STATUS'
|
|
36
38
|
}
|
|
37
|
-
return
|
|
39
|
+
return map[Object.keys(map).find(k => content[k])] || null
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
// ─── UNIFIED PROCESSOR ────────────────────────────────────────────────────
|
|
41
43
|
async processMessage(content, jid, quoted) {
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
44
|
-
const handler = this.handlers[
|
|
45
|
-
if (!handler) throw new Error(`No handler for: ${
|
|
46
|
-
return
|
|
44
|
+
const type = this.detectType(content)
|
|
45
|
+
if (!type) throw new Error('Unknown message type')
|
|
46
|
+
const handler = this.handlers[type]
|
|
47
|
+
if (!handler) throw new Error(`No handler for: ${type}`)
|
|
48
|
+
return await handler(content, jid, quoted)
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
// ─── HELPERS ──────────────────────────────────────────────────────────────
|
|
@@ -53,7 +55,7 @@ class NexusHandler {
|
|
|
53
55
|
return await this.utils.prepareWAMessageMedia(payload, { upload: this.upload })
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
async
|
|
58
|
+
async genMsg(jid, content, opts = {}) {
|
|
57
59
|
return await this.utils.generateWAMessage(jid, content, {
|
|
58
60
|
...opts,
|
|
59
61
|
upload: this.upload,
|
|
@@ -63,37 +65,72 @@ class NexusHandler {
|
|
|
63
65
|
})
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
async genFromContent(jid, content, opts = {}) {
|
|
69
|
+
return await this.utils.generateWAMessageFromContent(jid, content, {
|
|
70
|
+
...opts,
|
|
71
|
+
userJid: opts.userJid || this.user?.id
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
async sendMsg(jid, message, opts = {}) {
|
|
67
76
|
return await this.relay(jid, message, opts)
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
buildCtx(quoted, sender) {
|
|
71
|
-
return {
|
|
80
|
+
return {
|
|
81
|
+
stanzaId: quoted?.key?.id,
|
|
82
|
+
participant: quoted?.key?.participant || sender,
|
|
83
|
+
quotedMessage: quoted?.message
|
|
84
|
+
}
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
buildFullCtx(ctx, adReply) {
|
|
88
|
+
const allowed = ['title', 'body', 'mediaType', 'thumbnailUrl', 'mediaUrl', 'sourceUrl', 'showAdAttribution', 'renderLargerThumbnail', 'thumbnail']
|
|
75
89
|
const final = ctx ? { mentionedJid: ctx.mentionedJid || [], forwardingScore: ctx.forwardingScore || 0, isForwarded: ctx.isForwarded || false, ...ctx } : {}
|
|
76
|
-
if (adReply)
|
|
90
|
+
if (adReply) {
|
|
91
|
+
final.externalAdReply = {}
|
|
92
|
+
for (const k of allowed) if (adReply[k] !== undefined) final.externalAdReply[k] = adReply[k]
|
|
93
|
+
final.externalAdReply = { mediaType: 1, showAdAttribution: false, renderLargerThumbnail: false, ...final.externalAdReply }
|
|
94
|
+
}
|
|
77
95
|
return final
|
|
78
96
|
}
|
|
79
97
|
|
|
80
|
-
genJid() {
|
|
81
|
-
|
|
82
|
-
|
|
98
|
+
genJid() {
|
|
99
|
+
const id = this.utils.generateMessageIDV2?.() || this.utils.generateMessageID?.() || crypto.randomBytes(10).toString('hex')
|
|
100
|
+
return id.includes('@') ? id : `${id}@s.whatsapp.net`
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
parseTime(val, def) { return typeof val === 'string' ? parseInt(val) : (val || def) }
|
|
104
|
+
delay(ms) { return new Promise(r => setTimeout(r, ms)) }
|
|
105
|
+
|
|
106
|
+
async downloadBuffer(urlOrBuffer) {
|
|
107
|
+
if (Buffer.isBuffer(urlOrBuffer)) return urlOrBuffer
|
|
108
|
+
if (typeof urlOrBuffer === 'string') {
|
|
109
|
+
try {
|
|
110
|
+
const res = await axios.get(urlOrBuffer, { responseType: 'arraybuffer' })
|
|
111
|
+
return Buffer.from(res.data)
|
|
112
|
+
} catch { this.opts.logger?.warn('Failed to download buffer from URL') }
|
|
113
|
+
}
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
83
116
|
|
|
84
117
|
// ─── PAYMENT ──────────────────────────────────────────────────────────────
|
|
85
118
|
async handlePayment(content, jid, quoted) {
|
|
86
119
|
const d = content.requestPaymentMessage
|
|
120
|
+
const ctx = this.buildCtx(quoted, content.sender)
|
|
87
121
|
const notes = d.sticker?.stickerMessage
|
|
88
|
-
? { stickerMessage: { ...d.sticker.stickerMessage, contextInfo:
|
|
89
|
-
: d.note ? { extendedTextMessage: { text: d.note, contextInfo:
|
|
122
|
+
? { stickerMessage: { ...d.sticker.stickerMessage, contextInfo: ctx } }
|
|
123
|
+
: d.note ? { extendedTextMessage: { text: d.note, contextInfo: ctx } } : {}
|
|
90
124
|
const targetJid = jid || content.jid
|
|
91
|
-
const msg = await this.
|
|
92
|
-
requestPaymentMessage: {
|
|
93
|
-
expiryTimestamp: d.expiry || 0,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
125
|
+
const msg = await this.genFromContent(targetJid, {
|
|
126
|
+
requestPaymentMessage: proto.Message.RequestPaymentMessage.fromObject({
|
|
127
|
+
expiryTimestamp: d.expiry || 0,
|
|
128
|
+
amount1000: d.amount || 0,
|
|
129
|
+
currencyCodeIso4217: d.currency || 'IDR',
|
|
130
|
+
requestFrom: d.from || '0@s.whatsapp.net',
|
|
131
|
+
noteMessage: notes,
|
|
132
|
+
background: d.background ?? { id: 'DEFAULT', placeholderArgb: 0xfff0f0f0 }
|
|
133
|
+
})
|
|
97
134
|
}, { quoted })
|
|
98
135
|
await this.sendMsg(targetJid, msg.message, { messageId: msg.key.id })
|
|
99
136
|
return msg
|
|
@@ -104,13 +141,36 @@ class NexusHandler {
|
|
|
104
141
|
const p = content.productMessage || {}
|
|
105
142
|
let prodImg = null
|
|
106
143
|
if (p.thumbnail) {
|
|
107
|
-
const
|
|
108
|
-
const res = await this.utils.generateWAMessageContent(
|
|
144
|
+
const src = Buffer.isBuffer(p.thumbnail) ? { image: p.thumbnail } : { image: { url: p.thumbnail.url || p.thumbnail } }
|
|
145
|
+
const res = await this.utils.generateWAMessageContent(src, { upload: this.upload })
|
|
109
146
|
prodImg = res?.imageMessage || res?.message?.imageMessage
|
|
110
147
|
}
|
|
111
|
-
const product =
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
const product = proto.Message.ProductMessage.ProductSnapshot.create({
|
|
149
|
+
productId: p.productId,
|
|
150
|
+
title: p.title || '',
|
|
151
|
+
description: p.description || '',
|
|
152
|
+
currencyCode: p.currencyCode || 'IDR',
|
|
153
|
+
priceAmount1000: p.priceAmount1000,
|
|
154
|
+
retailerId: p.retailerId,
|
|
155
|
+
url: p.url,
|
|
156
|
+
productImageCount: prodImg ? 1 : 0,
|
|
157
|
+
...(prodImg && { productImage: prodImg })
|
|
158
|
+
})
|
|
159
|
+
const msg = await this.genFromContent(jid, {
|
|
160
|
+
viewOnceMessage: {
|
|
161
|
+
message: {
|
|
162
|
+
interactiveMessage: proto.Message.InteractiveMessage.create({
|
|
163
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: p.body || '' }),
|
|
164
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: p.footer || '' }),
|
|
165
|
+
header: proto.Message.InteractiveMessage.Header.create({
|
|
166
|
+
title: p.title || '',
|
|
167
|
+
hasMediaAttachment: !!prodImg,
|
|
168
|
+
productMessage: proto.Message.ProductMessage.create({ product, businessOwnerJid: '0@s.whatsapp.net' })
|
|
169
|
+
}),
|
|
170
|
+
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({ buttons: p.buttons || [] })
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
}
|
|
114
174
|
}, { quoted })
|
|
115
175
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
116
176
|
return msg
|
|
@@ -130,26 +190,29 @@ class NexusHandler {
|
|
|
130
190
|
if (i.mimetype) media.documentMessage.mimetype = i.mimetype
|
|
131
191
|
}
|
|
132
192
|
const bodyText = i.body?.text || i.title || ''
|
|
133
|
-
const footerText = i.footer?.text || i.footer || ''
|
|
134
|
-
const
|
|
193
|
+
const footerText = i.footer?.text || (typeof i.footer === 'string' ? i.footer : '') || ''
|
|
194
|
+
const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
|
|
195
|
+
let nativeFlow = null
|
|
135
196
|
if (i.buttons?.length || i.nativeFlowMessage) {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (media.imageMessage) headerMedia.imageMessage = media.imageMessage
|
|
142
|
-
if (media.videoMessage) headerMedia.videoMessage = media.videoMessage
|
|
143
|
-
if (media.documentMessage) headerMedia.documentMessage = media.documentMessage
|
|
144
|
-
const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
|
|
145
|
-
interactive.header = { title: headerTitle, hasMediaAttachment: true, ...headerMedia }
|
|
146
|
-
} else {
|
|
147
|
-
const headerTitle = typeof i.header === 'string' ? i.header : i.header?.title || ''
|
|
148
|
-
interactive.header = { title: headerTitle, hasMediaAttachment: false }
|
|
197
|
+
const nfm = i.nativeFlowMessage || {}
|
|
198
|
+
nativeFlow = proto.Message.InteractiveMessage.NativeFlowMessage.create({
|
|
199
|
+
buttons: i.buttons || nfm.buttons || [],
|
|
200
|
+
messageParamsJson: nfm.messageParamsJson || ''
|
|
201
|
+
})
|
|
149
202
|
}
|
|
203
|
+
const headerMedia = {}
|
|
204
|
+
if (media?.imageMessage) headerMedia.imageMessage = media.imageMessage
|
|
205
|
+
if (media?.videoMessage) headerMedia.videoMessage = media.videoMessage
|
|
206
|
+
if (media?.documentMessage) headerMedia.documentMessage = media.documentMessage
|
|
207
|
+
const interactive = proto.Message.InteractiveMessage.create({
|
|
208
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: bodyText }),
|
|
209
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: footerText }),
|
|
210
|
+
header: proto.Message.InteractiveMessage.Header.create({ title: headerTitle, hasMediaAttachment: !!media, ...headerMedia }),
|
|
211
|
+
...(nativeFlow && { nativeFlowMessage: nativeFlow })
|
|
212
|
+
})
|
|
150
213
|
const ctx = this.buildFullCtx(i.contextInfo, i.externalAdReply)
|
|
151
214
|
if (Object.keys(ctx).length) interactive.contextInfo = ctx
|
|
152
|
-
const msg = await this.
|
|
215
|
+
const msg = await this.genFromContent(jid, { interactiveMessage: interactive }, { quoted })
|
|
153
216
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
154
217
|
return msg
|
|
155
218
|
}
|
|
@@ -158,17 +221,51 @@ class NexusHandler {
|
|
|
158
221
|
async handleAlbum(content, jid, quoted) {
|
|
159
222
|
const arr = Array.isArray(content.albumMessage) ? content.albumMessage : []
|
|
160
223
|
if (!arr.length) throw new Error('albumMessage must contain media items')
|
|
161
|
-
const album = await this.
|
|
162
|
-
messageContextInfo: { messageSecret: crypto.randomBytes(32) },
|
|
163
|
-
albumMessage:
|
|
224
|
+
const album = await this.genFromContent(jid, {
|
|
225
|
+
messageContextInfo: proto.MessageContextInfo.create({ messageSecret: crypto.randomBytes(32) }),
|
|
226
|
+
albumMessage: proto.Message.AlbumMessage.create({
|
|
227
|
+
expectedImageCount: arr.filter(a => a.image).length,
|
|
228
|
+
expectedVideoCount: arr.filter(a => a.video).length
|
|
229
|
+
})
|
|
164
230
|
}, { userJid: this.genJid(), quoted })
|
|
165
231
|
await this.sendMsg(jid, album.message, { messageId: album.key.id })
|
|
166
232
|
for (const item of arr) {
|
|
167
|
-
const img = await this.
|
|
168
|
-
img.message.messageContextInfo =
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
233
|
+
const img = await this.genMsg(jid, item, {})
|
|
234
|
+
img.message.messageContextInfo = proto.MessageContextInfo.create({
|
|
235
|
+
messageSecret: crypto.randomBytes(32),
|
|
236
|
+
messageAssociation: proto.MessageAssociation.create({ associationType: 1, parentMessageKey: album.key }),
|
|
237
|
+
participant: '0@s.whatsapp.net',
|
|
238
|
+
remoteJid: 'status@broadcast',
|
|
239
|
+
forwardingScore: 99999,
|
|
240
|
+
isForwarded: true,
|
|
241
|
+
mentionedJid: [jid],
|
|
242
|
+
starred: true,
|
|
243
|
+
labels: ['Y', 'Important'],
|
|
244
|
+
isHighlighted: true,
|
|
245
|
+
businessMessageForwardInfo: proto.ContextInfo.BusinessMessageForwardInfo.create({ businessOwnerJid: jid }),
|
|
246
|
+
dataSharingContext: proto.ContextInfo.DataSharingContext.create({ showMmDisclosure: true })
|
|
247
|
+
})
|
|
248
|
+
img.message.forwardedNewsletterMessageInfo = proto.ContextInfo.ForwardedNewsletterMessageInfo.create({
|
|
249
|
+
newsletterJid: '0@newsletter',
|
|
250
|
+
serverMessageId: 1,
|
|
251
|
+
newsletterName: 'WhatsApp',
|
|
252
|
+
contentType: 'UPDATE_CARD',
|
|
253
|
+
timestamp: new Date().toISOString(),
|
|
254
|
+
senderName: 'Nexus',
|
|
255
|
+
priority: 'high',
|
|
256
|
+
status: 'sent'
|
|
257
|
+
})
|
|
258
|
+
img.message.disappearingMode = proto.DisappearingMode.create({
|
|
259
|
+
initiator: 3, trigger: 4, initiatorDeviceJid: jid,
|
|
260
|
+
initiatedByExternalService: true, initiatedByUserDevice: true,
|
|
261
|
+
initiatedBySystem: true, initiatedByServer: true,
|
|
262
|
+
initiatedByAdmin: true, initiatedByUser: true,
|
|
263
|
+
initiatedByApp: true, initiatedByBot: true, initiatedByMe: true
|
|
264
|
+
})
|
|
265
|
+
await this.sendMsg(jid, img.message, {
|
|
266
|
+
messageId: img.key.id,
|
|
267
|
+
quoted: { key: { ...album.key, fromMe: true, participant: this.genJid() }, message: album.message }
|
|
268
|
+
})
|
|
172
269
|
}
|
|
173
270
|
return album
|
|
174
271
|
}
|
|
@@ -176,8 +273,33 @@ class NexusHandler {
|
|
|
176
273
|
// ─── EVENT ────────────────────────────────────────────────────────────────
|
|
177
274
|
async handleEvent(content, jid, quoted) {
|
|
178
275
|
const e = content.eventMessage
|
|
179
|
-
const msg = await this.
|
|
180
|
-
|
|
276
|
+
const msg = await this.genFromContent(jid, {
|
|
277
|
+
messageContextInfo: proto.MessageContextInfo.create({
|
|
278
|
+
deviceListMetadata: {},
|
|
279
|
+
deviceListMetadataVersion: 2,
|
|
280
|
+
messageSecret: crypto.randomBytes(32),
|
|
281
|
+
supportPayload: JSON.stringify({ version: 2, is_ai_message: true, should_show_system_message: true, ticket_id: crypto.randomBytes(16).toString('hex') })
|
|
282
|
+
}),
|
|
283
|
+
eventMessage: proto.Message.EventMessage.create({
|
|
284
|
+
contextInfo: proto.ContextInfo.create({
|
|
285
|
+
mentionedJid: [jid],
|
|
286
|
+
participant: jid,
|
|
287
|
+
remoteJid: 'status@broadcast',
|
|
288
|
+
forwardedNewsletterMessageInfo: proto.ContextInfo.ForwardedNewsletterMessageInfo.create({
|
|
289
|
+
newsletterName: 'Nexus Events',
|
|
290
|
+
newsletterJid: '120363422827915475@newsletter',
|
|
291
|
+
serverMessageId: 1
|
|
292
|
+
})
|
|
293
|
+
}),
|
|
294
|
+
isCanceled: e.isCanceled || false,
|
|
295
|
+
name: e.name,
|
|
296
|
+
description: e.description,
|
|
297
|
+
location: e.location || { degreesLatitude: 0, degreesLongitude: 0, name: 'Location' },
|
|
298
|
+
joinLink: e.joinLink || '',
|
|
299
|
+
startTime: this.parseTime(e.startTime, Date.now()),
|
|
300
|
+
endTime: this.parseTime(e.endTime, Date.now() + 3600000),
|
|
301
|
+
extraGuestsAllowed: e.extraGuestsAllowed !== false
|
|
302
|
+
})
|
|
181
303
|
}, { quoted })
|
|
182
304
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
183
305
|
return msg
|
|
@@ -186,8 +308,24 @@ class NexusHandler {
|
|
|
186
308
|
// ─── POLL RESULT ──────────────────────────────────────────────────────────
|
|
187
309
|
async handlePollResult(content, jid, quoted) {
|
|
188
310
|
const p = content.pollResultMessage
|
|
189
|
-
const msg = await this.
|
|
190
|
-
pollResultSnapshotMessage:
|
|
311
|
+
const msg = await this.genFromContent(jid, {
|
|
312
|
+
pollResultSnapshotMessage: proto.Message.PollResultSnapshotMessage.create({
|
|
313
|
+
name: p.name,
|
|
314
|
+
pollVotes: (p.pollVotes || []).map(v => proto.Message.PollResultSnapshotMessage.PollVote.create({
|
|
315
|
+
optionName: v.optionName,
|
|
316
|
+
optionVoteCount: typeof v.optionVoteCount === 'number' ? v.optionVoteCount.toString() : v.optionVoteCount
|
|
317
|
+
})),
|
|
318
|
+
contextInfo: proto.ContextInfo.create({
|
|
319
|
+
isForwarded: true,
|
|
320
|
+
forwardingScore: 1,
|
|
321
|
+
forwardedNewsletterMessageInfo: proto.ContextInfo.ForwardedNewsletterMessageInfo.create({
|
|
322
|
+
newsletterName: p.newsletter?.newsletterName || 'Newsletter',
|
|
323
|
+
newsletterJid: p.newsletter?.newsletterJid || '120363399602691477@newsletter',
|
|
324
|
+
serverMessageId: 1000,
|
|
325
|
+
contentType: 'UPDATE'
|
|
326
|
+
})
|
|
327
|
+
})
|
|
328
|
+
})
|
|
191
329
|
}, { userJid: this.genJid(), quoted })
|
|
192
330
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
193
331
|
return msg
|
|
@@ -196,30 +334,54 @@ class NexusHandler {
|
|
|
196
334
|
// ─── STATUS MENTION ───────────────────────────────────────────────────────
|
|
197
335
|
async handleStMention(content, jid, quoted) {
|
|
198
336
|
const d = content.statusMentionMessage
|
|
199
|
-
const
|
|
200
|
-
await this.
|
|
337
|
+
const mediaType = d.image ? 'image' : 'video'
|
|
338
|
+
const media = await this.prepMedia(d.image || d.video, mediaType)
|
|
339
|
+
const statusMsg = await this.relay('status@broadcast', { ...media }, {
|
|
201
340
|
statusJidList: [d.mentions, this.user?.id].filter(Boolean),
|
|
202
|
-
additionalNodes: [{
|
|
341
|
+
additionalNodes: [{
|
|
342
|
+
tag: 'meta', attrs: {},
|
|
343
|
+
content: [{ tag: 'mentioned_users', attrs: {}, content: [{ tag: 'to', attrs: { jid: d.mentions }, content: undefined }] }]
|
|
344
|
+
}]
|
|
203
345
|
})
|
|
204
|
-
const
|
|
205
|
-
statusMentionMessage: {
|
|
346
|
+
const mentionMsg = await this.genFromContent(jid, {
|
|
347
|
+
statusMentionMessage: proto.Message.StatusMentionMessage.create({
|
|
348
|
+
message: {
|
|
349
|
+
protocolMessage: proto.Message.ProtocolMessage.create({
|
|
350
|
+
messageId: statusMsg?.key?.id || d.mentions,
|
|
351
|
+
type: proto.Message.ProtocolMessage.Type.STATUS_MENTION_MESSAGE
|
|
352
|
+
})
|
|
353
|
+
}
|
|
354
|
+
})
|
|
206
355
|
}, { additionalNodes: [{ tag: 'meta', attrs: { is_status_mention: 'true' }, content: undefined }] })
|
|
207
|
-
await this.sendMsg(jid,
|
|
208
|
-
return
|
|
356
|
+
await this.sendMsg(jid, mentionMsg.message, { messageId: mentionMsg.key.id })
|
|
357
|
+
return mentionMsg
|
|
209
358
|
}
|
|
210
359
|
|
|
211
360
|
// ─── ORDER ────────────────────────────────────────────────────────────────
|
|
212
361
|
async handleOrderMessage(content, jid, quoted) {
|
|
213
362
|
const o = content.orderMessage
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
363
|
+
const thumb = await this.downloadBuffer(o.thumbnail)
|
|
364
|
+
const cleanJid = (id) => {
|
|
365
|
+
if (!id) return null
|
|
366
|
+
const [user] = id.split(':')
|
|
367
|
+
return user.includes('@') ? user : `${user}@s.whatsapp.net`
|
|
220
368
|
}
|
|
221
|
-
const
|
|
222
|
-
|
|
369
|
+
const seller = cleanJid(o.sellerJid) || cleanJid(this.user?.id) || cleanJid(jid) || '0@s.whatsapp.net'
|
|
370
|
+
const msg = await this.genFromContent(jid, {
|
|
371
|
+
orderMessage: proto.Message.OrderMessage.create({
|
|
372
|
+
orderId: o.orderId || '7NEXUS25022008',
|
|
373
|
+
thumbnail: thumb,
|
|
374
|
+
itemCount: o.itemCount || 0,
|
|
375
|
+
status: 2, // ACCEPTED
|
|
376
|
+
surface: 1, // CATALOG
|
|
377
|
+
message: o.message,
|
|
378
|
+
orderTitle: o.orderTitle,
|
|
379
|
+
sellerJid: seller,
|
|
380
|
+
token: o.token || 'NEXUS_EXAMPLE_TOKEN',
|
|
381
|
+
totalAmount1000: o.totalAmount1000 || 0,
|
|
382
|
+
totalCurrencyCode: o.totalCurrencyCode || 'IDR',
|
|
383
|
+
messageVersion: 2
|
|
384
|
+
})
|
|
223
385
|
}, { quoted })
|
|
224
386
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
225
387
|
return msg
|
|
@@ -228,62 +390,137 @@ class NexusHandler {
|
|
|
228
390
|
// ─── GROUP STATUS ─────────────────────────────────────────────────────────
|
|
229
391
|
async handleGroupStory(content, jid, quoted) {
|
|
230
392
|
const s = content.groupStatus
|
|
231
|
-
const mediaContent = await this.utils.generateWAMessageContent(s, {
|
|
232
|
-
|
|
233
|
-
|
|
393
|
+
const mediaContent = await this.utils.generateWAMessageContent(s, {
|
|
394
|
+
upload: this.upload,
|
|
395
|
+
getUrlInfo: this.opts.getUrlInfo,
|
|
396
|
+
logger: this.opts.logger
|
|
397
|
+
})
|
|
398
|
+
const msg = await this.genFromContent(jid, {
|
|
399
|
+
groupStatusMessageV2: proto.Message.FutureProofMessage.create({ message: proto.Message.fromObject(mediaContent) })
|
|
400
|
+
}, { userJid: jid })
|
|
401
|
+
return await this.sendMsg(jid, msg.message, {
|
|
402
|
+
messageId: msg.key.id,
|
|
403
|
+
additionalNodes: [{ tag: 'meta', attrs: { is_group_status: 'true' }, content: undefined }]
|
|
404
|
+
})
|
|
234
405
|
}
|
|
235
406
|
|
|
236
407
|
// ─── CAROUSEL ─────────────────────────────────────────────────────────────
|
|
237
408
|
async handleCarousel(content, jid, quoted) {
|
|
238
409
|
const c = content.carouselMessage || content.carousel || {}
|
|
239
410
|
const cards = await Promise.all((c.cards || []).map(card => this.buildCard(card)))
|
|
240
|
-
const msg = await this.
|
|
241
|
-
viewOnceMessage: {
|
|
411
|
+
const msg = await this.genFromContent(jid, {
|
|
412
|
+
viewOnceMessage: {
|
|
413
|
+
message: {
|
|
414
|
+
interactiveMessage: proto.Message.InteractiveMessage.create({
|
|
415
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: c.caption || c.body || '' }),
|
|
416
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: c.footer || '' }),
|
|
417
|
+
carouselMessage: proto.Message.InteractiveMessage.CarouselMessage.create({ cards, messageVersion: 1 })
|
|
418
|
+
})
|
|
419
|
+
}
|
|
420
|
+
}
|
|
242
421
|
}, { quoted })
|
|
243
422
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
244
423
|
return msg
|
|
245
424
|
}
|
|
246
425
|
|
|
247
426
|
async buildCard(card) {
|
|
427
|
+
const buttons = (card.buttons || []).map(btn => ({
|
|
428
|
+
name: btn.name,
|
|
429
|
+
buttonParamsJson: JSON.stringify(btn.params || {})
|
|
430
|
+
}))
|
|
248
431
|
if (card.productTitle) {
|
|
249
|
-
|
|
432
|
+
const imgMedia = await this.prepMedia({ url: card.imageUrl }, 'image')
|
|
433
|
+
return {
|
|
434
|
+
header: proto.Message.InteractiveMessage.Header.create({
|
|
435
|
+
title: card.headerTitle || '',
|
|
436
|
+
subtitle: card.headerSubtitle || '',
|
|
437
|
+
hasMediaAttachment: false,
|
|
438
|
+
productMessage: proto.Message.ProductMessage.create({
|
|
439
|
+
product: proto.Message.ProductMessage.ProductSnapshot.create({
|
|
440
|
+
productImage: imgMedia?.imageMessage,
|
|
441
|
+
productId: card.productId || '123456',
|
|
442
|
+
title: card.productTitle,
|
|
443
|
+
description: card.productDescription || '',
|
|
444
|
+
currencyCode: card.currencyCode || 'IDR',
|
|
445
|
+
priceAmount1000: card.priceAmount1000 || '100000',
|
|
446
|
+
retailerId: card.retailerId || 'Retailer',
|
|
447
|
+
url: card.url || '',
|
|
448
|
+
productImageCount: 1
|
|
449
|
+
}),
|
|
450
|
+
businessOwnerJid: card.businessOwnerJid || '0@s.whatsapp.net'
|
|
451
|
+
})
|
|
452
|
+
}),
|
|
453
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: card.bodyText || '' }),
|
|
454
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: card.footerText || '' }),
|
|
455
|
+
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({ buttons })
|
|
456
|
+
}
|
|
250
457
|
}
|
|
251
458
|
const imgMedia = card.imageUrl ? await this.prepMedia({ url: card.imageUrl }, 'image') : {}
|
|
252
|
-
return {
|
|
459
|
+
return {
|
|
460
|
+
header: proto.Message.InteractiveMessage.Header.create({
|
|
461
|
+
title: card.headerTitle || '',
|
|
462
|
+
subtitle: card.headerSubtitle || '',
|
|
463
|
+
hasMediaAttachment: !!card.imageUrl,
|
|
464
|
+
...imgMedia
|
|
465
|
+
}),
|
|
466
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: card.bodyText || '' }),
|
|
467
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: card.footerText || '' }),
|
|
468
|
+
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({ buttons })
|
|
469
|
+
}
|
|
253
470
|
}
|
|
254
471
|
|
|
255
472
|
// ─── CAROUSEL PROTO ───────────────────────────────────────────────────────
|
|
256
473
|
async handleCarouselProto(content, jid, quoted) {
|
|
257
474
|
const c = content.carouselProto
|
|
258
|
-
const proto = this.utils.WAProto?.proto
|
|
259
|
-
if (!proto) throw new Error('WAProto not available')
|
|
260
475
|
const cards = await Promise.all((c.cards || []).map(async card => ({
|
|
261
|
-
header: proto.Message.InteractiveMessage.Header.create({
|
|
476
|
+
header: proto.Message.InteractiveMessage.Header.create({
|
|
477
|
+
title: card.title?.substring(0, 60) || '',
|
|
478
|
+
subtitle: card.subtitle || '',
|
|
479
|
+
hasMediaAttachment: false
|
|
480
|
+
}),
|
|
262
481
|
body: proto.Message.InteractiveMessage.Body.create({ text: card.bodyText || '' }),
|
|
263
482
|
footer: proto.Message.InteractiveMessage.Footer.create({ text: card.footerText || '' }),
|
|
264
|
-
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({
|
|
483
|
+
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({
|
|
484
|
+
buttons: (card.buttons || []).map(btn => ({ name: btn.name, buttonParamsJson: JSON.stringify(btn.params || {}) }))
|
|
485
|
+
})
|
|
265
486
|
})))
|
|
266
|
-
const msg = await this.
|
|
267
|
-
viewOnceMessage: {
|
|
487
|
+
const msg = await this.genFromContent(jid, {
|
|
488
|
+
viewOnceMessage: {
|
|
489
|
+
message: {
|
|
490
|
+
messageContextInfo: proto.MessageContextInfo.create({ deviceListMetadata: {}, deviceListMetadataVersion: 2 }),
|
|
491
|
+
interactiveMessage: proto.Message.InteractiveMessage.create({
|
|
492
|
+
body: proto.Message.InteractiveMessage.Body.create({ text: c.body || '' }),
|
|
493
|
+
footer: proto.Message.InteractiveMessage.Footer.create({ text: c.footer || '' }),
|
|
494
|
+
carouselMessage: proto.Message.InteractiveMessage.CarouselMessage.create({ cards, messageVersion: 1 })
|
|
495
|
+
})
|
|
496
|
+
}
|
|
497
|
+
}
|
|
268
498
|
}, { quoted })
|
|
269
499
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
270
500
|
return msg
|
|
271
501
|
}
|
|
272
502
|
|
|
273
503
|
// ─── STICKER PACK ─────────────────────────────────────────────────────────
|
|
274
|
-
async handleStickerPack(
|
|
275
|
-
const
|
|
504
|
+
async handleStickerPack(content, jid, quoted) {
|
|
505
|
+
const stickerPack = content.stickerPack
|
|
506
|
+
const result = await this.utils.prepareStickerPackMessage(stickerPack, {
|
|
507
|
+
logger: this.opts?.logger,
|
|
508
|
+
upload: this.upload,
|
|
509
|
+
mediaCache: this.opts?.mediaCache,
|
|
510
|
+
options: this.opts,
|
|
511
|
+
mediaUploadTimeoutMs: this.opts?.mediaUploadTimeoutMs
|
|
512
|
+
})
|
|
276
513
|
if (result.isBatched) {
|
|
277
514
|
const sent = []
|
|
278
515
|
for (let i = 0; i < result.stickerPackMessage.length; i++) {
|
|
279
|
-
const msg = await this.
|
|
516
|
+
const msg = await this.genFromContent(jid, { stickerPackMessage: result.stickerPackMessage[i] }, { quoted })
|
|
280
517
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
281
518
|
sent.push(msg)
|
|
282
519
|
if (i < result.stickerPackMessage.length - 1) await this.delay(2000)
|
|
283
520
|
}
|
|
284
521
|
return sent[sent.length - 1]
|
|
285
522
|
}
|
|
286
|
-
const msg = await this.
|
|
523
|
+
const msg = await this.genFromContent(jid, { stickerPackMessage: result.stickerPackMessage }, { quoted })
|
|
287
524
|
await this.sendMsg(jid, msg.message, { messageId: msg.key.id })
|
|
288
525
|
return msg
|
|
289
526
|
}
|