mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Removed deprecations + merge message-status-update into chat-update
1. Update package version to 4.0.0 2. Retry query if the connection unexpectedly closes + make query iterative instead of recursive 3. Remove message-new & message-update deprecations 4. Deprecate loadProfilePicturesForChatsAutomatically
This commit is contained in:
@@ -9,13 +9,14 @@ import {
|
||||
ReconnectMode,
|
||||
ProxyAgent,
|
||||
waChatKey,
|
||||
delay,
|
||||
} from '../src/WAConnection/WAConnection'
|
||||
import * as fs from 'fs'
|
||||
|
||||
async function example() {
|
||||
const conn = new WAConnection() // instantiate
|
||||
conn.autoReconnect = ReconnectMode.onConnectionLost // only automatically reconnect when the connection breaks
|
||||
conn.logger.level = 'debug' // set to 'debug' to see what kind of stuff you can implement
|
||||
conn.logger.level = 'trace' // set to 'debug' to see what kind of stuff you can implement
|
||||
// attempt to reconnect at most 10 times in a row
|
||||
conn.connectOptions.maxRetries = 10
|
||||
conn.chatOrderingKey = waChatKey(true) // order chats such that pinned chats are on top
|
||||
@@ -34,28 +35,34 @@ async function example() {
|
||||
})
|
||||
|
||||
// loads the auth file credentials if present
|
||||
/* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code,
|
||||
and get full access to one's WhatsApp. Despite the convenience, be careful with this file */
|
||||
fs.existsSync('./auth_info.json') && conn.loadAuthInfo ('./auth_info.json')
|
||||
// uncomment the following line to proxy the connection; some random proxy I got off of: https://proxyscrape.com/free-proxy-list
|
||||
//conn.connectOptions.agent = ProxyAgent ('http://1.0.180.120:8080')
|
||||
await conn.connect()
|
||||
|
||||
console.log('oh hello ' + conn.user.name + ' (' + conn.user.jid + ')')
|
||||
|
||||
// uncomment to load all unread messages
|
||||
//const unread = await conn.loadAllUnreadMessages ()
|
||||
//console.log ('you have ' + unread.length + ' unread messages')
|
||||
|
||||
/* Note: one can take this auth_info.json file and login again from any computer without having to scan the QR code,
|
||||
and get full access to one's WhatsApp. Despite the convenience, be careful with this file */
|
||||
conn.on ('message-status-update', json => {
|
||||
const participant = json.participant ? ' (' + json.participant + ')' : '' // participant exists when the message is from a group
|
||||
console.log(`${json.to}${participant} acknlowledged message(s) ${json.ids} as ${json.type}`)
|
||||
})
|
||||
/**
|
||||
* The universal event for anything that happens
|
||||
* New messages, updated messages, read & delivered messages
|
||||
*/
|
||||
conn.on('chat-update', async chat => {
|
||||
if (chat.presences) { // receive presence updates -- composing, available, etc.
|
||||
Object.values(chat.presences).forEach(presence => console.log( `${presence.name}'s presence is ${presence.lastKnownPresence} in ${chat.jid}`))
|
||||
}
|
||||
// only do something when a new message is received
|
||||
if (!chat.hasNewMessage) return
|
||||
if (!chat.hasNewMessage) {
|
||||
if(chat.messages) {
|
||||
console.log('updated message: ', chat.messages.first)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const m = chat.messages.all()[0] // pull the new message from the update
|
||||
const messageStubType = WA_MESSAGE_STUB_TYPES[m.messageStubType] || 'MESSAGE'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@adiwajshing/baileys",
|
||||
"version": "3.4.1",
|
||||
"version": "4.0.0",
|
||||
"description": "WhatsApp Web API",
|
||||
"homepage": "https://github.com/adiwajshing/Baileys",
|
||||
"main": "lib/index.js",
|
||||
|
||||
@@ -372,4 +372,21 @@ describe ('Pending Requests', () => {
|
||||
|
||||
conn.close ()
|
||||
})
|
||||
it('should re-execute query on connection closed error', async () => {
|
||||
const conn = makeConnection ()
|
||||
//conn.pendingRequestTimeoutMs = 10_000
|
||||
await conn.loadAuthInfo('./auth_info.json').connect ()
|
||||
const task: Promise<any> = conn.query({json: ['query', 'Status', conn.user.jid], waitForOpen: true})
|
||||
|
||||
await delay(20)
|
||||
conn['onMessageRecieved']('1234,["Pong",false]') // fake cancel the connection
|
||||
|
||||
await delay(2000)
|
||||
|
||||
const json = await task
|
||||
|
||||
assert.ok (json.status)
|
||||
|
||||
conn.close ()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { MessageType, Mimetype, delay, promiseTimeout, WA_MESSAGE_STATUS_TYPE, WAMessageStatusUpdate } from '../WAConnection/WAConnection'
|
||||
import { MessageType, Mimetype, delay, promiseTimeout, WA_MESSAGE_STATUS_TYPE, WAMessageStatusUpdate, generateMessageID, WAMessage } from '../WAConnection/WAConnection'
|
||||
import {promises as fs} from 'fs'
|
||||
import * as assert from 'assert'
|
||||
import { WAConnectionTest, testJid, sendAndRetreiveMessage, assertChatDBIntegrity } from './Common'
|
||||
@@ -168,17 +168,23 @@ WAConnectionTest('Messages', conn => {
|
||||
const content2 = await fs.readFile('./Media/cat.jpeg')
|
||||
await sendAndRetreiveMessage(conn, content2, MessageType.image)
|
||||
})
|
||||
it('should fail to send a text message', done => {
|
||||
it('should fail to send a text message', async () => {
|
||||
const JID = '1234-1234@g.us'
|
||||
conn.sendMessage(JID, 'hello', MessageType.text)
|
||||
const messageId = generateMessageID()
|
||||
conn.sendMessage(JID, 'hello', MessageType.text, { messageId })
|
||||
|
||||
conn.on ('message-status-update', async update => {
|
||||
if (update.to === JID) {
|
||||
assert.strictEqual (update.type, WA_MESSAGE_STATUS_TYPE.ERROR)
|
||||
await conn.deleteChat (JID)
|
||||
done ()
|
||||
}
|
||||
})
|
||||
await new Promise(resolve => (
|
||||
conn.on ('chat-update', async update => {
|
||||
console.log(messageId, update.messages?.first)
|
||||
if (
|
||||
update.jid === JID &&
|
||||
update.messages?.first.key.id === messageId &&
|
||||
update.messages.first.status === WA_MESSAGE_STATUS_TYPE.ERROR) {
|
||||
resolve(undefined)
|
||||
}
|
||||
})
|
||||
))
|
||||
conn.removeAllListeners('chat-update')
|
||||
})
|
||||
it('should maintain message integrity', async () => {
|
||||
// loading twice does not alter the results
|
||||
@@ -236,16 +242,17 @@ WAConnectionTest('Messages', conn => {
|
||||
}
|
||||
})
|
||||
it('should deliver a message', async () => {
|
||||
const response = await conn.sendMessage(testJid, 'My Name Jeff', MessageType.text)
|
||||
const waitForUpdate =
|
||||
promiseTimeout(15000, resolve => {
|
||||
conn.on('message-status-update', update => {
|
||||
if (update.ids.includes(response.key.id)) {
|
||||
resolve(update)
|
||||
conn.on('chat-update', update => {
|
||||
if (update.messages?.first.key.id === response.key.id) {
|
||||
resolve(update.messages.first)
|
||||
}
|
||||
})
|
||||
}) as Promise<WAMessageStatusUpdate>
|
||||
const response = await conn.sendMessage(testJid, 'My Name Jeff', MessageType.text)
|
||||
}) as Promise<WAMessage>
|
||||
|
||||
const m = await waitForUpdate
|
||||
assert.ok (m.type >= WA_MESSAGE_STATUS_TYPE.DELIVERY_ACK)
|
||||
assert.ok (m.status >= WA_MESSAGE_STATUS_TYPE.DELIVERY_ACK)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -171,7 +171,7 @@ WAConnectionTest('Misc', conn => {
|
||||
await delay (2000)
|
||||
await conn.modifyChat (testJid, ChatModification.unmute)
|
||||
})
|
||||
it('should star/unchar messages', async () => {
|
||||
it('should star/unstar messages', async () => {
|
||||
for (let i = 1; i <= 5; i++) {
|
||||
await conn.sendMessage(testJid, `Message ${i}`, MessageType.text)
|
||||
await delay(1000)
|
||||
@@ -276,7 +276,7 @@ WAConnectionTest('Misc', conn => {
|
||||
it('should detect overlaps and clear messages accordingly', async () => {
|
||||
// wait for chats
|
||||
await new Promise(resolve => (
|
||||
conn.once('chats-received', ({ hasReceivedLastMessage }) => hasReceivedLastMessage && resolve(undefined))
|
||||
conn.once('initial-data-received', resolve)
|
||||
))
|
||||
|
||||
conn.maxCachedMessages = 100
|
||||
@@ -293,18 +293,16 @@ WAConnectionTest('Misc', conn => {
|
||||
chat.messages = newMessagesDB( chat.messages.all().slice(0, 20) )
|
||||
|
||||
const task = new Promise(resolve => (
|
||||
conn.on('chats-received', ({ hasReceivedLastMessage, chatsWithMissingMessages }) => {
|
||||
if (hasReceivedLastMessage) {
|
||||
assert.strictEqual(Object.keys(chatsWithMissingMessages).length, 1)
|
||||
const missing = chatsWithMissingMessages.find(({ jid }) => jid === testJid)
|
||||
assert.ok(missing, 'missing message not detected')
|
||||
assert.strictEqual(
|
||||
conn.chats.get(testJid).messages.length,
|
||||
missing.count
|
||||
)
|
||||
assert.strictEqual(missing.count, oldCount)
|
||||
resolve(undefined)
|
||||
}
|
||||
conn.on('initial-data-received', ({ chatsWithMissingMessages }) => {
|
||||
assert.strictEqual(Object.keys(chatsWithMissingMessages).length, 1)
|
||||
const missing = chatsWithMissingMessages.find(({ jid }) => jid === testJid)
|
||||
assert.ok(missing, 'missing message not detected')
|
||||
assert.strictEqual(
|
||||
conn.chats.get(testJid).messages.length,
|
||||
missing.count
|
||||
)
|
||||
assert.strictEqual(missing.count, oldCount)
|
||||
resolve(undefined)
|
||||
})
|
||||
))
|
||||
|
||||
|
||||
@@ -61,7 +61,8 @@ export class WAConnection extends EventEmitter {
|
||||
messageLog: { tag: string, json: string, fromMe: boolean, binaryTags?: any[] }[] = []
|
||||
|
||||
maxCachedMessages = 50
|
||||
loadProfilePicturesForChatsAutomatically = true
|
||||
/** @deprecated won't be supported soon */
|
||||
loadProfilePicturesForChatsAutomatically = false
|
||||
|
||||
lastChatsReceived: Date
|
||||
chats = new KeyedDB (Utils.waChatKey(false), value => value.jid)
|
||||
@@ -207,39 +208,52 @@ export class WAConnection extends EventEmitter {
|
||||
* @param tag the tag to attach to the message
|
||||
*/
|
||||
async query(q: WAQuery): Promise<any> {
|
||||
let {json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag, requiresPhoneConnection, startDebouncedTimeout} = q
|
||||
let {json, binaryTags, tag, timeoutMs, expect200, waitForOpen, longTag, requiresPhoneConnection, startDebouncedTimeout, maxRetries} = q
|
||||
requiresPhoneConnection = requiresPhoneConnection !== false
|
||||
waitForOpen = waitForOpen !== false
|
||||
if (waitForOpen) await this.waitForConnection()
|
||||
|
||||
let triesLeft = maxRetries || 2
|
||||
tag = tag || this.generateMessageTag (longTag)
|
||||
const promise = this.waitForMessage(tag, requiresPhoneConnection, timeoutMs)
|
||||
|
||||
if (this.logger.level === 'trace') {
|
||||
this.logger.trace ({ fromMe: true },`${tag},${JSON.stringify(json)}`)
|
||||
}
|
||||
while (triesLeft >= 0) {
|
||||
if (waitForOpen) await this.waitForConnection()
|
||||
|
||||
const promise = this.waitForMessage(tag, requiresPhoneConnection, timeoutMs)
|
||||
|
||||
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag)
|
||||
else tag = await this.sendJSON(json, tag)
|
||||
|
||||
const response = await promise
|
||||
|
||||
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
||||
// read here: http://getstatuscode.com/599
|
||||
if (response.status === 599) {
|
||||
this.unexpectedDisconnect (DisconnectReason.badSession)
|
||||
const response = await this.query (q)
|
||||
return response
|
||||
if (this.logger.level === 'trace') {
|
||||
this.logger.trace ({ fromMe: true },`${tag},${JSON.stringify(json)}`)
|
||||
}
|
||||
|
||||
const message = STATUS_CODES[response.status] || 'unknown'
|
||||
throw new BaileysError (
|
||||
`Unexpected status in '${json[0] || 'generic query'}': ${STATUS_CODES[response.status]}(${response.status})`,
|
||||
{query: json, message, status: response.status}
|
||||
)
|
||||
if (binaryTags) tag = await this.sendBinary(json as WANode, binaryTags, tag)
|
||||
else tag = await this.sendJSON(json, tag)
|
||||
|
||||
try {
|
||||
const response = await promise
|
||||
if (expect200 && response.status && Math.floor(+response.status / 100) !== 2) {
|
||||
const message = STATUS_CODES[response.status] || 'unknown'
|
||||
throw new BaileysError (
|
||||
`Unexpected status in '${json[0] || 'query'}': ${STATUS_CODES[response.status]}(${response.status})`,
|
||||
{query: json, message, status: response.status}
|
||||
)
|
||||
}
|
||||
if (startDebouncedTimeout) {
|
||||
this.startDebouncedTimeout()
|
||||
}
|
||||
return response
|
||||
} catch (error) {
|
||||
if (triesLeft === 0) {
|
||||
throw error
|
||||
}
|
||||
// read here: http://getstatuscode.com/599
|
||||
if (error.status === 599) {
|
||||
this.unexpectedDisconnect (DisconnectReason.badSession)
|
||||
} else if ((error.message === 'close' || error.message === 'lost') && waitForOpen && this.state !== 'close') {
|
||||
// nothing here
|
||||
} else throw error
|
||||
|
||||
triesLeft -= 1
|
||||
this.logger.debug(`query failed due to ${error}, retrying...`)
|
||||
}
|
||||
}
|
||||
if (startDebouncedTimeout) this.startDebouncedTimeout ()
|
||||
return response
|
||||
}
|
||||
/** interval is started when a query takes too long to respond */
|
||||
protected startPhoneCheckInterval () {
|
||||
@@ -330,7 +344,7 @@ export class WAConnection extends EventEmitter {
|
||||
let onOpen: () => void
|
||||
let onClose: ({ reason }) => void
|
||||
|
||||
if (this.pendingRequestTimeoutMs <= 0) {
|
||||
if (this.pendingRequestTimeoutMs !== null && this.pendingRequestTimeoutMs <= 0) {
|
||||
throw new BaileysError(DisconnectReason.close, { status: 428 })
|
||||
}
|
||||
await (
|
||||
@@ -396,7 +410,6 @@ export class WAConnection extends EventEmitter {
|
||||
this.phoneCheckListeners = 0
|
||||
this.clearPhoneCheckInterval ()
|
||||
|
||||
|
||||
this.emit ('ws-close', { reason: DisconnectReason.close })
|
||||
|
||||
try {
|
||||
|
||||
@@ -93,33 +93,21 @@ export class WAConnection extends Base {
|
||||
this.startKeepAliveRequest()
|
||||
this.logger.info(`connected to WhatsApp Web server, authenticating via ${reconnectID ? 'reconnect' : 'takeover'}`)
|
||||
|
||||
let waitForChats: Promise<{ hasNewChats: boolean }>
|
||||
// add wait for chats promise if required
|
||||
if (options?.waitForChats) {
|
||||
const {wait, cancellations} = this.receiveChatsAndContacts(this.connectOptions.waitOnlyForLastMessage)
|
||||
waitForChats = wait
|
||||
rejections.push (...cancellations)
|
||||
}
|
||||
try {
|
||||
const [authResult, chatsResult] = await Promise.all (
|
||||
[
|
||||
this.authenticate(reconnectID),
|
||||
waitForChats || undefined
|
||||
]
|
||||
)
|
||||
const authResult = await this.authenticate(reconnectID)
|
||||
|
||||
this.conn
|
||||
.removeAllListeners('error')
|
||||
.removeAllListeners('close')
|
||||
this.stopDebouncedTimeout ()
|
||||
resolve ({ ...authResult, ...chatsResult })
|
||||
this.stopDebouncedTimeout()
|
||||
resolve(authResult)
|
||||
} catch (error) {
|
||||
reject (error)
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
this.conn.on('error', rejectAll)
|
||||
this.conn.on('close', () => rejectAll(new Error(DisconnectReason.close)))
|
||||
}) as Promise<{ hasNewChats?: boolean, isNewUser: boolean }>
|
||||
}) as Promise<{ isNewUser: boolean }>
|
||||
)
|
||||
|
||||
this.on ('ws-close', rejectAllOnWSClose)
|
||||
@@ -132,45 +120,15 @@ export class WAConnection extends Base {
|
||||
const result = await connect ()
|
||||
return result
|
||||
} catch (error) {
|
||||
this.endConnection ()
|
||||
this.endConnection()
|
||||
throw error
|
||||
} finally {
|
||||
this.off ('ws-close', rejectAllOnWSClose)
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets up callbacks to receive chats, contacts & messages.
|
||||
* Must be called immediately after connect
|
||||
*/
|
||||
protected receiveChatsAndContacts(waitOnlyForLast: boolean) {
|
||||
const rejectableWaitForEvent = (event: string) => {
|
||||
let rejectTask = (_: Error) => {}
|
||||
const task = new Promise((resolve, reject) => {
|
||||
this.once (event, data => {
|
||||
this.startDebouncedTimeout() // start timeout again
|
||||
resolve(data)
|
||||
})
|
||||
rejectTask = reject
|
||||
})
|
||||
return { reject: rejectTask, task }
|
||||
}
|
||||
const events = [ 'chats-received', 'contacts-received', 'CB:action,add:last' ]
|
||||
if (!waitOnlyForLast) events.push('CB:action,add:before', 'CB:action,add:unread')
|
||||
|
||||
const cancellations = []
|
||||
const wait = Promise.all (
|
||||
events.map (ev => {
|
||||
const {reject, task} = rejectableWaitForEvent(ev)
|
||||
cancellations.push(reject)
|
||||
return task
|
||||
})
|
||||
).then(([update]) => update as { hasNewChats: boolean })
|
||||
|
||||
return { wait, cancellations }
|
||||
}
|
||||
private onMessageRecieved(message: string | Buffer) {
|
||||
if (message[0] === '!') {
|
||||
// when the first character in the message is an '!', the server is updating the last seen
|
||||
// when the first character in the message is an '!', the server is sending a pong frame
|
||||
const timestamp = message.slice(1, message.length).toString ('utf-8')
|
||||
this.lastSeen = new Date(parseInt(timestamp))
|
||||
this.emit ('received-pong')
|
||||
|
||||
@@ -128,7 +128,7 @@ export class WAConnection extends Base {
|
||||
}
|
||||
}
|
||||
}).filter(Boolean)
|
||||
this.emit('chats-received', { hasReceivedLastMessage: true, chatsWithMissingMessages })
|
||||
this.emit('initial-data-received', { chatsWithMissingMessages })
|
||||
}
|
||||
}
|
||||
this.on('CB:action,add:last', json => messagesUpdate(json, 'last'))
|
||||
@@ -173,7 +173,6 @@ export class WAConnection extends Base {
|
||||
|
||||
this.emit('contacts-received', { updatedContacts })
|
||||
})
|
||||
|
||||
// new messages
|
||||
this.on('CB:action,add:relay,message', json => {
|
||||
const message = json[2][0][2] as WAMessage
|
||||
@@ -227,6 +226,29 @@ export class WAConnection extends Base {
|
||||
this.logger.debug ({ unhandled: true }, 'received message update for non-present message from ' + jid)
|
||||
}
|
||||
})
|
||||
this.on('CB:action,add:relay,received', json => {
|
||||
json = json[2][0][1]
|
||||
const chat = this.chats.get( whatsappID(json.jid) )
|
||||
const msg = chat?.messages.get(GET_MESSAGE_ID({ id: json.index, fromMe: json.owner === 'true' }))
|
||||
if (msg) {
|
||||
const MAP = {
|
||||
read: WA_MESSAGE_STATUS_TYPE.READ,
|
||||
message: WA_MESSAGE_STATUS_TYPE.DELIVERY_ACK,
|
||||
error: WA_MESSAGE_STATUS_TYPE.ERROR
|
||||
}
|
||||
const status = MAP[json.type]
|
||||
if (typeof status !== 'undefined') {
|
||||
if (status > msg.status || status === WA_MESSAGE_STATUS_TYPE.ERROR) {
|
||||
msg.status = status
|
||||
this.emit('chat-update', { jid: chat.jid, messages: newMessagesDB([ msg ]) })
|
||||
}
|
||||
} else {
|
||||
this.logger.warn({ update: json }, 'received unknown message status update')
|
||||
}
|
||||
} else {
|
||||
this.logger.debug ({ unhandled: true, update: json }, 'received message status update for non-present message')
|
||||
}
|
||||
})
|
||||
// If a user's contact has changed
|
||||
this.on ('CB:action,,user', json => {
|
||||
const node = json[2][0]
|
||||
@@ -266,7 +288,7 @@ export class WAConnection extends Base {
|
||||
return 'clear'
|
||||
},
|
||||
'archive': () => {
|
||||
this.chats.updateKey(chat, chat => chat.archive = 'true')
|
||||
this.chats.update(chat.jid, chat => chat.archive = 'true')
|
||||
return 'archive'
|
||||
},
|
||||
'unarchive': () => {
|
||||
@@ -294,7 +316,6 @@ export class WAConnection extends Base {
|
||||
contact.imgUrl = imgUrl
|
||||
this.emit('contact-update', { jid, imgUrl })
|
||||
}
|
||||
|
||||
const chat = this.chats.get(jid)
|
||||
if (chat) {
|
||||
chat.imgUrl = imgUrl
|
||||
@@ -305,8 +326,6 @@ export class WAConnection extends Base {
|
||||
this.on('CB:Status,status', async json => {
|
||||
const jid = whatsappID(json[1].id)
|
||||
this.emit ('contact-update', { jid, status: json[1].status })
|
||||
// emit deprecated
|
||||
this.emit ('user-status-update', { jid, status: json[1].status })
|
||||
})
|
||||
// User Profile Name Updates
|
||||
this.on ('CB:Conn,pushname', json => {
|
||||
@@ -326,41 +345,7 @@ export class WAConnection extends Base {
|
||||
else chat.count = 0
|
||||
|
||||
this.emit ('chat-update', { jid: chat.jid, count: chat.count })
|
||||
})
|
||||
this.on ('CB:action,add:relay,received', json => {
|
||||
json = json[2][0][1]
|
||||
if (json.type === 'error') {
|
||||
const update: WAMessageStatusUpdate = {
|
||||
from: this.user.jid,
|
||||
to: whatsappID(json.jid),
|
||||
participant: this.user.jid,
|
||||
timestamp: new Date(),
|
||||
ids: [ json.index ],
|
||||
type: WA_MESSAGE_STATUS_TYPE.ERROR,
|
||||
}
|
||||
this.forwardStatusUpdate (update)
|
||||
}
|
||||
})
|
||||
|
||||
const func = json => {
|
||||
json = json[1]
|
||||
let ids = json.id
|
||||
|
||||
if (json.cmd === 'ack') ids = [json.id]
|
||||
|
||||
const update: WAMessageStatusUpdate = {
|
||||
from: whatsappID(json.from),
|
||||
to: whatsappID(json.to),
|
||||
participant: whatsappID(json.participant),
|
||||
timestamp: new Date(json.t * 1000),
|
||||
ids: ids,
|
||||
type: (+json.ack)+1,
|
||||
}
|
||||
this.forwardStatusUpdate (update)
|
||||
}
|
||||
this.on('CB:Msg', func)
|
||||
this.on('CB:MsgInfo', func)
|
||||
|
||||
})
|
||||
this.on ('qr', qr => QR.generate(qr, { small: true }))
|
||||
|
||||
// blocklist updates
|
||||
@@ -380,14 +365,16 @@ export class WAConnection extends Base {
|
||||
/** Get the URL to download the profile picture of a person/group */
|
||||
@Mutex (jid => jid)
|
||||
async getProfilePicture(jid: string | null) {
|
||||
const response = await this.query({ json: ['query', 'ProfilePicThumb', jid || this.user.jid], expect200: true, requiresPhoneConnection: false })
|
||||
const response = await this.query({
|
||||
json: ['query', 'ProfilePicThumb', jid || this.user.jid],
|
||||
expect200: true,
|
||||
requiresPhoneConnection: false
|
||||
})
|
||||
return response.eurl as string
|
||||
}
|
||||
protected applyingPresenceUpdate(update: PresenceUpdate) {
|
||||
const chatId = whatsappID(update.id)
|
||||
const jid = whatsappID(update.participant || update.id)
|
||||
// emit deprecated
|
||||
this.emit('user-presence-update', update)
|
||||
|
||||
const chat = this.chats.get(chatId)
|
||||
if (chat && jid.endsWith('@s.whatsapp.net')) { // if its a single chat
|
||||
@@ -409,13 +396,6 @@ export class WAConnection extends Base {
|
||||
return { jid: chatId, presences: { [jid]: presence } } as Partial<WAChat>
|
||||
}
|
||||
}
|
||||
protected forwardStatusUpdate (update: WAMessageStatusUpdate) {
|
||||
const chat = this.chats.get( whatsappID(update.to) )
|
||||
if (!chat) return
|
||||
|
||||
this.emit ('message-status-update', update)
|
||||
this.chatUpdatedMessage (update.ids, update.type, chat)
|
||||
}
|
||||
/** inserts an empty chat into the DB */
|
||||
protected async chatAdd (jid: string, name?: string) {
|
||||
const chat: WAChat = {
|
||||
@@ -499,8 +479,6 @@ export class WAConnection extends Base {
|
||||
found.messageStubType = WA_MESSAGE_STUB_TYPE.REVOKE
|
||||
delete found.message
|
||||
chatUpdate.messages = newMessagesDB([ found ])
|
||||
// emit deprecated
|
||||
this.emit('message-update', found)
|
||||
}
|
||||
break
|
||||
default:
|
||||
@@ -529,8 +507,6 @@ export class WAConnection extends Base {
|
||||
}
|
||||
chatUpdate.hasNewMessage = true
|
||||
chatUpdate.messages = newMessagesDB([ message ])
|
||||
// emit deprecated
|
||||
this.emit('message-new', message)
|
||||
// check if the message is an action
|
||||
if (message.messageStubType) {
|
||||
const jid = chat.jid
|
||||
@@ -611,17 +587,7 @@ export class WAConnection extends Base {
|
||||
if (chat.metadata) Object.assign(chat.metadata, update)
|
||||
this.emit ('group-update', { jid, ...update })
|
||||
}
|
||||
protected chatUpdatedMessage (messageIDs: string[], status: WA_MESSAGE_STATUS_TYPE, chat: WAChat) {
|
||||
for (let id of messageIDs) {
|
||||
let msg = chat.messages.get (GET_MESSAGE_ID({ id, fromMe: true })) || chat.messages.get (GET_MESSAGE_ID({ id, fromMe: false }))
|
||||
if (msg && msg.status < status) {
|
||||
if (status <= WA_MESSAGE_STATUS_TYPE.PENDING) msg.status = status
|
||||
else if (isGroupID(chat.jid)) msg.status = status-1
|
||||
else msg.status = status
|
||||
}
|
||||
}
|
||||
}
|
||||
protected chatUpdateTime = (chat, stamp: number) => this.chats.updateKey (chat, c => c.t = stamp)
|
||||
protected chatUpdateTime = (chat, stamp: number) => this.chats.update (chat.jid, c => c.t = stamp)
|
||||
/** sets the profile picture of a chat */
|
||||
protected async setProfilePicture (chat: WAChat) {
|
||||
chat.imgUrl = await this.getProfilePicture (chat.jid).catch (err => '')
|
||||
@@ -645,39 +611,24 @@ export class WAConnection extends Base {
|
||||
on (event: 'qr', listener: (qr: string) => void): this
|
||||
/** when the connection to the phone changes */
|
||||
on (event: 'connection-phone-change', listener: (state: {connected: boolean}) => void): this
|
||||
/**
|
||||
* when a user's presence is updated
|
||||
* @deprecated use `chat-update`
|
||||
* */
|
||||
on (event: 'user-presence-update', listener: (update: PresenceUpdate) => void): this
|
||||
/**
|
||||
* when a user's status is updated
|
||||
* @deprecated use `contact-update`
|
||||
*/
|
||||
on (event: 'user-status-update', listener: (update: {jid: string, status?: string}) => void): this
|
||||
/** when a user's status is updated */
|
||||
/** when a contact is updated */
|
||||
on (event: 'contact-update', listener: (update: WAContactUpdate) => void): this
|
||||
/** when a new chat is added */
|
||||
on (event: 'chat-new', listener: (chat: WAChat) => void): this
|
||||
/** when contacts are sent by WA */
|
||||
on (event: 'contacts-received', listener: (u: { updatedContacts: Partial<WAContact>[] }) => void): this
|
||||
/** when chats are sent by WA, and when all messages are received */
|
||||
on (event: 'chats-received', listener: (update: {hasNewChats?: boolean, hasReceivedLastMessage?: boolean, chatsWithMissingMessages: { jid: string, count: number }[] }) => void): this
|
||||
on (event: 'chats-received', listener: (update: {hasNewChats?: boolean}) => void): this
|
||||
/** when all initial messages are received from WA */
|
||||
on (event: 'initial-data-received', listener: (update: {chatsWithMissingMessages: { jid: string, count: number }[] }) => void): this
|
||||
/** when multiple chats are updated (new message, updated message, deleted, pinned, etc) */
|
||||
on (event: 'chats-update', listener: (chats: WAChatUpdate[]) => void): this
|
||||
/** when a chat is updated (new message, updated message, deleted, pinned, presence updated etc) */
|
||||
/** when a chat is updated (new message, updated message, read message, deleted, pinned, presence updated etc) */
|
||||
on (event: 'chat-update', listener: (chat: WAChatUpdate) => void): this
|
||||
/**
|
||||
* when a new message is relayed
|
||||
* @deprecated use `chat-update`
|
||||
* when a message's status is updated (deleted, delivered, read, sent etc.)
|
||||
* @deprecated will not be called anymore. Use `chat-update`
|
||||
* */
|
||||
on (event: 'message-new', listener: (message: WAMessage) => void): this
|
||||
/**
|
||||
* when a message object itself is updated (receives its media info or is deleted)
|
||||
* @deprecated use `chat-update`
|
||||
* */
|
||||
on (event: 'message-update', listener: (message: WAMessage) => void): this
|
||||
/** when a message's status is updated (deleted, delivered, read, sent etc.) */
|
||||
on (event: 'message-status-update', listener: (message: WAMessageStatusUpdate) => void): this
|
||||
/** when participants are added to a group */
|
||||
on (event: 'group-participants-update', listener: (update: {jid: string, participants: string[], actor?: string, action: WAParticipantAction}) => void): this
|
||||
|
||||
@@ -65,6 +65,7 @@ export interface WAQuery {
|
||||
longTag?: boolean
|
||||
requiresPhoneConnection?: boolean
|
||||
startDebouncedTimeout?: boolean
|
||||
maxRetries?: number
|
||||
}
|
||||
export enum ReconnectMode {
|
||||
/** does not reconnect */
|
||||
@@ -80,25 +81,10 @@ export type WALoadChatOptions = {
|
||||
loadProfilePicture?: boolean
|
||||
}
|
||||
export type WAConnectOptions = {
|
||||
/**
|
||||
* New QR generation interval, set to null if you don't want to regenerate
|
||||
* @deprecated no need to set this as we use WA ttl
|
||||
* */
|
||||
regenerateQRIntervalMs?: number
|
||||
/** fails the connection if no data is received for X seconds */
|
||||
maxIdleTimeMs?: number
|
||||
/** maximum attempts to connect */
|
||||
maxRetries?: number
|
||||
/**
|
||||
* @deprecated -- use the `chats-received` & `contacts-received` events
|
||||
* should the chats be waited for
|
||||
* */
|
||||
waitForChats?: boolean
|
||||
/**
|
||||
* @deprecated -- use the `chats-received` & `contacts-received` events
|
||||
* if set to true, the connect only waits for the last message of the chat
|
||||
* */
|
||||
waitOnlyForLastMessage?: boolean
|
||||
/** max time for the phone to respond to a connectivity test */
|
||||
phoneResponseTime?: number
|
||||
connectCooldownMs?: number
|
||||
@@ -465,16 +451,15 @@ export type BaileysEvent =
|
||||
'close' |
|
||||
'ws-close' |
|
||||
'qr' |
|
||||
'connection-validated' |
|
||||
'connection-phone-change' |
|
||||
'contacts-received' |
|
||||
'chats-received' |
|
||||
'chat-new' |
|
||||
'chat-update' |
|
||||
'message-status-update' |
|
||||
'group-participants-update' |
|
||||
'group-update' |
|
||||
'received-pong' |
|
||||
'credentials-updated' |
|
||||
'connection-validated' |
|
||||
'blocklist-update' |
|
||||
'contact-update'
|
||||
Reference in New Issue
Block a user