Slint fixes applied

This commit is contained in:
Rafael Garcia
2023-05-15 09:41:33 -05:00
parent 464ffd23b4
commit 3ac29e131d
7 changed files with 327 additions and 338 deletions

View File

@@ -23,7 +23,7 @@ setInterval(() => {
}, 10_000)
// start a connection
const startSock = async () => {
const startSock = async() => {
const { state, saveCreds } = await useMultiFileAuthState('baileys_auth_info')
// fetch latest version of WA Web
const { version, isLatest } = await fetchLatestBaileysVersion()
@@ -49,7 +49,7 @@ const startSock = async () => {
store?.bind(sock.ev)
const sendMessageWTyping = async (msg: AnyMessageContent, jid: string) => {
const sendMessageWTyping = async(msg: AnyMessageContent, jid: string) => {
await sock.presenceSubscribe(jid)
await delay(500)
@@ -65,15 +65,15 @@ const startSock = async () => {
// efficiently in a batch
sock.ev.process(
// events is a map for event name => event data
async (events) => {
async(events) => {
// something about the connection changed
// maybe it closed, or we received all offline message or connection opened
if (events['connection.update']) {
if(events['connection.update']) {
const update = events['connection.update']
const { connection, lastDisconnect } = update
if (connection === 'close') {
if(connection === 'close') {
// reconnect if not logged out
if ((lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut) {
if((lastDisconnect?.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut) {
startSock()
} else {
console.log('Connection closed. You are logged out.')
@@ -84,37 +84,37 @@ const startSock = async () => {
}
// credentials updated -- save them
if (events['creds.update']) {
if(events['creds.update']) {
await saveCreds()
}
if (events['labels.association']) {
if(events['labels.association']) {
console.log(events['labels.association'])
}
if (events['labels.edit']) {
if(events['labels.edit']) {
console.log(events['labels.edit'])
}
if (events.call) {
if(events.call) {
console.log('recv call event', events.call)
}
// history received
if (events['messaging-history.set']) {
if(events['messaging-history.set']) {
const { chats, contacts, messages, isLatest } = events['messaging-history.set']
console.log(`recv ${chats.length} chats, ${contacts.length} contacts, ${messages.length} msgs (is latest: ${isLatest})`)
}
// received a new message
if (events['messages.upsert']) {
if(events['messages.upsert']) {
const upsert = events['messages.upsert']
console.log('recv messages ', JSON.stringify(upsert, undefined, 2))
if (upsert.type === 'notify') {
for (const msg of upsert.messages) {
if (!msg.key.fromMe && doReplies) {
if(upsert.type === 'notify') {
for(const msg of upsert.messages) {
if(!msg.key.fromMe && doReplies) {
console.log('replying to', msg.key.remoteJid)
await sock!.readMessages([msg.key])
await sendMessageWTyping({ text: 'Hello there!' }, msg.key.remoteJid!)
@@ -124,15 +124,15 @@ const startSock = async () => {
}
// messages updated like status delivered, message deleted etc.
if (events['messages.update']) {
if(events['messages.update']) {
console.log(
JSON.stringify(events['messages.update'], undefined, 2)
)
for (const { key, update } of events['messages.update']) {
if (update.pollUpdates) {
for(const { key, update } of events['messages.update']) {
if(update.pollUpdates) {
const pollCreation = await getMessage(key)
if (pollCreation) {
if(pollCreation) {
console.log(
'got poll update, aggregation: ',
getAggregateVotesInPollMessage({
@@ -145,25 +145,25 @@ const startSock = async () => {
}
}
if (events['message-receipt.update']) {
if(events['message-receipt.update']) {
console.log(events['message-receipt.update'])
}
if (events['messages.reaction']) {
if(events['messages.reaction']) {
console.log(events['messages.reaction'])
}
if (events['presence.update']) {
if(events['presence.update']) {
console.log(events['presence.update'])
}
if (events['chats.update']) {
if(events['chats.update']) {
console.log(events['chats.update'])
}
if (events['contacts.update']) {
for (const contact of events['contacts.update']) {
if (typeof contact.imgUrl !== 'undefined') {
if(events['contacts.update']) {
for(const contact of events['contacts.update']) {
if(typeof contact.imgUrl !== 'undefined') {
const newUrl = contact.imgUrl === null
? null
: await sock!.profilePictureUrl(contact.id!).catch(() => null)
@@ -174,7 +174,7 @@ const startSock = async () => {
}
}
if (events['chats.delete']) {
if(events['chats.delete']) {
console.log('chats deleted ', events['chats.delete'])
}
}
@@ -183,7 +183,7 @@ const startSock = async () => {
return sock
async function getMessage(key: WAMessageKey): Promise<WAMessageContent | undefined> {
if (store) {
if(store) {
const msg = await store.loadMessage(key.remoteJid!, key.id!)
return msg?.message || undefined
}

View File

@@ -37,13 +37,13 @@ export const makeChatsSocket = (config: SocketConfig) => {
const processingMutex = makeMutex()
/** helper function to fetch the given app state sync key */
const getAppStateSyncKey = async (keyId: string) => {
const getAppStateSyncKey = async(keyId: string) => {
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId])
return key
}
const fetchPrivacySettings = async (force: boolean = false) => {
if (!privacySettings || force) {
const fetchPrivacySettings = async(force: boolean = false) => {
if(!privacySettings || force) {
const { content } = await query({
tag: 'iq',
attrs: {
@@ -62,7 +62,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** helper function to run a privacy IQ query */
const privacyQuery = async (name: string, value: string) => {
const privacyQuery = async(name: string, value: string) => {
await query({
tag: 'iq',
attrs: {
@@ -83,31 +83,31 @@ export const makeChatsSocket = (config: SocketConfig) => {
})
}
const updateLastSeenPrivacy = async (value: WAPrivacyValue) => {
const updateLastSeenPrivacy = async(value: WAPrivacyValue) => {
await privacyQuery('last', value)
}
const updateOnlinePrivacy = async (value: WAPrivacyOnlineValue) => {
const updateOnlinePrivacy = async(value: WAPrivacyOnlineValue) => {
await privacyQuery('online', value)
}
const updateProfilePicturePrivacy = async (value: WAPrivacyValue) => {
const updateProfilePicturePrivacy = async(value: WAPrivacyValue) => {
await privacyQuery('profile', value)
}
const updateStatusPrivacy = async (value: WAPrivacyValue) => {
const updateStatusPrivacy = async(value: WAPrivacyValue) => {
await privacyQuery('status', value)
}
const updateReadReceiptsPrivacy = async (value: WAReadReceiptsValue) => {
const updateReadReceiptsPrivacy = async(value: WAReadReceiptsValue) => {
await privacyQuery('readreceipts', value)
}
const updateGroupsAddPrivacy = async (value: WAPrivacyValue) => {
const updateGroupsAddPrivacy = async(value: WAPrivacyValue) => {
await privacyQuery('groupadd', value)
}
const updateDefaultDisappearingMode = async (duration: number) => {
const updateDefaultDisappearingMode = async(duration: number) => {
await query({
tag: 'iq',
attrs: {
@@ -125,7 +125,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** helper function to run a generic IQ query */
const interactiveQuery = async (userNodes: BinaryNode[], queryNode: BinaryNode) => {
const interactiveQuery = async(userNodes: BinaryNode[], queryNode: BinaryNode) => {
const result = await query({
tag: 'iq',
attrs: {
@@ -166,7 +166,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
return users
}
const onWhatsApp = async (...jids: string[]) => {
const onWhatsApp = async(...jids: string[]) => {
const results = await interactiveQuery(
[
{
@@ -190,12 +190,12 @@ export const makeChatsSocket = (config: SocketConfig) => {
}).filter(item => item.exists)
}
const fetchStatus = async (jid: string) => {
const fetchStatus = async(jid: string) => {
const [result] = await interactiveQuery(
[{ tag: 'user', attrs: { jid } }],
{ tag: 'status', attrs: {} }
)
if (result) {
if(result) {
const status = getBinaryNodeChild(result, 'status')
return {
status: status?.content!.toString(),
@@ -205,7 +205,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** update the profile picture for yourself or a group */
const updateProfilePicture = async (jid: string, content: WAMediaUpload) => {
const updateProfilePicture = async(jid: string, content: WAMediaUpload) => {
const { img } = await generateProfilePicture(content)
await query({
tag: 'iq',
@@ -225,7 +225,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** remove the profile picture for yourself or a group */
const removeProfilePicture = async (jid: string) => {
const removeProfilePicture = async(jid: string) => {
await query({
tag: 'iq',
attrs: {
@@ -237,7 +237,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** update the profile status for yourself */
const updateProfileStatus = async (status: string) => {
const updateProfileStatus = async(status: string) => {
await query({
tag: 'iq',
attrs: {
@@ -255,11 +255,11 @@ export const makeChatsSocket = (config: SocketConfig) => {
})
}
const updateProfileName = async (name: string) => {
const updateProfileName = async(name: string) => {
await chatModify({ pushNameSetting: name }, '')
}
const fetchBlocklist = async () => {
const fetchBlocklist = async() => {
const result = await query({
tag: 'iq',
attrs: {
@@ -274,7 +274,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
.map(n => n.attrs.jid)
}
const updateBlockStatus = async (jid: string, action: 'block' | 'unblock') => {
const updateBlockStatus = async(jid: string, action: 'block' | 'unblock') => {
await query({
tag: 'iq',
attrs: {
@@ -294,7 +294,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
})
}
const getBusinessProfile = async (jid: string): Promise<WABusinessProfile | void> => {
const getBusinessProfile = async(jid: string): Promise<WABusinessProfile | void> => {
const results = await query({
tag: 'iq',
attrs: {
@@ -314,7 +314,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
const profileNode = getBinaryNodeChild(results, 'business_profile')
const profiles = getBinaryNodeChild(profileNode, 'profile')
if (profiles) {
if(profiles) {
const address = getBinaryNodeChild(profiles, 'address')
const description = getBinaryNodeChild(profiles, 'description')
const website = getBinaryNodeChild(profiles, 'website')
@@ -340,7 +340,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
}
const updateAccountSyncTimestamp = async (fromTimestamp: number | string) => {
const updateAccountSyncTimestamp = async(fromTimestamp: number | string) => {
logger.info({ fromTimestamp }, 'requesting account sync')
await sendNode({
tag: 'iq',
@@ -376,30 +376,30 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
}
const resyncAppState = ev.createBufferedFunction(async (collections: readonly WAPatchName[], isInitialSync: boolean) => {
const resyncAppState = ev.createBufferedFunction(async(collections: readonly WAPatchName[], isInitialSync: boolean) => {
// we use this to determine which events to fire
// otherwise when we resync from scratch -- all notifications will fire
const initialVersionMap: { [T in WAPatchName]?: number } = {}
const globalMutationMap: ChatMutationMap = {}
await authState.keys.transaction(
async () => {
async() => {
const collectionsToHandle = new Set<string>(collections)
// in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
const attemptsMap: { [T in WAPatchName]?: number } = {}
// keep executing till all collections are done
// sometimes a single patch request will not return all the patches (God knows why)
// so we fetch till they're all done (this is determined by the "has_more_patches" flag)
while (collectionsToHandle.size) {
while(collectionsToHandle.size) {
const states = {} as { [T in WAPatchName]: LTHashState }
const nodes: BinaryNode[] = []
for (const name of collectionsToHandle) {
for(const name of collectionsToHandle) {
const result = await authState.keys.get('app-state-sync-version', [name])
let state = result[name]
if (state) {
if (typeof initialVersionMap[name] === 'undefined') {
if(state) {
if(typeof initialVersionMap[name] === 'undefined') {
initialVersionMap[name] = state.version
}
} else {
@@ -439,11 +439,11 @@ export const makeChatsSocket = (config: SocketConfig) => {
// extract from binary node
const decoded = await extractSyncdPatches(result, config?.options)
for (const key in decoded) {
for(const key in decoded) {
const name = key as WAPatchName
const { patches, hasMorePatches, snapshot } = decoded[name]
try {
if (snapshot) {
if(snapshot) {
const { state: newState, mutationMap } = await decodeSyncdSnapshot(
name,
snapshot,
@@ -460,7 +460,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
// only process if there are syncd patches
if (patches.length) {
if(patches.length) {
const { state: newState, mutationMap } = await decodePatches(
name,
patches,
@@ -480,12 +480,12 @@ export const makeChatsSocket = (config: SocketConfig) => {
Object.assign(globalMutationMap, mutationMap)
}
if (hasMorePatches) {
if(hasMorePatches) {
logger.info(`${name} has more patches...`)
} else { // collection is done with sync
collectionsToHandle.delete(name)
}
} catch (error) {
} catch(error) {
// if retry attempts overshoot
// or key not found
const isIrrecoverableError = attemptsMap[name]! >= MAX_SYNC_ATTEMPTS
@@ -499,7 +499,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
// increment number of retries
attemptsMap[name] = (attemptsMap[name] || 0) + 1
if (isIrrecoverableError) {
if(isIrrecoverableError) {
// stop retrying
collectionsToHandle.delete(name)
}
@@ -510,7 +510,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
)
const { onMutation } = newAppStateChunkHandler(isInitialSync)
for (const key in globalMutationMap) {
for(const key in globalMutationMap) {
onMutation(globalMutationMap[key])
}
})
@@ -520,7 +520,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
* type = "preview" for a low res picture
* type = "image for the high res picture"
*/
const profilePictureUrl = async (jid: string, type: 'preview' | 'image' = 'preview', timeoutMs?: number) => {
const profilePictureUrl = async(jid: string, type: 'preview' | 'image' = 'preview', timeoutMs?: number) => {
jid = jidNormalizedUser(jid)
const result = await query({
tag: 'iq',
@@ -537,10 +537,10 @@ export const makeChatsSocket = (config: SocketConfig) => {
return child?.attrs?.url
}
const sendPresenceUpdate = async (type: WAPresence, toJid?: string) => {
const sendPresenceUpdate = async(type: WAPresence, toJid?: string) => {
const me = authState.creds.me!
if (type === 'available' || type === 'unavailable') {
if (!me!.name) {
if(type === 'available' || type === 'unavailable') {
if(!me!.name) {
logger.warn('no name present, ignoring presence update request...')
return
}
@@ -600,23 +600,23 @@ export const makeChatsSocket = (config: SocketConfig) => {
const jid = attrs.from
const participant = attrs.participant || attrs.from
if (shouldIgnoreJid(jid)) {
if(shouldIgnoreJid(jid)) {
return
}
if (tag === 'presence') {
if(tag === 'presence') {
presence = {
lastKnownPresence: attrs.type === 'unavailable' ? 'unavailable' : 'available',
lastSeen: attrs.last && attrs.last !== 'deny' ? +attrs.last : undefined
}
} else if (Array.isArray(content)) {
} else if(Array.isArray(content)) {
const [firstChild] = content
let type = firstChild.tag as WAPresence
if (type === 'paused') {
if(type === 'paused') {
type = 'available'
}
if (firstChild.attrs?.media === 'audio') {
if(firstChild.attrs?.media === 'audio') {
type = 'recording'
}
@@ -625,15 +625,15 @@ export const makeChatsSocket = (config: SocketConfig) => {
logger.error({ tag, attrs, content }, 'recv invalid presence node')
}
if (presence) {
if(presence) {
ev.emit('presence.update', { id: jid, presences: { [participant]: presence } })
}
}
const appPatch = async (patchCreate: WAPatchCreate) => {
const appPatch = async(patchCreate: WAPatchCreate) => {
const name = patchCreate.type
const myAppStateKeyId = authState.creds.myAppStateKeyId
if (!myAppStateKeyId) {
if(!myAppStateKeyId) {
throw new Boom('App state key not present!', { statusCode: 400 })
}
@@ -641,9 +641,9 @@ export const makeChatsSocket = (config: SocketConfig) => {
let encodeResult: { patch: proto.ISyncdPatch, state: LTHashState }
await processingMutex.mutex(
async () => {
async() => {
await authState.keys.transaction(
async () => {
async() => {
logger.debug({ patch: patchCreate }, 'applying app patch')
await resyncAppState([name], false)
@@ -698,7 +698,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
)
if (config.emitOwnEvents) {
if(config.emitOwnEvents) {
const { onMutation } = newAppStateChunkHandler(false)
const { mutationMap } = await decodePatches(
name,
@@ -709,14 +709,14 @@ export const makeChatsSocket = (config: SocketConfig) => {
undefined,
logger,
)
for (const key in mutationMap) {
for(const key in mutationMap) {
onMutation(mutationMap[key])
}
}
}
/** sending abt props may fix QR scan fail if server expects */
const fetchAbt = async () => {
const fetchAbt = async() => {
const abtNode = await query({
tag: 'iq',
attrs: {
@@ -732,7 +732,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
const propsNode = getBinaryNodeChild(abtNode, 'props')
let props: { [_: string]: string } = {}
if (propsNode) {
if(propsNode) {
props = reduceBinaryNodeToDictionary(propsNode, 'prop')
}
@@ -742,7 +742,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
/** sending non-abt props may fix QR scan fail if server expects */
const fetchProps = async () => {
const fetchProps = async() => {
const resultNode = await query({
tag: 'iq',
attrs: {
@@ -758,7 +758,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
const propsNode = getBinaryNodeChild(resultNode, 'props')
let props: { [_: string]: string } = {}
if (propsNode) {
if(propsNode) {
props = reduceBinaryNodeToDictionary(propsNode, 'prop')
}
@@ -827,7 +827,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
* queries need to be fired on connection open
* help ensure parity with WA Web
* */
const executeInitQueries = async () => {
const executeInitQueries = async() => {
await Promise.all([
fetchAbt(),
fetchProps(),
@@ -836,19 +836,19 @@ export const makeChatsSocket = (config: SocketConfig) => {
])
}
const upsertMessage = ev.createBufferedFunction(async (msg: WAMessage, type: MessageUpsertType) => {
const upsertMessage = ev.createBufferedFunction(async(msg: WAMessage, type: MessageUpsertType) => {
ev.emit('messages.upsert', { messages: [msg], type })
if (!!msg.pushName) {
if(!!msg.pushName) {
let jid = msg.key.fromMe ? authState.creds.me!.id : (msg.key.participant || msg.key.remoteJid)
jid = jidNormalizedUser(jid!)
if (!msg.key.fromMe) {
if(!msg.key.fromMe) {
ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName! }])
}
// update our pushname too
if (msg.key.fromMe && msg.pushName && authState.creds.me?.name !== msg.pushName) {
if(msg.key.fromMe && msg.pushName && authState.creds.me?.name !== msg.pushName) {
ev.emit('creds.update', { me: { ...authState.creds.me!, name: msg.pushName! } })
}
}
@@ -861,14 +861,14 @@ export const makeChatsSocket = (config: SocketConfig) => {
)
: false
if (historyMsg && !authState.creds.myAppStateKeyId) {
if(historyMsg && !authState.creds.myAppStateKeyId) {
logger.warn('skipping app state sync, as myAppStateKeyId is not set')
pendingAppStateSync = true
}
await Promise.all([
(async () => {
if (
(async() => {
if(
historyMsg
&& authState.creds.myAppStateKeyId
) {
@@ -890,7 +890,7 @@ export const makeChatsSocket = (config: SocketConfig) => {
)
])
if (
if(
msg.message?.protocolMessage?.appStateSyncKeyShare
&& pendingAppStateSync
) {
@@ -899,14 +899,14 @@ export const makeChatsSocket = (config: SocketConfig) => {
}
async function doAppStateSync() {
if (!authState.creds.accountSyncCounter) {
if(!authState.creds.accountSyncCounter) {
logger.info('doing initial app state sync')
await resyncAppState(ALL_WA_PATCH_NAMES, true)
const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1
ev.emit('creds.update', { accountSyncCounter })
if (needToFlushWithAppStateSync) {
if(needToFlushWithAppStateSync) {
logger.debug('flushing with app state sync')
ev.flush()
}
@@ -917,31 +917,31 @@ export const makeChatsSocket = (config: SocketConfig) => {
ws.on('CB:presence', handlePresenceUpdate)
ws.on('CB:chatstate', handlePresenceUpdate)
ws.on('CB:ib,,dirty', async (node: BinaryNode) => {
ws.on('CB:ib,,dirty', async(node: BinaryNode) => {
const { attrs } = getBinaryNodeChild(node, 'dirty')!
const type = attrs.type
switch (type) {
case 'account_sync':
if (attrs.timestamp) {
let { lastAccountSyncTimestamp } = authState.creds
if (lastAccountSyncTimestamp) {
await updateAccountSyncTimestamp(lastAccountSyncTimestamp)
}
lastAccountSyncTimestamp = +attrs.timestamp
ev.emit('creds.update', { lastAccountSyncTimestamp })
case 'account_sync':
if(attrs.timestamp) {
let { lastAccountSyncTimestamp } = authState.creds
if(lastAccountSyncTimestamp) {
await updateAccountSyncTimestamp(lastAccountSyncTimestamp)
}
break
default:
logger.info({ node }, 'received unknown sync')
break
lastAccountSyncTimestamp = +attrs.timestamp
ev.emit('creds.update', { lastAccountSyncTimestamp })
}
break
default:
logger.info({ node }, 'received unknown sync')
break
}
})
ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
if (connection === 'open') {
if (fireInitQueries) {
if(connection === 'open') {
if(fireInitQueries) {
executeInitQueries()
.catch(
error => onUnexpectedError(error, 'init queries')
@@ -954,11 +954,11 @@ export const makeChatsSocket = (config: SocketConfig) => {
)
}
if (receivedPendingNotifications) {
if(receivedPendingNotifications) {
// if we don't have the app state key
// we keep buffering events until we finally have
// the key and can sync the messages
if (!authState.creds?.myAppStateKeyId) {
if(!authState.creds?.myAppStateKeyId) {
ev.buffer()
needToFlushWithAppStateSync = true
}

View File

@@ -91,7 +91,7 @@ export default (
const labelAssociations = new KeyedDB<LabelAssociation, string>(labelAssociationKey, labelAssociationKey.key)
const assertMessageList = (jid: string) => {
if (!messages[jid]) {
if(!messages[jid]) {
messages[jid] = makeMessagesDictionary()
}
@@ -100,7 +100,7 @@ export default (
const contactsUpsert = (newContacts: Contact[]) => {
const oldContacts = new Set(Object.keys(contacts))
for (const contact of newContacts) {
for(const contact of newContacts) {
oldContacts.delete(contact.id)
contacts[contact.id] = Object.assign(
contacts[contact.id] || {},
@@ -112,7 +112,7 @@ export default (
}
const labelsUpsert = (newLabels: Label[]) => {
for (const label of newLabels) {
for(const label of newLabels) {
labels.upsertById(label.id, label)
}
}
@@ -134,10 +134,10 @@ export default (
messages: newMessages,
isLatest
}) => {
if (isLatest) {
if(isLatest) {
chats.clear()
for (const id in messages) {
for(const id in messages) {
delete messages[id]
}
}
@@ -146,13 +146,13 @@ export default (
logger.debug({ chatsAdded }, 'synced chats')
const oldContacts = contactsUpsert(newContacts)
for (const jid of oldContacts) {
for(const jid of oldContacts) {
delete contacts[jid]
}
logger.debug({ deletedContacts: oldContacts.size, newContacts }, 'synced contacts')
for (const msg of newMessages) {
for(const msg of newMessages) {
const jid = msg.key.remoteJid!
const list = assertMessageList(jid)
list.upsert(msg, 'prepend')
@@ -162,8 +162,8 @@ export default (
})
ev.on('contacts.update', updates => {
for (const update of updates) {
if (contacts[update.id!]) {
for(const update of updates) {
if(contacts[update.id!]) {
Object.assign(contacts[update.id!], update)
} else {
logger.debug({ update }, 'got update for non-existant contact')
@@ -174,28 +174,28 @@ export default (
chats.upsert(...newChats)
})
ev.on('chats.update', updates => {
for (let update of updates) {
for(let update of updates) {
const result = chats.update(update.id!, chat => {
if (update.unreadCount! > 0) {
if(update.unreadCount! > 0) {
update = { ...update }
update.unreadCount = (chat.unreadCount || 0) + update.unreadCount!
}
Object.assign(chat, update)
})
if (!result) {
if(!result) {
logger.debug({ update }, 'got update for non-existant chat')
}
}
})
ev.on('labels.edit', (label: Label) => {
if (label.deleted) {
if(label.deleted) {
return labels.deleteById(label.id)
}
// WhatsApp can store only up to 20 labels
if (labels.count() < 20) {
if(labels.count() < 20) {
return labels.upsertById(label.id, label)
}
@@ -204,14 +204,14 @@ export default (
ev.on('labels.association', ({ type, association }) => {
switch (type) {
case 'add':
labelAssociations.upsert(association)
break
case 'remove':
labelAssociations.delete(association)
break
default:
console.error(`unknown operation type [${type}]`)
case 'add':
labelAssociations.upsert(association)
break
case 'remove':
labelAssociations.delete(association)
break
default:
console.error(`unknown operation type [${type}]`)
}
})
@@ -220,52 +220,52 @@ export default (
Object.assign(presences[id], update)
})
ev.on('chats.delete', deletions => {
for (const item of deletions) {
for(const item of deletions) {
chats.deleteById(item)
}
})
ev.on('messages.upsert', ({ messages: newMessages, type }) => {
switch (type) {
case 'append':
case 'notify':
for (const msg of newMessages) {
const jid = jidNormalizedUser(msg.key.remoteJid!)
const list = assertMessageList(jid)
list.upsert(msg, 'append')
case 'append':
case 'notify':
for(const msg of newMessages) {
const jid = jidNormalizedUser(msg.key.remoteJid!)
const list = assertMessageList(jid)
list.upsert(msg, 'append')
if (type === 'notify') {
if (!chats.get(jid)) {
ev.emit('chats.upsert', [
{
id: jid,
conversationTimestamp: toNumber(msg.messageTimestamp),
unreadCount: 1
}
])
}
if(type === 'notify') {
if(!chats.get(jid)) {
ev.emit('chats.upsert', [
{
id: jid,
conversationTimestamp: toNumber(msg.messageTimestamp),
unreadCount: 1
}
])
}
}
}
break
break
}
})
ev.on('messages.update', updates => {
for (const { update, key } of updates) {
for(const { update, key } of updates) {
const list = assertMessageList(key.remoteJid!)
const result = list.updateAssign(key.id!, update)
if (!result) {
if(!result) {
logger.debug({ update }, 'got update for non-existent message')
}
}
})
ev.on('messages.delete', item => {
if ('all' in item) {
if('all' in item) {
const list = messages[item.jid]
list?.clear()
} else {
const jid = item.keys[0].remoteJid!
const list = messages[jid]
if (list) {
if(list) {
const idSet = new Set(item.keys.map(k => k.id))
list.filter(m => !idSet.has(m.key.id))
}
@@ -273,9 +273,9 @@ export default (
})
ev.on('groups.update', updates => {
for (const update of updates) {
for(const update of updates) {
const id = update.id!
if (groupMetadata[id]) {
if(groupMetadata[id]) {
Object.assign(groupMetadata[id], update)
} else {
logger.debug({ update }, 'got update for non-existant group metadata')
@@ -285,42 +285,42 @@ export default (
ev.on('group-participants.update', ({ id, participants, action }) => {
const metadata = groupMetadata[id]
if (metadata) {
if(metadata) {
switch (action) {
case 'add':
metadata.participants.push(...participants.map(id => ({ id, isAdmin: false, isSuperAdmin: false })))
break
case 'demote':
case 'promote':
for (const participant of metadata.participants) {
if (participants.includes(participant.id)) {
participant.isAdmin = action === 'promote'
}
case 'add':
metadata.participants.push(...participants.map(id => ({ id, isAdmin: false, isSuperAdmin: false })))
break
case 'demote':
case 'promote':
for(const participant of metadata.participants) {
if(participants.includes(participant.id)) {
participant.isAdmin = action === 'promote'
}
}
break
case 'remove':
metadata.participants = metadata.participants.filter(p => !participants.includes(p.id))
break
break
case 'remove':
metadata.participants = metadata.participants.filter(p => !participants.includes(p.id))
break
}
}
})
ev.on('message-receipt.update', updates => {
for (const { key, receipt } of updates) {
for(const { key, receipt } of updates) {
const obj = messages[key.remoteJid!]
const msg = obj?.get(key.id!)
if (msg) {
if(msg) {
updateMessageWithReceipt(msg, receipt)
}
}
})
ev.on('messages.reaction', (reactions) => {
for (const { key, reaction } of reactions) {
for(const { key, reaction } of reactions) {
const obj = messages[key.remoteJid!]
const msg = obj?.get(key.id!)
if (msg) {
if(msg) {
updateMessageWithReaction(msg, reaction)
}
}
@@ -335,20 +335,14 @@ export default (
labelAssociations
})
const fromJSON = (json: {
chats: Chat[],
contacts: { [id: string]: Contact },
messages: { [id: string]: WAMessage[] },
labels: { [labelId: string]: Label },
labelAssociations: LabelAssociation[]
}) => {
const fromJSON = (json: {chats: Chat[], contacts: { [id: string]: Contact }, messages: { [id: string]: WAMessage[] }, labels: { [labelId: string]: Label }, labelAssociations: LabelAssociation[]}) => {
chats.upsert(...json.chats)
labelAssociations.upsert(...json.labelAssociations || [])
contactsUpsert(Object.values(json.contacts))
labelsUpsert(Object.values(json.labels || {}))
for (const jid in json.messages) {
for(const jid in json.messages) {
const list = assertMessageList(jid)
for (const msg of json.messages[jid]) {
for(const msg of json.messages[jid]) {
list.upsert(proto.WebMessageInfo.fromObject(msg), 'append')
}
}
@@ -366,15 +360,15 @@ export default (
labelAssociations,
bind,
/** loads messages from the store, if not found -- uses the legacy connection */
loadMessages: async (jid: string, count: number, cursor: WAMessageCursor) => {
loadMessages: async(jid: string, count: number, cursor: WAMessageCursor) => {
const list = assertMessageList(jid)
const mode = !cursor || 'before' in cursor ? 'before' : 'after'
const cursorKey = !!cursor ? ('before' in cursor ? cursor.before : cursor.after) : undefined
const cursorValue = cursorKey ? list.get(cursorKey.id!) : undefined
let messages: WAMessage[]
if (list && mode === 'before' && (!cursorKey || cursorValue)) {
if (cursorValue) {
if(list && mode === 'before' && (!cursorKey || cursorValue)) {
if(cursorValue) {
const msgIdx = list.array.findIndex(m => m.key.id === cursorKey?.id)
messages = list.array.slice(0, msgIdx)
} else {
@@ -382,7 +376,7 @@ export default (
}
const diff = count - messages.length
if (diff < 0) {
if(diff < 0) {
messages = messages.slice(-count) // get the last X messages
}
} else {
@@ -423,27 +417,27 @@ export default (
return associations.map(({ labelId }) => labelId)
},
loadMessage: async (jid: string, id: string) => messages[jid]?.get(id),
mostRecentMessage: async (jid: string) => {
loadMessage: async(jid: string, id: string) => messages[jid]?.get(id),
mostRecentMessage: async(jid: string) => {
const message: WAMessage | undefined = messages[jid]?.array.slice(-1)[0]
return message
},
fetchImageUrl: async (jid: string, sock: WASocket | undefined) => {
fetchImageUrl: async(jid: string, sock: WASocket | undefined) => {
const contact = contacts[jid]
if (!contact) {
if(!contact) {
return sock?.profilePictureUrl(jid)
}
if (typeof contact.imgUrl === 'undefined') {
if(typeof contact.imgUrl === 'undefined') {
contact.imgUrl = await sock?.profilePictureUrl(jid)
}
return contact.imgUrl
},
fetchGroupMetadata: async (jid: string, sock: WASocket | undefined) => {
if (!groupMetadata[jid]) {
fetchGroupMetadata: async(jid: string, sock: WASocket | undefined) => {
if(!groupMetadata[jid]) {
const metadata = await sock?.groupMetadata(jid)
if (metadata) {
if(metadata) {
groupMetadata[jid] = metadata
}
}
@@ -460,7 +454,7 @@ export default (
// return groupMetadata[jid]
// },
fetchMessageReceipts: async ({ remoteJid, id }: WAMessageKey) => {
fetchMessageReceipts: async({ remoteJid, id }: WAMessageKey) => {
const list = messages[remoteJid!]
const msg = list?.get(id!)
return msg?.userReceipt
@@ -475,7 +469,7 @@ export default (
readFromFile: (path: string) => {
// require fs here so that in case "fs" is not available -- the app does not crash
const { readFileSync, existsSync } = require('fs')
if (existsSync(path)) {
if(existsSync(path)) {
logger.debug({ path }, 'reading from file')
const jsonStr = readFileSync(path, { encoding: 'utf-8' })
const json = JSON.parse(jsonStr)

View File

@@ -1,31 +1,32 @@
export class ObjectRepository<T extends object> {
readonly entityMap: Map<string, T>
readonly entityMap: Map<string, T>
constructor(entities: Record<string, T> = {}) {
this.entityMap = new Map(Object.entries(entities))
}
constructor(entities: Record<string, T> = {}) {
this.entityMap = new Map(Object.entries(entities))
}
findById(id: string) {
return this.entityMap.get(id)
}
findById(id: string) {
return this.entityMap.get(id)
}
findAll() {
return Array.from(this.entityMap.values())
}
findAll() {
return Array.from(this.entityMap.values())
}
upsertById(id: string, entity: T) {
return this.entityMap.set(id, { ...entity })
}
upsertById(id: string, entity: T) {
return this.entityMap.set(id, { ...entity })
}
deleteById(id: string) {
return this.entityMap.delete(id)
}
deleteById(id: string) {
return this.entityMap.delete(id)
}
count() {
return this.entityMap.size
}
count() {
return this.entityMap.size
}
toJSON() {
return this.findAll()
}
toJSON() {
return this.findAll()
}
}

View File

@@ -15,13 +15,7 @@ export type WAReadReceiptsValue = 'all' | 'none'
/** set of statuses visible to other people; see updatePresence() in WhatsAppWeb.Send */
export type WAPresence = 'unavailable' | 'available' | 'composing' | 'recording' | 'paused'
export const ALL_WA_PATCH_NAMES = [
'critical_block',
'critical_unblock_low',
'regular_high',
'regular_low',
'regular'
] as const
export const ALL_WA_PATCH_NAMES = ['critical_block', 'critical_unblock_low', 'regular_high', 'regular_low', 'regular'] as const
export type WAPatchName = typeof ALL_WA_PATCH_NAMES[number]

View File

@@ -1,35 +1,35 @@
/** Association type */
export enum LabelAssociationType {
Chat = 'label_jid',
Message = 'label_message'
}
Chat = 'label_jid',
Message = 'label_message'
}
export type LabelAssociationTypes = `${LabelAssociationType}`
export type LabelAssociationTypes = `${LabelAssociationType}`
/** Association for chat */
export interface ChatLabelAssociation {
type: LabelAssociationType.Chat
chatId: string
labelId: string
}
/** Association for chat */
export interface ChatLabelAssociation {
type: LabelAssociationType.Chat
chatId: string
labelId: string
}
/** Association for message */
export interface MessageLabelAssociation {
type: LabelAssociationType.Message
chatId: string
messageId: string
labelId: string
}
/** Association for message */
export interface MessageLabelAssociation {
type: LabelAssociationType.Message
chatId: string
messageId: string
labelId: string
}
export type LabelAssociation = ChatLabelAssociation | MessageLabelAssociation
export type LabelAssociation = ChatLabelAssociation | MessageLabelAssociation
/** Body for add/remove chat label association action */
export interface ChatLabelAssociationActionBody {
labelId: string
}
/** Body for add/remove chat label association action */
export interface ChatLabelAssociationActionBody {
labelId: string
}
/** body for add/remove message label association action */
export interface MessageLabelAssociationActionBody {
labelId: string
messageId: string
}
/** body for add/remove message label association action */
export interface MessageLabelAssociationActionBody {
labelId: string
messageId: string
}

View File

@@ -29,12 +29,12 @@ const generateMac = (operation: proto.SyncdMutation.SyncdOperation, data: Buffer
const getKeyData = () => {
let r: number
switch (operation) {
case proto.SyncdMutation.SyncdOperation.SET:
r = 0x01
break
case proto.SyncdMutation.SyncdOperation.REMOVE:
r = 0x02
break
case proto.SyncdMutation.SyncdOperation.SET:
r = 0x01
break
case proto.SyncdMutation.SyncdOperation.REMOVE:
r = 0x02
break
}
const buff = Buffer.from([r])
@@ -69,8 +69,8 @@ const makeLtHashGenerator = ({ indexValueMap, hash }: Pick<LTHashState, 'hash' |
mix: ({ indexMac, valueMac, operation }: Mac) => {
const indexMacBase64 = Buffer.from(indexMac).toString('base64')
const prevOp = indexValueMap[indexMacBase64]
if (operation === proto.SyncdMutation.SyncdOperation.REMOVE) {
if (!prevOp) {
if(operation === proto.SyncdMutation.SyncdOperation.REMOVE) {
if(!prevOp) {
throw new Boom('tried remove, but no previous op', { data: { indexMac, valueMac } })
}
@@ -82,7 +82,7 @@ const makeLtHashGenerator = ({ indexValueMap, hash }: Pick<LTHashState, 'hash' |
indexValueMap[indexMacBase64] = { valueMac }
}
if (prevOp) {
if(prevOp) {
subBuffs.push(new Uint8Array(prevOp.valueMac).buffer)
}
},
@@ -120,14 +120,14 @@ const generatePatchMac = (snapshotMac: Uint8Array, valueMacs: Uint8Array[], vers
export const newLTHashState = (): LTHashState => ({ version: 0, hash: Buffer.alloc(128), indexValueMap: {} })
export const encodeSyncdPatch = async (
export const encodeSyncdPatch = async(
{ type, index, syncAction, apiVersion, operation }: WAPatchCreate,
myAppStateKeyId: string,
state: LTHashState,
getAppStateSyncKey: FetchAppStateSyncKey
) => {
const key = !!myAppStateKeyId ? await getAppStateSyncKey(myAppStateKeyId) : undefined
if (!key) {
if(!key) {
throw new Boom(`myAppStateKey ("${myAppStateKeyId}") not present`, { statusCode: 404 })
}
@@ -185,7 +185,7 @@ export const encodeSyncdPatch = async (
return { patch, state }
}
export const decodeSyncdMutations = async (
export const decodeSyncdMutations = async(
msgMutations: (proto.ISyncdMutation | proto.ISyncdRecord)[],
initialState: LTHashState,
getAppStateSyncKey: FetchAppStateSyncKey,
@@ -196,7 +196,7 @@ export const decodeSyncdMutations = async (
// indexKey used to HMAC sign record.index.blob
// valueEncryptionKey used to AES-256-CBC encrypt record.value.blob[0:-32]
// the remaining record.value.blob[0:-32] is the mac, it the HMAC sign of key.keyId + decoded proto data + length of bytes in keyId
for (const msgMutation of msgMutations!) {
for(const msgMutation of msgMutations!) {
// if it's a syncdmutation, get the operation property
// otherwise, if it's only a record -- it'll be a SET mutation
const operation = 'operation' in msgMutation ? msgMutation.operation : proto.SyncdMutation.SyncdOperation.SET
@@ -206,9 +206,9 @@ export const decodeSyncdMutations = async (
const content = Buffer.from(record.value!.blob!)
const encContent = content.slice(0, -32)
const ogValueMac = content.slice(-32)
if (validateMacs) {
if(validateMacs) {
const contentHmac = generateMac(operation!, encContent, record.keyId!.id!, key.valueMacKey)
if (Buffer.compare(contentHmac, ogValueMac) !== 0) {
if(Buffer.compare(contentHmac, ogValueMac) !== 0) {
throw new Boom('HMAC content verification failed')
}
}
@@ -216,9 +216,9 @@ export const decodeSyncdMutations = async (
const result = aesDecrypt(encContent, key.valueEncryptionKey)
const syncAction = proto.SyncActionData.decode(result)
if (validateMacs) {
if(validateMacs) {
const hmac = hmacSign(syncAction.index, key.indexKey)
if (Buffer.compare(hmac, record.index!.blob!) !== 0) {
if(Buffer.compare(hmac, record.index!.blob!) !== 0) {
throw new Boom('HMAC index verification failed')
}
}
@@ -238,7 +238,7 @@ export const decodeSyncdMutations = async (
async function getKey(keyId: Uint8Array) {
const base64Key = Buffer.from(keyId!).toString('base64')
const keyEnc = await getAppStateSyncKey(base64Key)
if (!keyEnc) {
if(!keyEnc) {
throw new Boom(`failed to find key "${base64Key}" to decode mutation`, { statusCode: 404, data: { msgMutations } })
}
@@ -246,7 +246,7 @@ export const decodeSyncdMutations = async (
}
}
export const decodeSyncdPatch = async (
export const decodeSyncdPatch = async(
msg: proto.ISyncdPatch,
name: WAPatchName,
initialState: LTHashState,
@@ -254,10 +254,10 @@ export const decodeSyncdPatch = async (
onMutation: (mutation: ChatMutation) => void,
validateMacs: boolean
) => {
if (validateMacs) {
if(validateMacs) {
const base64Key = Buffer.from(msg.keyId!.id!).toString('base64')
const mainKeyObj = await getAppStateSyncKey(base64Key)
if (!mainKeyObj) {
if(!mainKeyObj) {
throw new Boom(`failed to find key "${base64Key}" to decode patch`, { statusCode: 404, data: { msg } })
}
@@ -265,7 +265,7 @@ export const decodeSyncdPatch = async (
const mutationmacs = msg.mutations!.map(mutation => mutation.record!.value!.blob!.slice(-32))
const patchMac = generatePatchMac(msg.snapshotMac!, mutationmacs, toNumber(msg.version!.version!), name, mainKey.patchMacKey)
if (Buffer.compare(patchMac, msg.patchMac!) !== 0) {
if(Buffer.compare(patchMac, msg.patchMac!) !== 0) {
throw new Boom('Invalid patch mac')
}
}
@@ -274,7 +274,7 @@ export const decodeSyncdPatch = async (
return result
}
export const extractSyncdPatches = async (
export const extractSyncdPatches = async(
result: BinaryNode,
options: AxiosRequestConfig<any>
) => {
@@ -296,8 +296,8 @@ export const extractSyncdPatches = async (
const hasMorePatches = collectionNode.attrs.has_more_patches === 'true'
let snapshot: proto.ISyncdSnapshot | undefined = undefined
if (snapshotNode && !!snapshotNode.content) {
if (!Buffer.isBuffer(snapshotNode)) {
if(snapshotNode && !!snapshotNode.content) {
if(!Buffer.isBuffer(snapshotNode)) {
snapshotNode.content = Buffer.from(Object.values(snapshotNode.content))
}
@@ -308,14 +308,14 @@ export const extractSyncdPatches = async (
snapshot = proto.SyncdSnapshot.decode(data)
}
for (let { content } of patches) {
if (content) {
if (!Buffer.isBuffer(content)) {
for(let { content } of patches) {
if(content) {
if(!Buffer.isBuffer(content)) {
content = Buffer.from(Object.values(content))
}
const syncd = proto.SyncdPatch.decode(content! as Uint8Array)
if (!syncd.version) {
if(!syncd.version) {
syncd.version = { version: +collectionNode.attrs.version + 1 }
}
@@ -332,7 +332,7 @@ export const extractSyncdPatches = async (
}
export const downloadExternalBlob = async (
export const downloadExternalBlob = async(
blob: proto.IExternalBlobReference,
options: AxiosRequestConfig<any>
) => {
@@ -345,7 +345,7 @@ export const downloadExternalBlob = async (
return Buffer.concat(bufferArray)
}
export const downloadExternalPatch = async (
export const downloadExternalPatch = async(
blob: proto.IExternalBlobReference,
options: AxiosRequestConfig<any>
) => {
@@ -354,7 +354,7 @@ export const downloadExternalPatch = async (
return syncData
}
export const decodeSyncdSnapshot = async (
export const decodeSyncdSnapshot = async(
name: WAPatchName,
snapshot: proto.ISyncdSnapshot,
getAppStateSyncKey: FetchAppStateSyncKey,
@@ -383,16 +383,16 @@ export const decodeSyncdSnapshot = async (
newState.hash = hash
newState.indexValueMap = indexValueMap
if (validateMacs) {
if(validateMacs) {
const base64Key = Buffer.from(snapshot.keyId!.id!).toString('base64')
const keyEnc = await getAppStateSyncKey(base64Key)
if (!keyEnc) {
if(!keyEnc) {
throw new Boom(`failed to find key "${base64Key}" to decode mutation`)
}
const result = mutationKeys(keyEnc.keyData!)
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey)
if (Buffer.compare(snapshot.mac!, computedSnapshotMac) !== 0) {
if(Buffer.compare(snapshot.mac!, computedSnapshotMac) !== 0) {
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name} from snapshot`)
}
}
@@ -403,7 +403,7 @@ export const decodeSyncdSnapshot = async (
}
}
export const decodePatches = async (
export const decodePatches = async(
name: WAPatchName,
syncds: proto.ISyncdPatch[],
initial: LTHashState,
@@ -420,10 +420,10 @@ export const decodePatches = async (
const mutationMap: ChatMutationMap = {}
for (let i = 0; i < syncds.length; i++) {
for(let i = 0; i < syncds.length; i++) {
const syncd = syncds[i]
const { version, keyId, snapshotMac } = syncd
if (syncd.externalMutations) {
if(syncd.externalMutations) {
logger?.trace({ name, version }, 'downloading external patch')
const ref = await downloadExternalPatch(syncd.externalMutations, options)
logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch')
@@ -452,16 +452,16 @@ export const decodePatches = async (
newState.hash = decodeResult.hash
newState.indexValueMap = decodeResult.indexValueMap
if (validateMacs) {
if(validateMacs) {
const base64Key = Buffer.from(keyId!.id!).toString('base64')
const keyEnc = await getAppStateSyncKey(base64Key)
if (!keyEnc) {
if(!keyEnc) {
throw new Boom(`failed to find key "${base64Key}" to decode mutation`)
}
const result = mutationKeys(keyEnc.keyData!)
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey)
if (Buffer.compare(snapshotMac!, computedSnapshotMac) !== 0) {
if(Buffer.compare(snapshotMac!, computedSnapshotMac) !== 0) {
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name}`)
}
}
@@ -480,25 +480,25 @@ export const chatModificationToAppPatch = (
const OP = proto.SyncdMutation.SyncdOperation
const getMessageRange = (lastMessages: LastMessageList) => {
let messageRange: proto.SyncActionValue.ISyncActionMessageRange
if (Array.isArray(lastMessages)) {
if(Array.isArray(lastMessages)) {
const lastMsg = lastMessages[lastMessages.length - 1]
messageRange = {
lastMessageTimestamp: lastMsg?.messageTimestamp,
messages: lastMessages?.length ? lastMessages.map(
m => {
if (!m.key?.id || !m.key?.remoteJid) {
if(!m.key?.id || !m.key?.remoteJid) {
throw new Boom('Incomplete key', { statusCode: 400, data: m })
}
if (isJidGroup(m.key.remoteJid) && !m.key.fromMe && !m.key.participant) {
if(isJidGroup(m.key.remoteJid) && !m.key.fromMe && !m.key.participant) {
throw new Boom('Expected not from me message to have participant', { statusCode: 400, data: m })
}
if (!m.messageTimestamp || !toNumber(m.messageTimestamp)) {
if(!m.messageTimestamp || !toNumber(m.messageTimestamp)) {
throw new Boom('Missing timestamp in last message list', { statusCode: 400, data: m })
}
if (m.key.participant) {
if(m.key.participant) {
m.key.participant = jidNormalizedUser(m.key.participant)
}
@@ -514,7 +514,7 @@ export const chatModificationToAppPatch = (
}
let patch: WAPatchCreate
if ('mute' in mod) {
if('mute' in mod) {
patch = {
syncAction: {
muteAction: {
@@ -527,7 +527,7 @@ export const chatModificationToAppPatch = (
apiVersion: 2,
operation: OP.SET
}
} else if ('archive' in mod) {
} else if('archive' in mod) {
patch = {
syncAction: {
archiveChatAction: {
@@ -540,7 +540,7 @@ export const chatModificationToAppPatch = (
apiVersion: 3,
operation: OP.SET
}
} else if ('markRead' in mod) {
} else if('markRead' in mod) {
patch = {
syncAction: {
markChatAsReadAction: {
@@ -553,8 +553,8 @@ export const chatModificationToAppPatch = (
apiVersion: 3,
operation: OP.SET
}
} else if ('clear' in mod) {
if (mod.clear === 'all') {
} else if('clear' in mod) {
if(mod.clear === 'all') {
throw new Boom('not supported')
} else {
const key = mod.clear.messages[0]
@@ -571,7 +571,7 @@ export const chatModificationToAppPatch = (
operation: OP.SET
}
}
} else if ('pin' in mod) {
} else if('pin' in mod) {
patch = {
syncAction: {
pinAction: {
@@ -583,7 +583,7 @@ export const chatModificationToAppPatch = (
apiVersion: 5,
operation: OP.SET
}
} else if ('delete' in mod) {
} else if('delete' in mod) {
patch = {
syncAction: {
deleteChatAction: {
@@ -595,7 +595,7 @@ export const chatModificationToAppPatch = (
apiVersion: 6,
operation: OP.SET
}
} else if ('pushNameSetting' in mod) {
} else if('pushNameSetting' in mod) {
patch = {
syncAction: {
pushNameSetting: {
@@ -607,7 +607,7 @@ export const chatModificationToAppPatch = (
apiVersion: 1,
operation: OP.SET,
}
} else if ('addChatLabel' in mod) {
} else if('addChatLabel' in mod) {
patch = {
syncAction: {
labelAssociationAction: {
@@ -619,7 +619,7 @@ export const chatModificationToAppPatch = (
apiVersion: 3,
operation: OP.SET,
}
} else if ('removeChatLabel' in mod) {
} else if('removeChatLabel' in mod) {
patch = {
syncAction: {
labelAssociationAction: {
@@ -631,7 +631,7 @@ export const chatModificationToAppPatch = (
apiVersion: 3,
operation: OP.SET,
}
} else if ('addMessageLabel' in mod) {
} else if('addMessageLabel' in mod) {
patch = {
syncAction: {
labelAssociationAction: {
@@ -650,7 +650,7 @@ export const chatModificationToAppPatch = (
apiVersion: 3,
operation: OP.SET,
}
} else if ('removeMessageLabel' in mod) {
} else if('removeMessageLabel' in mod) {
patch = {
syncAction: {
labelAssociationAction: {
@@ -695,7 +695,7 @@ export const processSyncAction = (
index: [type, id, msgId, fromMe]
} = syncAction
if (action?.muteAction) {
if(action?.muteAction) {
ev.emit(
'chats.update',
[
@@ -708,7 +708,7 @@ export const processSyncAction = (
}
]
)
} else if (action?.archiveChatAction || type === 'archive' || type === 'unarchive') {
} else if(action?.archiveChatAction || type === 'archive' || type === 'unarchive') {
// okay so we've to do some annoying computation here
// when we're initially syncing the app state
// there are a few cases we need to handle
@@ -737,7 +737,7 @@ export const processSyncAction = (
archived: isArchived,
conditional: getChatUpdateConditional(id, msgRange)
}])
} else if (action?.markChatAsReadAction) {
} else if(action?.markChatAsReadAction) {
const markReadAction = action.markChatAsReadAction
// basically we don't need to fire an "read" update if the chat is being marked as read
// because the chat is read by default
@@ -749,7 +749,7 @@ export const processSyncAction = (
unreadCount: isNullUpdate ? null : !!markReadAction?.read ? 0 : -1,
conditional: getChatUpdateConditional(id, markReadAction?.messageRange)
}])
} else if (action?.deleteMessageForMeAction || type === 'deleteMessageForMe') {
} else if(action?.deleteMessageForMeAction || type === 'deleteMessageForMe') {
ev.emit('messages.delete', {
keys: [
{
@@ -759,30 +759,30 @@ export const processSyncAction = (
}
]
})
} else if (action?.contactAction) {
} else if(action?.contactAction) {
ev.emit('contacts.upsert', [{ id, name: action.contactAction!.fullName! }])
} else if (action?.pushNameSetting) {
} else if(action?.pushNameSetting) {
const name = action?.pushNameSetting?.name
if (name && me?.name !== name) {
if(name && me?.name !== name) {
ev.emit('creds.update', { me: { ...me, name } })
}
} else if (action?.pinAction) {
} else if(action?.pinAction) {
ev.emit('chats.update', [{
id,
pinned: action.pinAction?.pinned ? toNumber(action.timestamp!) : null,
conditional: getChatUpdateConditional(id, undefined)
}])
} else if (action?.unarchiveChatsSetting) {
} else if(action?.unarchiveChatsSetting) {
const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats
ev.emit('creds.update', { accountSettings: { unarchiveChats } })
logger?.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`)
if (accountSettings) {
if(accountSettings) {
accountSettings.unarchiveChats = unarchiveChats
}
} else if (action?.starAction || type === 'star') {
} else if(action?.starAction || type === 'star') {
let starred = action?.starAction?.starred
if (typeof starred !== 'boolean') {
if(typeof starred !== 'boolean') {
starred = syncAction.index[syncAction.index.length - 1] === '1'
}
@@ -792,11 +792,11 @@ export const processSyncAction = (
update: { starred }
}
])
} else if (action?.deleteChatAction || type === 'deleteChat') {
if (!isInitialSync) {
} else if(action?.deleteChatAction || type === 'deleteChat') {
if(!isInitialSync) {
ev.emit('chats.delete', [id])
}
} else if (action?.labelEditAction) {
} else if(action?.labelEditAction) {
const { name, color, deleted, predefinedId } = action.labelEditAction!
ev.emit('labels.edit', {
@@ -806,7 +806,7 @@ export const processSyncAction = (
deleted: deleted!,
predefinedId: predefinedId ? String(predefinedId) : undefined
})
} else if (action?.labelAssociationAction) {
} else if(action?.labelAssociationAction) {
ev.emit('labels.association', {
type: action.labelAssociationAction.labeled
? 'add'
@@ -832,7 +832,7 @@ export const processSyncAction = (
return isInitialSync
? (data) => {
const chat = data.historySets.chats[id] || data.chatUpserts[id]
if (chat) {
if(chat) {
return msgRange ? isValidPatchBasedOnMessageRange(chat, msgRange) : true
}
}