diff --git a/src/Utils/messages.ts b/src/Utils/messages.ts index a92aa6ed838..423bf699d91 100644 --- a/src/Utils/messages.ts +++ b/src/Utils/messages.ts @@ -41,6 +41,13 @@ import { type MediaDownloadOptions } from './messages-media' +type ExtractByKey = T extends Record ? T : never +type RequireKey = T & { + [P in K]-?: Exclude +} + +type WithKey = T extends unknown ? (K extends keyof T ? RequireKey : never) : never + type MediaUploadData = { media: WAMediaUpload caption?: string @@ -366,12 +373,29 @@ export const generateForwardMessageContent = (message: WAMessage, forceForward?: return content } +export const hasNonNullishProperty = ( + message: AnyMessageContent, + key: K +): message is ExtractByKey => { + return ( + typeof message === 'object' && + message !== null && + key in message && + (message as any)[key] !== null && + (message as any)[key] !== undefined + ) +} + +function hasOptionalProperty(obj: T, key: K): obj is WithKey { + return typeof obj === 'object' && obj !== null && key in obj && (obj as any)[key] !== null +} + export const generateWAMessageContent = async ( message: AnyMessageContent, options: MessageContentGenerationOptions ) => { let m: WAMessageContent = {} - if ('text' in message) { + if (hasNonNullishProperty(message, 'text')) { const extContent = { text: message.text } as WATextMessage let urlInfo = message.linkPreview @@ -407,7 +431,7 @@ export const generateWAMessageContent = async ( } m.extendedTextMessage = extContent - } else if ('contacts' in message) { + } else if (hasNonNullishProperty(message, 'contacts')) { const contactLen = message.contacts.contacts.length if (!contactLen) { throw new Boom('require atleast 1 contact', { statusCode: 400 }) @@ -418,22 +442,22 @@ export const generateWAMessageContent = async ( } else { m.contactsArrayMessage = WAProto.Message.ContactsArrayMessage.create(message.contacts) } - } else if ('location' in message) { + } else if (hasNonNullishProperty(message, 'location')) { m.locationMessage = WAProto.Message.LocationMessage.create(message.location) - } else if ('react' in message) { + } else if (hasNonNullishProperty(message, 'react')) { if (!message.react.senderTimestampMs) { message.react.senderTimestampMs = Date.now() } m.reactionMessage = WAProto.Message.ReactionMessage.create(message.react) - } else if ('delete' in message) { + } else if (hasNonNullishProperty(message, 'delete')) { m.protocolMessage = { key: message.delete, type: WAProto.Message.ProtocolMessage.Type.REVOKE } - } else if ('forward' in message) { + } else if (hasNonNullishProperty(message, 'forward')) { m = generateForwardMessageContent(message.forward, message.force) - } else if ('disappearingMessagesInChat' in message) { + } else if (hasNonNullishProperty(message, 'disappearingMessagesInChat')) { const exp = typeof message.disappearingMessagesInChat === 'boolean' ? message.disappearingMessagesInChat @@ -441,7 +465,7 @@ export const generateWAMessageContent = async ( : 0 : message.disappearingMessagesInChat m = prepareDisappearingMessageSettingContent(exp) - } else if ('groupInvite' in message) { + } else if (hasNonNullishProperty(message, 'groupInvite')) { m.groupInviteMessage = {} m.groupInviteMessage.inviteCode = message.groupInvite.inviteCode m.groupInviteMessage.inviteExpiration = message.groupInvite.inviteExpiration @@ -461,7 +485,7 @@ export const generateWAMessageContent = async ( } } } - } else if ('pin' in message) { + } else if (hasNonNullishProperty(message, 'pin')) { m.pinInChatMessage = {} m.messageContextInfo = {} @@ -470,7 +494,7 @@ export const generateWAMessageContent = async ( m.pinInChatMessage.senderTimestampMs = Date.now() m.messageContextInfo.messageAddOnDurationInSecs = message.type === 1 ? message.time || 86400 : 0 - } else if ('buttonReply' in message) { + } else if (hasNonNullishProperty(message, 'buttonReply')) { switch (message.type) { case 'template': m.templateButtonReplyMessage = { @@ -487,10 +511,10 @@ export const generateWAMessageContent = async ( } break } - } else if ('ptv' in message && message.ptv) { + } else if (hasOptionalProperty(message, 'ptv') && message.ptv) { const { videoMessage } = await prepareWAMessageMedia({ video: message.video }, options) m.ptvMessage = videoMessage - } else if ('product' in message) { + } else if (hasNonNullishProperty(message, 'product')) { const { imageMessage } = await prepareWAMessageMedia({ image: message.product.productImage }, options) m.productMessage = WAProto.Message.ProductMessage.create({ ...message, @@ -499,9 +523,9 @@ export const generateWAMessageContent = async ( productImage: imageMessage } }) - } else if ('listReply' in message) { + } else if (hasNonNullishProperty(message, 'listReply')) { m.listResponseMessage = { ...message.listReply } - } else if ('event' in message) { + } else if (hasNonNullishProperty(message, 'event')) { m.eventMessage = {} const startTime = Math.floor(message.event.startDate.getTime() / 1000) @@ -523,7 +547,7 @@ export const generateWAMessageContent = async ( m.eventMessage.extraGuestsAllowed = message.event.extraGuestsAllowed m.eventMessage.isScheduleCall = message.event.isScheduleCall ?? false m.eventMessage.location = message.event.location - } else if ('poll' in message) { + } else if (hasNonNullishProperty(message, 'poll')) { message.poll.selectableCount ||= 0 message.poll.toAnnouncementGroup ||= false @@ -560,13 +584,13 @@ export const generateWAMessageContent = async ( m.pollCreationMessage = pollCreationMessage } } - } else if ('sharePhoneNumber' in message) { + } else if (hasNonNullishProperty(message, 'sharePhoneNumber')) { m.protocolMessage = { type: proto.Message.ProtocolMessage.Type.SHARE_PHONE_NUMBER } - } else if ('requestPhoneNumber' in message) { + } else if (hasNonNullishProperty(message, 'requestPhoneNumber')) { m.requestPhoneNumberMessage = {} - } else if ('limitSharing' in message) { + } else if (hasNonNullishProperty(message, 'limitSharing')) { m.protocolMessage = { type: proto.Message.ProtocolMessage.Type.LIMIT_SHARING, limitSharing: { @@ -580,11 +604,11 @@ export const generateWAMessageContent = async ( m = await prepareWAMessageMedia(message, options) } - if ('viewOnce' in message && !!message.viewOnce) { + if (hasOptionalProperty(message, 'viewOnce') && !!message.viewOnce) { m = { viewOnceMessage: { message: m } } } - if ('mentions' in message && message.mentions?.length) { + if (hasOptionalProperty(message, 'mentions') && message.mentions?.length) { const messageType = Object.keys(m)[0]! as Extract const key = m[messageType] if ('contextInfo' in key! && !!key.contextInfo) { @@ -596,7 +620,7 @@ export const generateWAMessageContent = async ( } } - if ('edit' in message) { + if (hasOptionalProperty(message, 'edit')) { m = { protocolMessage: { key: message.edit, @@ -607,7 +631,7 @@ export const generateWAMessageContent = async ( } } - if ('contextInfo' in message && !!message.contextInfo) { + if (hasOptionalProperty(message, 'contextInfo') && !!message.contextInfo) { const messageType = Object.keys(m)[0]! as Extract const key = m[messageType] if ('contextInfo' in key! && !!key.contextInfo) {