d08a09c35f
* feat: add inbound username support and USync username protocol Aligns with Baileys upstream PR #2480. WhatsApp is rolling out an inbound username field that maps to the user's LID. This change is purely additive — it captures and propagates the new optional field through types, decoders, USync queries, and group/contact events. Skipped intentionally to preserve InfiniteAPI's LID/PN customization: - handleGroupNotification in messages-recv.ts (custom LID->PN flow on groups.upsert / participants.map). Username for these specific events still flows via process-message's emitParticipantsUpdate (reads message.key.participantUsername added in decode-wa-message). Carousel/buttons code (messages.ts, messages-send.ts) untouched. Co-Authored-By: Renato Alcara
223 lines
8.5 KiB
TypeScript
223 lines
8.5 KiB
TypeScript
import type { Boom } from '@hapi/boom'
|
|
import { proto } from '../../WAProto/index.js'
|
|
import type { AuthenticationCreds, LIDMapping } from './Auth'
|
|
import type { WACallEvent } from './Call'
|
|
import type { Chat, ChatUpdate, PresenceData } from './Chat'
|
|
import type { Contact } from './Contact'
|
|
import type {
|
|
GroupMetadata,
|
|
GroupParticipant,
|
|
ParticipantAction,
|
|
RequestJoinAction,
|
|
RequestJoinMethod
|
|
} from './GroupMetadata'
|
|
import type { Label } from './Label'
|
|
import type { LabelAssociation } from './LabelAssociation'
|
|
import type { MessageUpsertType, MessageUserReceiptUpdate, WAMessage, WAMessageKey, WAMessageUpdate } from './Message'
|
|
import type { ConnectionState } from './State'
|
|
|
|
// TODO: refactor this mess
|
|
export type BaileysEventMap = {
|
|
/** connection state has been updated -- WS closed, opened, connecting etc. */
|
|
'connection.update': Partial<ConnectionState>
|
|
/** credentials updated -- some metadata, keys or something */
|
|
'creds.update': Partial<AuthenticationCreds>
|
|
/** set chats (history sync), everything is reverse chronologically sorted */
|
|
'messaging-history.set': {
|
|
chats: Chat[]
|
|
contacts: Contact[]
|
|
messages: WAMessage[]
|
|
/** Past participants for group chats (people who left/were removed). userJid is always a phone number (PN), never a LID. */
|
|
pastParticipants?: proto.IPastParticipants[] | null
|
|
isLatest?: boolean
|
|
progress?: number | null
|
|
syncType?: proto.HistorySync.HistorySyncType | null
|
|
chunkOrder?: number | null
|
|
peerDataRequestSessionId?: string | null
|
|
}
|
|
/** signals history sync milestones (completion or stall) per sync type */
|
|
'messaging-history.status': {
|
|
/** which sync phase this status refers to */
|
|
syncType: proto.HistorySync.HistorySyncType
|
|
/** the status of this sync phase */
|
|
status: 'complete' | 'paused'
|
|
/**
|
|
* progress === 100 was received from the server.
|
|
* when false, completion was inferred via timeout (no more chunks arriving).
|
|
*/
|
|
explicit: boolean
|
|
}
|
|
/** upsert chats */
|
|
'chats.upsert': Chat[]
|
|
/** update the given chats */
|
|
'chats.update': ChatUpdate[]
|
|
'lid-mapping.update': LIDMapping[]
|
|
/** delete chats with given ID */
|
|
'chats.delete': string[]
|
|
/** presence of contact in a chat updated */
|
|
'presence.update': { id: string; presences: { [participant: string]: PresenceData } }
|
|
|
|
'contacts.upsert': Contact[]
|
|
'contacts.update': Partial<Contact>[]
|
|
|
|
'messages.delete': { keys: WAMessageKey[] } | { jid: string; all: true }
|
|
'messages.update': WAMessageUpdate[]
|
|
'messages.media-update': { key: WAMessageKey; media?: { ciphertext: Uint8Array; iv: Uint8Array }; error?: Boom }[]
|
|
/**
|
|
* add/update the given messages. If they were received while the connection was online,
|
|
* the update will have type: "notify"
|
|
* if requestId is provided, then the messages was received from the phone due to it being unavailable
|
|
* */
|
|
'messages.upsert': { messages: WAMessage[]; type: MessageUpsertType; requestId?: string }
|
|
/** message was reacted to. If reaction was removed -- then "reaction.text" will be falsey */
|
|
'messages.reaction': { key: WAMessageKey; reaction: proto.IReaction }[]
|
|
|
|
'message-receipt.update': MessageUserReceiptUpdate[]
|
|
|
|
'groups.upsert': GroupMetadata[]
|
|
'groups.update': Partial<GroupMetadata>[]
|
|
/** apply an action to participants in a group */
|
|
'group-participants.update': {
|
|
id: string
|
|
author: string
|
|
authorPn?: string
|
|
authorUsername?: string
|
|
participants: GroupParticipant[]
|
|
action: ParticipantAction
|
|
}
|
|
'group.join-request': {
|
|
id: string
|
|
author: string
|
|
authorPn?: string
|
|
authorUsername?: string
|
|
participant: string
|
|
participantPn?: string
|
|
action: RequestJoinAction
|
|
method: RequestJoinMethod
|
|
}
|
|
/* update the labels assigned to a group participant */
|
|
'group.member-tag.update': {
|
|
groupId: string
|
|
participant: string
|
|
participantAlt?: string
|
|
label: string
|
|
messageTimestamp?: number
|
|
}
|
|
|
|
'blocklist.set': { blocklist: string[] }
|
|
'blocklist.update': { blocklist: string[]; type: 'add' | 'remove' }
|
|
|
|
/** Receive an update on a call, including when the call was received, rejected, accepted */
|
|
call: WACallEvent[]
|
|
'labels.edit': Label
|
|
'labels.association': { association: LabelAssociation; type: 'add' | 'remove' }
|
|
|
|
/** Newsletter-related events */
|
|
'newsletter.reaction': {
|
|
id: string
|
|
server_id: string
|
|
reaction: { code?: string; count?: number; removed?: boolean }
|
|
}
|
|
'newsletter.view': { id: string; server_id: string; count: number }
|
|
'newsletter-participants.update': { id: string; author: string; user: string; new_role: string; action: string }
|
|
'newsletter-settings.update': { id: string; update: any }
|
|
|
|
/** Settings and actions sync events */
|
|
'chats.lock': { id: string; locked: boolean }
|
|
/**
|
|
* Emitted when a new WhatsApp Web version is detected.
|
|
* The new version will be used on the next reconnection (soft update).
|
|
*/
|
|
'version.update': {
|
|
/** Previous version */
|
|
currentVersion: [number, number, number]
|
|
/** New version detected */
|
|
newVersion: [number, number, number]
|
|
/** Whether the update is critical (major version change) */
|
|
isCritical: boolean
|
|
}
|
|
'settings.update':
|
|
| { setting: 'unarchiveChats'; value: boolean }
|
|
| { setting: 'locale'; value: string }
|
|
| { setting: 'disableLinkPreviews'; value: proto.SyncActionValue.IPrivacySettingDisableLinkPreviewsAction }
|
|
| { setting: 'timeFormat'; value: proto.SyncActionValue.ITimeFormatAction }
|
|
| { setting: 'privacySettingRelayAllCalls'; value: proto.SyncActionValue.IPrivacySettingRelayAllCalls }
|
|
| { setting: 'statusPrivacy'; value: proto.SyncActionValue.IStatusPrivacyAction }
|
|
| {
|
|
setting: 'notificationActivitySetting'
|
|
value: proto.SyncActionValue.NotificationActivitySettingAction.NotificationActivitySetting
|
|
}
|
|
| {
|
|
setting: 'channelsPersonalisedRecommendation'
|
|
value: proto.SyncActionValue.IPrivacySettingChannelsPersonalisedRecommendationAction
|
|
}
|
|
|
|
/**
|
|
* Emitted when a contact's Signal identity key changes.
|
|
* This typically indicates the contact reinstalled WhatsApp or switched devices.
|
|
* Applications can use this to notify users about the security code change,
|
|
* similar to the "Security code changed" notification in the official WhatsApp client.
|
|
*/
|
|
'identity.changed': {
|
|
/** JID of the contact whose identity key changed */
|
|
jid: string
|
|
/** SHA-256 fingerprint of the previous identity key (hex string) */
|
|
previousKeyFingerprint: string | null
|
|
/** SHA-256 fingerprint of the new identity key (hex string) */
|
|
newKeyFingerprint: string
|
|
/** Timestamp when the change was detected */
|
|
timestamp: number
|
|
/** Whether this is a new contact (true) or an existing contact with changed key (false) */
|
|
isNewContact: boolean
|
|
}
|
|
|
|
/**
|
|
* Emitted when the session TTL (Time-To-Live) expires after 7 days.
|
|
* Applications can listen to this event to perform graceful cleanup,
|
|
* flush pending operations, or rotate credentials before the socket closes.
|
|
*/
|
|
'session.ttl-expired': {
|
|
/** Timestamp when the session started (Date.now()) */
|
|
startTime: number | undefined
|
|
/** Duration of the session in milliseconds */
|
|
duration: number
|
|
}
|
|
}
|
|
|
|
export type BufferedEventData = {
|
|
historySets: {
|
|
chats: { [jid: string]: Chat }
|
|
contacts: { [jid: string]: Contact }
|
|
messages: { [uqId: string]: WAMessage }
|
|
/** Keyed by groupJid for O(1) deduplication across chunks */
|
|
pastParticipants: { [groupJid: string]: proto.IPastParticipant[] }
|
|
empty: boolean
|
|
isLatest: boolean
|
|
progress?: number | null
|
|
syncType?: proto.HistorySync.HistorySyncType
|
|
chunkOrder?: number | null
|
|
peerDataRequestSessionId?: string
|
|
}
|
|
chatUpserts: { [jid: string]: Chat }
|
|
chatUpdates: { [jid: string]: ChatUpdate }
|
|
chatDeletes: Set<string>
|
|
contactUpserts: { [jid: string]: Contact }
|
|
contactUpdates: { [jid: string]: Partial<Contact> }
|
|
messageUpserts: { [key: string]: { type: MessageUpsertType; message: WAMessage } }
|
|
messageUpdates: { [key: string]: WAMessageUpdate }
|
|
messageDeletes: { [key: string]: WAMessageKey }
|
|
messageReactions: { [key: string]: { key: WAMessageKey; reactions: proto.IReaction[] } }
|
|
messageReceipts: { [key: string]: { key: WAMessageKey; userReceipt: proto.IUserReceipt[] } }
|
|
groupUpdates: { [jid: string]: Partial<GroupMetadata> }
|
|
lidMappings: { [key: string]: LIDMapping }
|
|
}
|
|
|
|
export type BaileysEvent = keyof BaileysEventMap
|
|
|
|
export interface BaileysEventEmitter {
|
|
on<T extends keyof BaileysEventMap>(event: T, listener: (arg: BaileysEventMap[T]) => void): void
|
|
off<T extends keyof BaileysEventMap>(event: T, listener: (arg: BaileysEventMap[T]) => void): void
|
|
removeAllListeners<T extends keyof BaileysEventMap>(event: T): void
|
|
emit<T extends keyof BaileysEventMap>(event: T, arg: BaileysEventMap[T]): boolean
|
|
}
|