diff --git a/src/Signal/libsignal.ts b/src/Signal/libsignal.ts index fb4099b2..93fadafc 100644 --- a/src/Signal/libsignal.ts +++ b/src/Signal/libsignal.ts @@ -708,7 +708,7 @@ function signalStorage( if (domainType === WAJIDDomains.LID || domainType === WAJIDDomains.HOSTED_LID) return id - const pnJid = `${user ?? ''}${device !== '0' ? `:${device}` : ''}@${domainType === WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}` + const pnJid = `${user!}${device !== '0' ? `:${device}` : ''}@${domainType === WAJIDDomains.HOSTED ? 'hosted' : 's.whatsapp.net'}` const lidForPN = await lidMapping.getLIDForPN(pnJid) if (lidForPN) { diff --git a/src/Socket/business.ts b/src/Socket/business.ts index 23392b23..d67fdd40 100644 --- a/src/Socket/business.ts +++ b/src/Socket/business.ts @@ -118,7 +118,7 @@ export const makeBusinessSocket = (config: SocketConfig) => { content: [ { tag: 'cover_photo', - attrs: { id: String(fbid), op: 'update', token: meta_hmac ?? '', ts: String(ts) } + attrs: { id: String(fbid), op: 'update', token: meta_hmac!, ts: String(ts) } } ] } diff --git a/src/Socket/chats.ts b/src/Socket/chats.ts index f8ac807f..759227b1 100644 --- a/src/Socket/chats.ts +++ b/src/Socket/chats.ts @@ -1107,8 +1107,8 @@ export const makeChatsSocket = (config: SocketConfig) => { ev.emit('messages.upsert', { messages: [msg], type }) if (!!msg.pushName) { - let jid = msg.key.fromMe ? (authState.creds.me?.id ?? '') : msg.key.participant || msg.key.remoteJid - jid = jidNormalizedUser(jid ?? '') + let jid = msg.key.fromMe ? authState.creds.me!.id : msg.key.participant || msg.key.remoteJid + jid = jidNormalizedUser(jid!) if (!msg.key.fromMe) { ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName! }]) diff --git a/src/Socket/communities.ts b/src/Socket/communities.ts index 9691be1a..0c78397b 100644 --- a/src/Socket/communities.ts +++ b/src/Socket/communities.ts @@ -358,13 +358,13 @@ export const makeCommunitiesSocket = (config: SocketConfig) => { communityAcceptInviteV4: ev.createBufferedFunction( async (key: string | WAMessageKey, inviteMessage: proto.Message.IGroupInviteMessage) => { key = typeof key === 'string' ? { remoteJid: key } : key - const results = await communityQuery(inviteMessage.groupJid ?? '', 'set', [ + const results = await communityQuery(inviteMessage.groupJid!, 'set', [ { tag: 'accept', attrs: { - code: inviteMessage.inviteCode ?? '', + code: inviteMessage.inviteCode!, expiration: (inviteMessage.inviteExpiration ?? 0).toString(), - admin: key.remoteJid ?? '' + admin: key.remoteJid! } } ]) @@ -475,7 +475,7 @@ export const extractCommunityMetadata = (result: BinaryNode) => { participants: getBinaryNodeChildren(community, 'participant').map(({ attrs }) => { return { // TODO: IMPLEMENT THE PN/LID FIELDS HERE!! - id: attrs.jid ?? '', + id: attrs.jid!, admin: (attrs.type || null) as GroupParticipant['admin'] } }), diff --git a/src/Socket/groups.ts b/src/Socket/groups.ts index 7517328c..33194e27 100644 --- a/src/Socket/groups.ts +++ b/src/Socket/groups.ts @@ -225,12 +225,12 @@ export const makeGroupsSocket = (config: SocketConfig) => { groupAcceptInviteV4: ev.createBufferedFunction( async (key: string | WAMessageKey, inviteMessage: proto.Message.IGroupInviteMessage) => { key = typeof key === 'string' ? { remoteJid: key } : key - const results = await groupQuery(inviteMessage.groupJid ?? '', 'set', [ + const results = await groupQuery(inviteMessage.groupJid!, 'set', [ { tag: 'accept', attrs: { - code: inviteMessage.inviteCode ?? '', - expiration: String(inviteMessage.inviteExpiration ?? ''), + code: inviteMessage.inviteCode!, + expiration: inviteMessage.inviteExpiration!.toString(), admin: key.remoteJid! } } @@ -316,14 +316,14 @@ export const extractGroupMetadata = (result: BinaryNode) => { descId = descChild.attrs.id } - const groupId = (group.attrs.id ?? '').includes('@') ? (group.attrs.id ?? '') : jidEncode(group.attrs.id ?? '', 'g.us') + const groupId = group.attrs.id!.includes('@') ? group.attrs.id! : jidEncode(group.attrs.id!, 'g.us') const eph = getBinaryNodeChild(group, 'ephemeral')?.attrs.expiration const memberAddMode = getBinaryNodeChildString(group, 'member_add_mode') === 'all_member_add' const metadata: GroupMetadata = { id: groupId, notify: group.attrs.notify, addressingMode: group.attrs.addressing_mode === 'lid' ? WAMessageAddressingMode.LID : WAMessageAddressingMode.PN, - subject: group.attrs.subject ?? '', + subject: group.attrs.subject!, subjectOwner: group.attrs.s_o, subjectOwnerPn: group.attrs.s_o_pn, subjectTime: +(group.attrs.s_t ?? '0'), @@ -347,7 +347,7 @@ export const extractGroupMetadata = (result: BinaryNode) => { participants: getBinaryNodeChildren(group, 'participant').map(({ attrs }) => { // TODO: Store LID MAPPINGS return { - id: attrs.jid ?? '', + id: attrs.jid!, phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined, lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined, admin: (attrs.type || null) as GroupParticipant['admin'] diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 6c6a3efa..7656e38b 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -156,17 +156,16 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { throw new Boom('Not authenticated') } - const msgId = messageKey?.id ?? '' - if (await placeholderResendCache.get(msgId)) { + if (await placeholderResendCache.get(messageKey?.id!)) { logger.debug({ messageKey }, 'already requested resend') return } else { - await placeholderResendCache.set(msgId, true) + await placeholderResendCache.set(messageKey?.id!, true) } await delay(2000) - if (!(await placeholderResendCache.get(msgId))) { + if (!(await placeholderResendCache.get(messageKey?.id!))) { logger.debug({ messageKey }, 'message received while resend requested') return 'RESOLVED' } @@ -181,9 +180,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } setTimeout(async () => { - if (await placeholderResendCache.get(msgId)) { + if (await placeholderResendCache.get(messageKey?.id!)) { logger.debug({ messageKey }, 'PDO message without response after 8 seconds. Phone possibly offline') - await placeholderResendCache.del(msgId) + await placeholderResendCache.del(messageKey?.id!) } }, 8_000) @@ -234,7 +233,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { if (update.jid && update.user) { ev.emit('newsletter-participants.update', { id: update.jid, - author: node.attrs.from ?? '', + author: node.attrs.from!, user: update.user, new_role: 'ADMIN', action: 'promote' @@ -252,10 +251,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { // Handles newsletter notifications const handleNewsletterNotification = async (node: BinaryNode) => { - const from = node.attrs.from ?? '' - const child = getAllBinaryNodeChildren(node)[0] - if (!child) return - const author = node.attrs.participant ?? '' + const from = node.attrs.from! + const child = getAllBinaryNodeChildren(node)[0]! + const author = node.attrs.participant! logger.info({ from, child }, 'got newsletter notification') @@ -263,7 +261,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { case 'reaction': const reactionUpdate = { id: from, - server_id: child.attrs.message_id ?? '', + server_id: child.attrs.message_id!, reaction: { code: getBinaryNodeChildString(child, 'reaction'), count: 1 @@ -275,7 +273,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { case 'view': const viewUpdate = { id: from, - server_id: child.attrs.message_id ?? '', + server_id: child.attrs.message_id!, count: parseInt(child.content?.toString() || '0', 10) } ev.emit('newsletter.view', viewUpdate) @@ -285,9 +283,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const participantUpdate = { id: from, author, - user: child.attrs.jid ?? '', - action: child.attrs.action ?? '', - new_role: child.attrs.role ?? '' + user: child.attrs.jid!, + action: child.attrs.action!, + new_role: child.attrs.role! } ev.emit('newsletter-participants.update', participantUpdate) break @@ -326,7 +324,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { fromMe: false // TODO: is this really true though }, message: messageProto, - messageTimestamp: +(child.attrs.t ?? 0) + messageTimestamp: +child.attrs.t! }).toJSON() as WAMessage await upsertMessage(fullMessage, 'append') logger.info('Processed plaintext newsletter message') @@ -347,8 +345,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const stanza: BinaryNode = { tag: 'ack', attrs: { - id: attrs.id ?? '', - to: attrs.from ?? '', + id: attrs.id!, + to: attrs.from!, class: tag } } @@ -407,16 +405,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } const sendRetryRequest = async (node: BinaryNode, forceIncludeKeys = false) => { - const meId = authState.creds.me?.id - if (!meId) throw new Boom('Not authenticated', { statusCode: 401 }) - const meLid = authState.creds.me?.lid || '' - const { fullMessage } = decodeMessageNode(node, meId, meLid) + const { fullMessage } = decodeMessageNode(node, authState.creds.me!.id, authState.creds.me!.lid || '') const { key: msgKey } = fullMessage - const msgId = msgKey.id - if (!msgId) { - logger.debug({ node }, 'missing message id in retry request') - return - } + const msgId = msgKey.id! if (messageRetryManager) { // Check if we've exceeded max retries using the new system @@ -454,7 +445,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const retryCount = (await msgRetryCache.get(key)) || 1 const { account, signedPreKey, signedIdentityKey: identityKey } = authState.creds - const fromJid = node.attrs.from ?? '' + const fromJid = node.attrs.from! // Check if we should recreate the session let shouldRecreateSession = false @@ -519,15 +510,15 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { attrs: { id: msgId, type: 'retry', - to: node.attrs.from ?? '' + to: node.attrs.from! }, content: [ { tag: 'retry', attrs: { count: retryCount.toString(), - id: node.attrs.id ?? '', - t: node.attrs.t ?? '', + id: node.attrs.id!, + t: node.attrs.t!, v: '1', // ADD ERROR FIELD error: '0' @@ -553,19 +544,16 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const { update, preKeys } = await getNextPreKeys(authState, 1) const [keyId] = Object.keys(preKeys) - if (!keyId) throw new Boom('No pre-keys available') - const key = preKeys[+keyId] - if (!key) throw new Boom('Pre-key not found') + const key = preKeys[+keyId!] - const content = receipt.content as BinaryNode[] - if (!content) throw new Boom('Receipt content missing') + const content = receipt.content! as BinaryNode[] content.push({ tag: 'keys', attrs: {}, content: [ { tag: 'type', attrs: {}, content: Buffer.from(KEY_BUNDLE_TYPE) }, { tag: 'identity', attrs: {}, content: identityKey.public }, - xmppPreKey(key, +keyId), + xmppPreKey(key!, +keyId!), xmppSignedPreKey(signedPreKey), { tag: 'device-identity', attrs: {}, content: deviceIdentity } ] @@ -584,9 +572,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const from = node.attrs.from if (from === S_WHATSAPP_NET) { const countChild = getBinaryNodeChild(node, 'count') - const countVal = countChild?.attrs?.value - if (!countVal) return - const count = +countVal + const count = +countChild!.attrs.value! const shouldUploadMorePreKeys = count < MIN_PREKEY_COUNT logger.debug({ count, shouldUploadMorePreKeys }, 'recv pre-key count') @@ -615,8 +601,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const actingParticipantLid = fullNode.attrs.participant const actingParticipantPn = fullNode.attrs.participant_pn - const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid || '' - const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn || '' + const affectedParticipantLid = getBinaryNodeChild(child, 'participant')?.attrs?.jid || actingParticipantLid! + const affectedParticipantPn = getBinaryNodeChild(child, 'participant')?.attrs?.phone_number || actingParticipantPn! switch (child?.tag) { case 'create': @@ -651,7 +637,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } break case 'modify': - const oldNumber = getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid ?? '').filter(Boolean) + const oldNumber = getBinaryNodeChildren(child, 'participant').map(p => p.attrs.jid!) msg.messageStubParameters = oldNumber || [] msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER break @@ -666,7 +652,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const participants = getBinaryNodeChildren(child, 'participant').map(({ attrs }) => { // TODO: Store LID MAPPINGS return { - id: attrs.jid ?? '', + id: attrs.jid!, phoneNumber: isLidUser(attrs.jid) && isPnUser(attrs.phone_number) ? attrs.phone_number : undefined, lid: isPnUser(attrs.jid) && isLidUser(attrs.lid) ? attrs.lid : undefined, admin: (attrs.type || null) as GroupParticipant['admin'] @@ -677,8 +663,8 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { participants.length === 1 && // if recv. "remove" message and sender removed themselves // mark as left - (areJidsSameUser(participants[0]?.id, actingParticipantLid) || - areJidsSameUser(participants[0]?.id, actingParticipantPn)) && + (areJidsSameUser(participants[0]!.id, actingParticipantLid) || + areJidsSameUser(participants[0]!.id, actingParticipantPn)) && child.tag === 'remove' ) { msg.messageStubType = WAMessageStubType.GROUP_PARTICIPANT_LEAVE @@ -688,7 +674,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { break case 'subject': msg.messageStubType = WAMessageStubType.GROUP_CHANGE_SUBJECT - msg.messageStubParameters = [child.attrs.subject ?? ''] + msg.messageStubParameters = [child.attrs.subject!] break case 'description': const description = getBinaryNodeChild(child, 'body')?.content?.toString() @@ -707,7 +693,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { break case 'invite': msg.messageStubType = WAMessageStubType.GROUP_CHANGE_INVITE_LINK - msg.messageStubParameters = [child.attrs.code ?? ''] + msg.messageStubParameters = [child.attrs.code!] break case 'member_add_mode': const addMode = child.content @@ -721,7 +707,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const approvalMode = getBinaryNodeChild(child, 'group_join') if (approvalMode) { msg.messageStubType = WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE - msg.messageStubParameters = [approvalMode.attrs.state ?? ''] + msg.messageStubParameters = [approvalMode.attrs.state!] } break @@ -730,7 +716,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { msg.messageStubParameters = [ JSON.stringify({ lid: affectedParticipantLid, pn: affectedParticipantPn }), 'created', - child.attrs.request_method ?? '' + child.attrs.request_method! ] break case 'revoked_membership_requests': @@ -760,8 +746,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { break case 'w:gp2': // TODO: HANDLE PARTICIPANT_PN - if (!child) break - handleGroupNotification(node, child, result) + handleGroupNotification(node, child!, result) break case 'mediaretry': const event = decodeMediaRetryNode(node) @@ -771,11 +756,10 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { await handleEncryptNotification(node) break case 'devices': - if (!child) break const devices = getBinaryNodeChildren(child, 'device') if ( - areJidsSameUser(child.attrs.jid, authState.creds.me?.id) || - areJidsSameUser(child.attrs.lid, authState.creds.me?.lid) + areJidsSameUser(child!.attrs.jid, authState.creds.me!.id) || + areJidsSameUser(child!.attrs.lid, authState.creds.me!.lid) ) { const deviceData = devices.map(d => ({ id: d.attrs.jid, lid: d.attrs.lid })) logger.info({ deviceData }, 'my own devices changed') @@ -821,9 +805,9 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { break case 'account_sync': - if (child?.tag === 'disappearing_mode') { - const newDuration = +(child.attrs.duration ?? '0') - const timestamp = +(child.attrs.t ?? '0') + if (child!.tag === 'disappearing_mode') { + const newDuration = +child!.attrs.duration! + const timestamp = +child!.attrs.t! logger.info({ newDuration }, 'updated account disappearing mode') @@ -836,11 +820,11 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } } }) - } else if (child?.tag === 'blocklist') { + } else if (child!.tag === 'blocklist') { const blocklists = getBinaryNodeChildren(child, 'item') for (const { attrs } of blocklists) { - const blocklist = [attrs.jid ?? ''] + const blocklist = [attrs.jid!] const type = attrs.action === 'block' ? 'add' : 'remove' ev.emit('blocklist.update', { blocklist, type }) } @@ -890,7 +874,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { { tag: 'link_code_companion_reg', attrs: { - jid: authState.creds.me?.id ?? '', + jid: authState.creds.me!.id, stage: 'companion_finish' }, content: [ @@ -1092,7 +1076,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const handleReceipt = async (node: BinaryNode) => { const { attrs, content } = node - const isLid = (attrs.from ?? '').includes('lid') + const isLid = attrs.from!.includes('lid') const isNodeFromMe = areJidsSameUser( attrs.participant || attrs.from, isLid ? authState.creds.me?.lid : authState.creds.me?.id @@ -1198,7 +1182,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { notificationMutex.mutex(async () => { const msg = await processNotification(node) if (msg) { - const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me?.id ?? '') + const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me!.id) const { senderAlt: participantAlt, addressingMode } = extractAddressingContext(node) msg.key = { remoteJid, @@ -1242,7 +1226,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { category, author, decrypt - } = decryptMessageNode(node, authState.creds.me?.id ?? '', authState.creds.me?.lid || '', signalRepository, logger) + } = decryptMessageNode(node, authState.creds.me!.id, authState.creds.me!.lid || '', signalRepository, logger) const alt = msg.key.participantAlt || msg.key.remoteJidAlt // Handle LID/PN mappings with hybrid approach: @@ -1527,7 +1511,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { // JID normalization moved BEFORE mutex acquisition (line 1273) to prevent race conditions // cleanMessage still runs inside mutex to ensure atomic message processing - cleanMessage(msg, authState.creds.me?.id ?? '', authState.creds.me?.lid ?? '') + cleanMessage(msg, authState.creds.me!.id, authState.creds.me!.lid!) await upsertMessage(msg, node.attrs.offline ? 'append' : 'notify') diff --git a/src/Socket/messages-send.ts b/src/Socket/messages-send.ts index 3d74a320..22dfdf0b 100644 --- a/src/Socket/messages-send.ts +++ b/src/Socket/messages-send.ts @@ -131,11 +131,11 @@ export const makeMessagesSocket = (config: SocketConfig) => { // TODO: explore full length of data that whatsapp provides const node: MediaConnInfo = { hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({ - hostname: attrs.hostname ?? '', - maxContentLengthBytes: +(attrs.maxContentLengthBytes ?? 0) + hostname: attrs.hostname!, + maxContentLengthBytes: +attrs.maxContentLengthBytes! })), - auth: mediaConnNode.attrs.auth ?? '', - ttl: +(mediaConnNode.attrs.ttl ?? 0), + auth: mediaConnNode.attrs.auth!, + ttl: +mediaConnNode.attrs.ttl!, fetchDate: new Date() } logger.debug('fetched media conn') @@ -163,7 +163,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { const node: BinaryNode = { tag: 'receipt', attrs: { - id: messageIds[0] ?? '' + id: messageIds[0]! } } const isReadReceipt = type === 'read' || type === 'read-self' @@ -268,11 +268,10 @@ export const makeMessagesSocket = (config: SocketConfig) => { } for (const { jid, user } of jidsWithUser) { - if (!user) continue if (useCache) { const devices = - mgetDevices?.[user] || - (userDevicesCache.mget ? undefined : ((await userDevicesCache.get(user)) as FullJid[])) + mgetDevices?.[user!] || + (userDevicesCache.mget ? undefined : ((await userDevicesCache.get(user!)) as FullJid[])) if (devices) { const devicesWithJid = devices.map(d => ({ ...d, @@ -567,8 +566,8 @@ export const makeMessagesSocket = (config: SocketConfig) => { let msgToEncrypt = patchedMessage if (dsmMessage) { - const targetUser = jidDecode(jid)?.user ?? '' - const ownPnUser = jidDecode(meId)?.user ?? '' + const { user: targetUser } = jidDecode(jid)! + const { user: ownPnUser } = jidDecode(meId)! const ownLidUser = meLidUser const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser) @@ -1081,7 +1080,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation') } - const ownUser = jidDecode(ownId)?.user ?? '' + const { user: ownUser } = jidDecode(ownId)! if (!participant) { const patchedForReporting = await patchMessageBeforeSending(message, [jid]) reportingMessage = Array.isArray(patchedForReporting) @@ -1099,7 +1098,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { if (user !== ownUser) { const ownUserServer = isLid ? 'lid' : 's.whatsapp.net' - const ownUserForAddressing = isLid && meLid ? (jidDecode(meLid)?.user ?? '') : (jidDecode(meId)?.user ?? '') + const ownUserForAddressing = isLid && meLid ? jidDecode(meLid)!.user : jidDecode(meId)!.user devices.push({ user: ownUserForAddressing, @@ -1115,8 +1114,8 @@ export const makeMessagesSocket = (config: SocketConfig) => { // Use conversation-appropriate sender identity const senderIdentity = isLid && meLid - ? jidEncode(jidDecode(meLid)?.user ?? '', 'lid', undefined) - : jidEncode(jidDecode(meId)?.user ?? '', 's.whatsapp.net', undefined) + ? jidEncode(jidDecode(meLid)?.user!, 'lid', undefined) + : jidEncode(jidDecode(meId)?.user!, 's.whatsapp.net', undefined) // Enumerate devices for sender and target with consistent addressing const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false) @@ -1135,8 +1134,8 @@ export const makeMessagesSocket = (config: SocketConfig) => { const allRecipients: string[] = [] const meRecipients: string[] = [] const otherRecipients: string[] = [] - const mePnUser = jidDecode(meId)?.user ?? '' - const meLidUser = meLid ? (jidDecode(meLid)?.user ?? null) : null + const { user: mePnUser } = jidDecode(meId)! + const { user: meLidUser } = meLid ? jidDecode(meLid)! : { user: null } // Carousel in DSM wrapper causes error 479 on own devices const isCarouselMsg = isCarouselMessage(message) @@ -1212,7 +1211,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { attrs: { v: '2', type, - count: (participant?.count ?? 0).toString() + count: participant!.count.toString() }, content: encryptedContent }) @@ -1636,7 +1635,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { throw new Boom('Missing media key for update', { statusCode: 400 }) } - const meId = authState.creds.me?.id ?? '' + const meId = authState.creds.me!.id const node = encryptMediaRetryRequest(message.key, mediaKey, meId) let error: Error | undefined = undefined @@ -1713,7 +1712,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { options: MiscMessageGenerationOptions = {} ): Promise => { const startTime = Date.now() - const userJid = authState.creds.me?.id ?? '' + const userJid = authState.creds.me!.id const { medias, @@ -1868,7 +1867,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { // Relay the message await relayMessage(jid, mediaMsg.message, { - messageId: mediaMsg.key.id ?? '', + messageId: mediaMsg.key.id!, useCachedGroupMetadata: options.useCachedGroupMetadata }) @@ -1997,7 +1996,7 @@ export const makeMessagesSocket = (config: SocketConfig) => { ) } - const userJid = authState.creds.me?.id ?? '' + const userJid = authState.creds.me!.id // Special path for carousel: call relayMessage directly with plain JS object // This matches Pastorini's working approach: diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index 0b4f779b..0b1a9563 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -609,12 +609,8 @@ export const makeSocket = (config: SocketConfig) => { }, content: [{ tag: 'count', attrs: {} }] }) - const countChild = getBinaryNodeChild(result, 'count') - if (!countChild) { - return 0 - } - - return +(countChild.attrs.value ?? 0) + const countChild = getBinaryNodeChild(result, 'count')! + return +countChild.attrs.value! } // Pre-key upload state management @@ -1364,7 +1360,7 @@ export const makeSocket = (config: SocketConfig) => { attrs: { to: S_WHATSAPP_NET, type: 'result', - id: stanza.attrs.id ?? '' + id: stanza.attrs.id! } } await sendNode(iq) @@ -1443,9 +1439,7 @@ export const makeSocket = (config: SocketConfig) => { logger.info('opened connection to WA') clearTimeout(qrTimer) // will never happen in all likelyhood -- but just in case WA sends success on first try - if (authState.creds.me) { - ev.emit('creds.update', { me: { ...authState.creds.me, lid: node.attrs.lid } }) - } + ev.emit('creds.update', { me: { ...authState.creds.me!, lid: node.attrs.lid } }) ev.emit('connection.update', { connection: 'open' }) @@ -1468,23 +1462,13 @@ export const makeSocket = (config: SocketConfig) => { const myLID = node.attrs.lid process.nextTick(async () => { try { - const me = authState.creds.me - if (!me) { - return - } - - const myPN = me.id + const myPN = authState.creds.me!.id // Store our own LID-PN mapping await signalRepository.lidMapping.storeLIDPNMappings([{ lid: myLID, pn: myPN }]) // Create device list for our own user (needed for bulk migration) - const decoded = jidDecode(myPN) - if (!decoded) { - return - } - - const { user, device } = decoded + const { user, device } = jidDecode(myPN)! await authState.keys.set({ 'device-list': { [user]: [device?.toString() || '0'] @@ -1572,7 +1556,7 @@ export const makeSocket = (config: SocketConfig) => { logger.debug({ name }, 'updated pushName') sendNode({ tag: 'presence', - attrs: { name: name ?? '' } + attrs: { name: name! } }).catch(err => { logger.warn({ trace: err.stack }, 'error in sending presence update on name change') }) diff --git a/src/Utils/chat-utils.ts b/src/Utils/chat-utils.ts index ff872a26..6ea8ebf3 100644 --- a/src/Utils/chat-utils.ts +++ b/src/Utils/chat-utils.ts @@ -470,7 +470,7 @@ export const decodeSyncdSnapshot = async ( areMutationsRequired ? mutation => { const index = mutation.syncAction.index?.toString() - mutationMap[index ?? ''] = mutation + mutationMap[index!] = mutation } : () => {}, validateMacs @@ -558,7 +558,7 @@ export const decodePatches = async ( shouldMutate ? mutation => { const index = mutation.syncAction.index?.toString() - mutationMap[index ?? ''] = mutation + mutationMap[index!] = mutation } : () => {}, true @@ -689,7 +689,7 @@ export const chatModificationToAppPatch = (mod: ChatModification, jid: string) = messageTimestamp: timestamp } }, - index: ['deleteMessageForMe', jid, key.id ?? '', key.fromMe ? '1' : '0', '0'], + index: ['deleteMessageForMe', jid, key.id!, key.fromMe ? '1' : '0', '0'], type: 'regular_high', apiVersion: 3, operation: OP.SET @@ -896,7 +896,7 @@ export const processSyncAction = ( { id, muteEndTime: action.muteAction?.muted ? toNumber(action.muteAction.muteEndTimestamp) : null, - conditional: getChatUpdateConditional(id ?? '', undefined) + conditional: getChatUpdateConditional(id!, undefined) } ]) } else if (action?.archiveChatAction || type === 'archive' || type === 'unarchive') { @@ -925,7 +925,7 @@ export const processSyncAction = ( { id, archived: isArchived, - conditional: getChatUpdateConditional(id ?? '', msgRange) + conditional: getChatUpdateConditional(id!, msgRange) } ]) } else if (action?.markChatAsReadAction) { @@ -939,7 +939,7 @@ export const processSyncAction = ( { id, unreadCount: isNullUpdate ? null : !!markReadAction?.read ? 0 : -1, - conditional: getChatUpdateConditional(id ?? '', markReadAction?.messageRange) + conditional: getChatUpdateConditional(id!, markReadAction?.messageRange) } ]) } else if (action?.deleteMessageForMeAction || type === 'deleteMessageForMe') { @@ -965,7 +965,7 @@ export const processSyncAction = ( { id, pinned: action.pinAction?.pinned ? toNumber(action.timestamp) : null, - conditional: getChatUpdateConditional(id ?? '', undefined) + conditional: getChatUpdateConditional(id!, undefined) } ]) } else if (action?.unarchiveChatsSetting) { @@ -990,7 +990,7 @@ export const processSyncAction = ( ]) } else if (action?.deleteChatAction || type === 'deleteChat') { if (!isInitialSync) { - ev.emit('chats.delete', [id ?? '']) + ev.emit('chats.delete', [id!]) } } else if (action?.labelEditAction) { const { name, color, deleted, predefinedId } = action.labelEditAction diff --git a/src/Utils/generics.ts b/src/Utils/generics.ts index 249914dc..03bbb5dc 100644 --- a/src/Utils/generics.ts +++ b/src/Utils/generics.ts @@ -343,7 +343,7 @@ const STATUS_MAP: { [_: string]: proto.WebMessageInfo.Status } = { * @param type type from receipt */ export const getStatusFromReceiptType = (type: string | undefined) => { - const status = STATUS_MAP[type ?? ''] + const status = STATUS_MAP[type!] if (typeof type === 'undefined') { return proto.WebMessageInfo.Status.DELIVERY_ACK } diff --git a/src/Utils/history.ts b/src/Utils/history.ts index 0394b02a..d5d6183a 100644 --- a/src/Utils/history.ts +++ b/src/Utils/history.ts @@ -294,7 +294,7 @@ export const processHistoryMessage = (item: proto.IHistorySync, logger?: ILogger case proto.HistorySync.HistorySyncType.FULL: case proto.HistorySync.HistorySyncType.ON_DEMAND: for (const chat of (item.conversations ?? []) as Chat[]) { - const chatId = chat.id ?? '' + const chatId = chat.id! // Source 2: Extract LID-PN mapping from conversation object // This handles cases where the mapping isn't in phoneNumberToLidMappings @@ -371,7 +371,7 @@ export const processHistoryMessage = (item: proto.IHistorySync, logger?: ILogger break case proto.HistorySync.HistorySyncType.PUSH_NAME: for (const c of (item.pushnames ?? [])) { - contacts.push({ id: c.id ?? '', notify: c.pushname ?? '' }) + contacts.push({ id: c.id!, notify: c.pushname! }) } break diff --git a/src/Utils/messages-media.ts b/src/Utils/messages-media.ts index 6533d7b2..5271c54a 100644 --- a/src/Utils/messages-media.ts +++ b/src/Utils/messages-media.ts @@ -317,7 +317,7 @@ export const getStream = async (item: WAMediaUpload, opts?: RequestInit & { maxC const urlStr = item.url.toString() if (urlStr.startsWith('data:')) { - const buffer = Buffer.from(urlStr.split(',')[1] ?? '', 'base64') + const buffer = Buffer.from(urlStr.split(',')[1]!, 'base64') return { stream: toReadable(buffer), type: 'buffer' } as const } @@ -532,7 +532,7 @@ export const downloadContentFromMessage = async ( opts: MediaDownloadOptions = {} ) => { const isValidMediaUrl = url?.startsWith('https://mmg.whatsapp.net/') - const downloadUrl = isValidMediaUrl ? url : getUrlFromDirectPath(directPath ?? '') + const downloadUrl = isValidMediaUrl ? url : getUrlFromDirectPath(directPath!) if (!downloadUrl) { throw new Boom('No valid media URL or directPath present in message', { statusCode: 400 }) } @@ -656,7 +656,7 @@ export function extensionForMediaMessage(message: WAMessageContent) { extension = '.jpeg' } else { const messageContent = message[type] as WAGenericMediaMessage - extension = getExtension(messageContent.mimetype ?? '') ?? '' + extension = getExtension(messageContent.mimetype!)! } return extension @@ -864,8 +864,8 @@ export const getWAUploadToServer = ( if (result?.url || result?.direct_path) { urls = { - mediaUrl: result.url ?? '', - directPath: result.direct_path ?? '', + mediaUrl: result.url!, + directPath: result.direct_path!, meta_hmac: result.meta_hmac, fbid: result.fbid, ts: result.ts diff --git a/src/Utils/messages.ts b/src/Utils/messages.ts index 4e5f71d9..e2a8e2bc 100644 --- a/src/Utils/messages.ts +++ b/src/Utils/messages.ts @@ -1770,7 +1770,7 @@ export const generateWAMessageFromContent = ( const innerContent = innerMessage[key as Exclude] const contextInfo: proto.IContextInfo = (innerContent && typeof innerContent === 'object' && 'contextInfo' in innerContent && (innerContent as Record).contextInfo as proto.IContextInfo) || {} - contextInfo.participant = jidNormalizedUser(participant ?? '') + contextInfo.participant = jidNormalizedUser(participant!) contextInfo.stanzaId = quoted.key.id contextInfo.quotedMessage = quotedMsg diff --git a/src/Utils/process-message.ts b/src/Utils/process-message.ts index bf6f256f..a3604860 100644 --- a/src/Utils/process-message.ts +++ b/src/Utils/process-message.ts @@ -59,24 +59,22 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([WAMessageStubType.GROUP_PARTICIPANT_ /** Cleans a received message to further processing */ export const cleanMessage = (message: WAMessage, meId: string, meLid: string) => { // ensure remoteJid and participant doesn't have device or agent in it - const remoteJid = message.key.remoteJid ?? '' - if (isHostedPnUser(remoteJid) || isHostedLidUser(remoteJid)) { + if (isHostedPnUser(message.key.remoteJid!) || isHostedLidUser(message.key.remoteJid!)) { message.key.remoteJid = jidEncode( - jidDecode(remoteJid)?.user ?? '', - isHostedPnUser(remoteJid) ? 's.whatsapp.net' : 'lid' + jidDecode(message.key?.remoteJid!)?.user!, + isHostedPnUser(message.key.remoteJid!) ? 's.whatsapp.net' : 'lid' ) } else { - message.key.remoteJid = jidNormalizedUser(remoteJid) + message.key.remoteJid = jidNormalizedUser(message.key.remoteJid!) } - const participantJid = message.key.participant ?? '' - if (isHostedPnUser(participantJid) || isHostedLidUser(participantJid)) { + if (isHostedPnUser(message.key.participant!) || isHostedLidUser(message.key.participant!)) { message.key.participant = jidEncode( - jidDecode(participantJid)?.user ?? '', - isHostedPnUser(participantJid) ? 's.whatsapp.net' : 'lid' + jidDecode(message.key.participant!)?.user!, + isHostedPnUser(message.key.participant!) ? 's.whatsapp.net' : 'lid' ) } else { - message.key.participant = jidNormalizedUser(participantJid) + message.key.participant = jidNormalizedUser(message.key.participant!) } const content = normalizeMessageContent(message.message) @@ -102,8 +100,8 @@ export const cleanMessage = (message: WAMessage, meId: string, meLid: string) => // if the sender believed the message being reacted to is not from them // we've to correct the key to be from them, or some other participant msgKey.fromMe = !msgKey.fromMe - ? areJidsSameUser(msgKey.participant || (msgKey.remoteJid ?? ''), meId) || - areJidsSameUser(msgKey.participant || (msgKey.remoteJid ?? ''), meLid) + ? areJidsSameUser(msgKey.participant || (msgKey.remoteJid!), meId) || + areJidsSameUser(msgKey.participant || (msgKey.remoteJid!), meLid) : // if the message being reacted to, was from them // fromMe automatically becomes false false @@ -177,12 +175,11 @@ export const shouldIncrementChatUnread = (message: WAMessage) => !message.key.fr * Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant */ export const getChatId = ({ remoteJid, participant, fromMe }: WAMessageKey) => { - const jid = remoteJid ?? '' - if (isJidBroadcast(jid) && !isJidStatusBroadcast(jid) && !fromMe) { - return participant ?? '' + if (isJidBroadcast(remoteJid!) && !isJidStatusBroadcast(remoteJid!) && !fromMe) { + return participant! } - return jid + return remoteJid! } type PollContext = { @@ -478,7 +475,7 @@ const processMessage = async ( ev.emit('messages.upsert', { messages: [webMessageInfo as WAMessage], type: 'notify', - requestId: response.stanzaId ?? '' + requestId: response.stanzaId! }) } } @@ -517,10 +514,10 @@ const processMessage = async ( const labelAssociationMsg = protocolMsg.memberLabel if (labelAssociationMsg?.label) { ev.emit('group.member-tag.update', { - groupId: chat.id ?? '', + groupId: chat.id!, label: labelAssociationMsg.label, - participant: message.key.participant ?? '', - participantAlt: message.key.participantAlt ?? '', + participant: message.key.participant!, + participantAlt: message.key.participantAlt!, messageTimestamp: Number(message.messageTimestamp) }) } @@ -578,7 +575,7 @@ const processMessage = async ( const meIdNormalised = jidNormalizedUser(meId) // all jids need to be PN - const eventCreatorKey = creationMsgKey.participant || (creationMsgKey.remoteJid ?? '') + const eventCreatorKey = creationMsgKey.participant || (creationMsgKey.remoteJid!) const eventCreatorPn = isLidUser(eventCreatorKey) ? await signalRepository.lidMapping.getPNForLID(eventCreatorKey) : eventCreatorKey @@ -600,7 +597,7 @@ const processMessage = async ( const responseMsg = decryptEventResponse(encEventResponse, { eventEncKey, eventCreatorJid, - eventMsgId: creationMsgKey.id ?? '', + eventMsgId: creationMsgKey.id!, responderJid }) diff --git a/src/Utils/signal.ts b/src/Utils/signal.ts index 6900743b..fcc9d814 100644 --- a/src/Utils/signal.ts +++ b/src/Utils/signal.ts @@ -88,18 +88,14 @@ export const xmppPreKey = (pair: KeyPair, id: number): BinaryNode => ({ }) export const parseAndInjectE2ESessions = async (node: BinaryNode, repository: SignalRepositoryWithLIDStore) => { - const extractKey = (key: BinaryNode) => { - if (!key) return undefined - const keyId = getBinaryNodeChildUInt(key, 'id', 3) - const publicKeyBuf = getBinaryNodeChildBuffer(key, 'value') - const signature = getBinaryNodeChildBuffer(key, 'signature') - if (keyId === undefined || !publicKeyBuf || !signature) return undefined - return { - keyId, - publicKey: generateSignalPubKey(publicKeyBuf), - signature - } - } + const extractKey = (key: BinaryNode) => + key + ? { + keyId: getBinaryNodeChildUInt(key, 'id', 3)!, + publicKey: generateSignalPubKey(getBinaryNodeChildBuffer(key, 'value')!), + signature: getBinaryNodeChildBuffer(key, 'signature')! + } + : undefined const nodes = getBinaryNodeChildren(getBinaryNodeChild(node, 'list'), 'user') for (const node of nodes) { assertNodeErrorFree(node) @@ -115,26 +111,20 @@ export const parseAndInjectE2ESessions = async (node: BinaryNode, repository: Si for (const nodesChunk of chunks) { for (const node of nodesChunk) { - const signedKey = getBinaryNodeChild(node, 'skey') - const key = getBinaryNodeChild(node, 'key') - const identity = getBinaryNodeChildBuffer(node, 'identity') - const jid = node.attrs.jid - if (!signedKey || !key || !identity || !jid) continue + const signedKey = getBinaryNodeChild(node, 'skey')! + const key = getBinaryNodeChild(node, 'key')! + const identity = getBinaryNodeChildBuffer(node, 'identity')! + const jid = node.attrs.jid! const registrationId = getBinaryNodeChildUInt(node, 'registration', 4) - if (registrationId === undefined) continue - - const signedPreKey = extractKey(signedKey) - const preKey = extractKey(key) - if (!signedPreKey || !preKey) continue await repository.injectE2ESession({ jid, session: { - registrationId, + registrationId: registrationId!, identityKey: generateSignalPubKey(identity), - signedPreKey, - preKey + signedPreKey: extractKey(signedKey)!, + preKey: extractKey(key)! } }) } @@ -147,18 +137,14 @@ export const extractDeviceJids = ( myLid: string, excludeZeroDevices: boolean ) => { - const myJidDecoded = jidDecode(myJid) - if (!myJidDecoded) return [] - - const { user: myUser, device: myDevice } = myJidDecoded + const { user: myUser, device: myDevice } = jidDecode(myJid)! const extracted: FullJid[] = [] for (const userResult of result) { const { devices, id } = userResult as { devices: ParsedDeviceInfo; id: string } - const decoded = jidDecode(id) - if (!decoded) continue - const { user, server } = decoded + const decoded = jidDecode(id)!, + { user, server } = decoded let { domainType } = decoded const deviceList = devices?.deviceList as DeviceListData[] if (!Array.isArray(deviceList)) continue diff --git a/src/Utils/validate-connection.ts b/src/Utils/validate-connection.ts index 6b1f3e13..8e4c73b9 100644 --- a/src/Utils/validate-connection.ts +++ b/src/Utils/validate-connection.ts @@ -237,7 +237,7 @@ export const configureSuccessfulPairing = ( content: [ { tag: 'device-identity', - attrs: { 'key-index': String(deviceIdentity.keyIndex ?? '') }, + attrs: { 'key-index': deviceIdentity.keyIndex!.toString() }, content: accountEnc } ] diff --git a/src/WABinary/jid-utils.ts b/src/WABinary/jid-utils.ts index 34dd447c..0c42456f 100644 --- a/src/WABinary/jid-utils.ts +++ b/src/WABinary/jid-utils.ts @@ -63,7 +63,7 @@ export const jidDecode = (jid: string | undefined): FullJid | undefined => { const userCombined = jid.slice(0, sepIdx) const [userAgent, device] = userCombined.split(':') - const [user, agent] = (userAgent ?? '').split('_') + const [user, agent] = userAgent!.split('_') let domainType = WAJIDDomains.WHATSAPP if (server === 'lid') { @@ -78,7 +78,7 @@ export const jidDecode = (jid: string | undefined): FullJid | undefined => { return { server: server as JidServer, - user: user ?? '', + user: user!, domainType, device: device ? +device : undefined } @@ -114,7 +114,7 @@ export const isAnyPnUser = (jid: string | undefined) => const botRegexp = /^1313555\d{4}$|^131655500\d{2}$/ -export const isJidBot = (jid: string | undefined) => jid && botRegexp.test(jid.split('@')[0] ?? '') && jid.endsWith('@c.us') +export const isJidBot = (jid: string | undefined) => jid && botRegexp.test(jid.split('@')[0]!) && jid.endsWith('@c.us') export const jidNormalizedUser = (jid: string | undefined) => { const result = jidDecode(jid) diff --git a/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts index 6435c6eb..fa999008 100644 --- a/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts +++ b/src/WAUSync/Protocols/UsyncBotProfileProtocol.ts @@ -35,7 +35,7 @@ export class USyncBotProfileProtocol implements USyncQueryProtocol { return { tag: 'bot', attrs: {}, - content: [{ tag: 'profile', attrs: { persona_id: user.personaId ?? '' } }] + content: [{ tag: 'profile', attrs: { persona_id: user.personaId! } }] } } @@ -51,24 +51,24 @@ export class USyncBotProfileProtocol implements USyncQueryProtocol { for (const command of getBinaryNodeChildren(commandsNode, 'command')) { commands.push({ - name: getBinaryNodeChildString(command, 'name') ?? '', - description: getBinaryNodeChildString(command, 'description') ?? '' + name: getBinaryNodeChildString(command, 'name')!, + description: getBinaryNodeChildString(command, 'description')! }) } for (const prompt of getBinaryNodeChildren(promptsNode, 'prompt')) { - prompts.push(`${getBinaryNodeChildString(prompt, 'emoji') ?? ''} ${getBinaryNodeChildString(prompt, 'text') ?? ''}`) + prompts.push(`${getBinaryNodeChildString(prompt, 'emoji')!} ${getBinaryNodeChildString(prompt, 'text')!}`) } return { isDefault: !!getBinaryNodeChild(profile, 'default'), - jid: node.attrs.jid ?? '', - name: getBinaryNodeChildString(profile, 'name') ?? '', - attributes: getBinaryNodeChildString(profile, 'attributes') ?? '', - description: getBinaryNodeChildString(profile, 'description') ?? '', - category: getBinaryNodeChildString(profile, 'category') ?? '', - personaId: profile?.attrs['persona_id'] ?? '', - commandsDescription: getBinaryNodeChildString(commandsNode, 'description') ?? '', + jid: node.attrs.jid!, + name: getBinaryNodeChildString(profile, 'name')!, + attributes: getBinaryNodeChildString(profile, 'attributes')!, + description: getBinaryNodeChildString(profile, 'description')!, + category: getBinaryNodeChildString(profile, 'category')!, + personaId: profile!.attrs['persona_id']!, + commandsDescription: getBinaryNodeChildString(commandsNode, 'description')!, commands, prompts }