fix(types): remove non-null assertions across 14 files

Files fixed:
- messages-recv.ts: 58 assertions → null guards, meId extraction, optional chaining
- process-message.ts: 38 assertions → remoteJid/participant guards, proto field checks
- chat-utils.ts: 31 assertions → proto field validation with Boom errors
- messages-send.ts: 20 assertions → meId extraction, participant guards
- chats.ts: 15 assertions → me guard, firstChild guard, jid guards
- messages.ts: 14 assertions → originalFilePath guard, key guards
- groups.ts: 12 assertions → attrs fallbacks with ??
- validate-connection.ts: 9 assertions → grouped proto field validation
- generics.ts: 1 assertion → versionLine guard
- history.ts: 2 assertions → key guards
- libsignal.ts: 1 assertion → deviceId guard
- sender-key-message.ts: 3 assertions → proto guards
- UsyncBotProfileProtocol.ts: 2 assertions → attrs guards
- example.ts: 3 assertions → optional chaining

https://claude.ai/code/session_01E2cfX1N3sJgCJBTvzGazSG
This commit is contained in:
Claude
2026-02-09 00:05:13 +00:00
parent 8fd10c8b9b
commit 7e88ddb858
14 changed files with 561 additions and 244 deletions
+40 -26
View File
@@ -126,15 +126,16 @@ export const makeMessagesSocket = (config: SocketConfig) => {
},
content: [{ tag: 'media_conn', attrs: {} }]
})
const mediaConnNode = getBinaryNodeChild(result, 'media_conn')!
const mediaConnNode = getBinaryNodeChild(result, 'media_conn')
if (!mediaConnNode) throw new Boom('Missing media_conn node')
// TODO: explore full length of data that whatsapp provides
const node: MediaConnInfo = {
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
hostname: attrs.hostname!,
maxContentLengthBytes: +attrs.maxContentLengthBytes!
hostname: attrs.hostname ?? '',
maxContentLengthBytes: +(attrs.maxContentLengthBytes ?? 0)
})),
auth: mediaConnNode.attrs.auth!,
ttl: +mediaConnNode.attrs.ttl!,
auth: mediaConnNode.attrs.auth ?? '',
ttl: +(mediaConnNode.attrs.ttl ?? 0),
fetchDate: new Date()
}
logger.debug('fetched media conn')
@@ -162,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'
@@ -171,8 +172,9 @@ export const makeMessagesSocket = (config: SocketConfig) => {
}
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
if (!participant) throw new Boom('Missing participant for sender receipt')
node.attrs.recipient = jid
node.attrs.to = participant!
node.attrs.to = participant
} else {
node.attrs.to = jid
if (participant) {
@@ -266,10 +268,11 @@ 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,
@@ -324,10 +327,14 @@ export const makeMessagesSocket = (config: SocketConfig) => {
}
}
const meId = authState.creds.me?.id
if (!meId) throw new Boom('Not authenticated', { statusCode: 401 })
const meLid = authState.creds.me?.lid || ''
const extracted = extractDeviceJids(
result?.list,
authState.creds.me!.id,
authState.creds.me!.lid!,
meId,
meLid,
ignoreZeroDevices
)
const deviceMap: { [_: string]: FullJid[] } = {}
@@ -547,7 +554,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }))
let shouldIncludeDeviceIdentity = false
const meId = authState.creds.me!.id
const meId = authState.creds.me?.id
if (!meId) throw new Boom('Not authenticated', { statusCode: 401 })
const meLid = authState.creds.me?.lid
const meLidUser = meLid ? jidDecode(meLid)?.user : null
@@ -559,8 +567,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
let msgToEncrypt = patchedMessage
if (dsmMessage) {
const { user: targetUser } = jidDecode(jid)!
const { user: ownPnUser } = jidDecode(meId)!
const targetUser = jidDecode(jid)?.user ?? ''
const ownPnUser = jidDecode(meId)?.user ?? ''
const ownLidUser = meLidUser
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
@@ -816,13 +824,16 @@ export const makeMessagesSocket = (config: SocketConfig) => {
statusJidList
}: MessageRelayOptions
) => {
const meId = authState.creds.me!.id
const meId = authState.creds.me?.id
if (!meId) throw new Boom('Not authenticated', { statusCode: 401 })
const meLid = authState.creds.me?.lid
const isRetryResend = Boolean(participant?.jid)
let shouldIncludeDeviceIdentity = isRetryResend
const statusJid = 'status@broadcast'
const { user, server } = jidDecode(jid)!
const jidDecoded = jidDecode(jid)
if (!jidDecoded) throw new Boom('Invalid JID')
const { user, server } = jidDecoded
const isGroup = server === 'g.us'
const isStatus = jid === statusJid
const isLid = server === 'lid'
@@ -910,7 +921,9 @@ export const makeMessagesSocket = (config: SocketConfig) => {
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
}
const { user, device } = jidDecode(participant.jid)!
const participantDecoded = jidDecode(participant.jid)
if (!participantDecoded) throw new Boom('Invalid participant JID')
const { user, device } = participantDecoded
devices.push({
user,
device,
@@ -1068,7 +1081,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
}
const { user: ownUser } = jidDecode(ownId)!
const ownUser = jidDecode(ownId)?.user ?? ''
if (!participant) {
const patchedForReporting = await patchMessageBeforeSending(message, [jid])
reportingMessage = Array.isArray(patchedForReporting)
@@ -1086,7 +1099,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,
@@ -1102,8 +1115,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)
@@ -1122,8 +1135,8 @@ export const makeMessagesSocket = (config: SocketConfig) => {
const allRecipients: string[] = []
const meRecipients: string[] = []
const otherRecipients: string[] = []
const { user: mePnUser } = jidDecode(meId)!
const { user: meLidUser } = meLid ? jidDecode(meLid)! : { user: null }
const mePnUser = jidDecode(meId)?.user ?? ''
const meLidUser = meLid ? (jidDecode(meLid)?.user ?? null) : null
// Carousel in DSM wrapper causes error 479 on own devices
const isCarouselMsg = isCarouselMessage(message)
@@ -1172,10 +1185,11 @@ export const makeMessagesSocket = (config: SocketConfig) => {
}
if (isRetryResend) {
if (!participant) throw new Boom('Missing participant for retry resend')
// Only check for regular LID users, NOT hosted LID users
// Hosted LID users should use meId for comparison, not meLid
const isParticipantLid = isLidUser(participant!.jid)
const isMe = areJidsSameUser(participant!.jid, isParticipantLid ? meLid : meId)
const isParticipantLid = isLidUser(participant.jid)
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId)
// Skip DSM for carousel - own devices reject it with error 479
const usesDSM = isMe && !isCarouselMessage(message)
@@ -1190,7 +1204,7 @@ export const makeMessagesSocket = (config: SocketConfig) => {
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
data: encodedMessageToSend,
jid: participant!.jid
jid: participant.jid
})
binaryNodeContent.push({