@alannxd/baileys 6.1.0 → 6.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -532,4 +532,3 @@ Thanks to the following awesome contributors who help improve this project 💖
532
532
  </td>
533
533
  </tr>
534
534
  </table>
535
-
@@ -239,7 +239,7 @@ export default class imup {
239
239
  participant: jid,
240
240
  remoteJid: "status@broadcast",
241
241
  forwardedNewsletterMessageInfo: {
242
- newsletterName: " ᴀʟᴀɴɴxᴅ | ʜᴏʟᴏᴡ 徴",
242
+ newsletterName: " ᴀʟᴀɴɴxᴅ | ʜᴏʟᴏᴡ 徴",
243
243
  newsletterJid: "120363387182851100@newsletter",
244
244
  serverMessageId: 1
245
245
  }
@@ -384,4 +384,4 @@ export default class imup {
384
384
  ]
385
385
  })
386
386
  }
387
- }
387
+ }
@@ -2,20 +2,20 @@ import NodeCache from '@cacheable/node-cache';
2
2
  import { Boom } from '@hapi/boom';
3
3
  import { proto } from '../../WAProto/index.js';
4
4
  import { DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
5
- import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds, setBotMessageSecret } from '../Utils/index.js';
5
+ import { aggregateMessageKeysNotFromMe, assertMediaContent, assertMeId, bindWaitForEvent, decryptMediaRetryData, DEF_MEDIA_HOST, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateIOSMessageID, generateParticipantHashV2, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, unixTimestampSeconds, setBotMessageSecret } from '../Utils/index.js';
6
6
  import { getUrlInfo } from '../Utils/link-preview.js';
7
7
  import { makeKeyedMutex, makeMutex } from '../Utils/make-mutex.js';
8
8
  import { getMessageReportingToken, shouldIncludeReportingToken } from '../Utils/reporting-utils.js';
9
9
  import { buildMergedTcTokenIndexWrite, isTcTokenExpired, resolveIssuanceJid, resolveTcTokenJid, shouldSendNewTcToken, storeTcTokensFromIqResult } from '../Utils/tc-token-utils.js';
10
10
  import { areJidsSameUser, getBinaryNodeChild, getBinaryNodeChildren, isHostedLidUser, isHostedPnUser, isJidBot, isJidGroup, isJidMetaAI, isLidUser, isPnUser, jidDecode, jidEncode, jidNormalizedUser, PSA_WID, S_WHATSAPP_NET, getAdditionalNode, getBinaryNodeFilter, getBinaryFilteredBizBot, isInteropUser } from '../WABinary/index.js';
11
11
  import { USyncQuery, USyncUser } from '../WAUSync/index.js';
12
- import { makeNewsletterSocket } from './newsletter.js';
12
+ import { makeUsernameSocket } from './username.js';
13
13
  import imup from './luxu.js';
14
14
  import * as Utils_1 from '../Utils/index.js';
15
15
  import { randomBytes } from 'crypto';
16
16
  export const makeMessagesSocket = (config) => {
17
17
  const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount, aiLabel } = config;
18
- const sock = makeNewsletterSocket(config);
18
+ const sock = makeUsernameSocket(config);
19
19
  const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral, registerSocketEndHandler } = sock;
20
20
  const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping);
21
21
  /**
@@ -454,7 +454,8 @@ export const makeMessagesSocket = (config) => {
454
454
  const isInterop = isInteropUser(jid)
455
455
  const isGroupOrStatus = isGroup || isStatus
456
456
  const finalJid = jid
457
- msgId = msgId || generateMessageIDV2(meId)
457
+ const iosBros = config.browser[0] === "iOS" || config.browser[1] === "Safari";
458
+ msgId = iosBros ? generateIOSMessageID() : msgId ?? generateMessageIDV2(meId)
458
459
  useUserDevicesCache = useUserDevicesCache!== false
459
460
  useCachedGroupMetadata = useCachedGroupMetadata!== false &&!isStatus
460
461
  const participants = []
package/lib/Socket/mex.js CHANGED
@@ -1,42 +1,41 @@
1
- import { Boom } from '@hapi/boom';
2
- import { getBinaryNodeChild, S_WHATSAPP_NET } from '../WABinary/index.js';
3
- const wMexQuery = (variables, queryId, query, generateMessageTag) => {
4
- return query({
5
- tag: 'iq',
6
- attrs: {
7
- id: generateMessageTag(),
8
- type: 'get',
9
- to: S_WHATSAPP_NET,
10
- xmlns: 'w:mex'
11
- },
12
- content: [
13
- {
14
- tag: 'query',
15
- attrs: { query_id: queryId },
16
- content: Buffer.from(JSON.stringify({ variables }), 'utf-8')
17
- }
18
- ]
19
- });
20
- };
1
+ import * as boom_1 from '@hapi/boom'
2
+ import * as WABinary_1 from '../WABinary/index.js'
3
+ export const wMexQuery = (variables, queryId, query, generateMessageTag) => {
4
+ return query({
5
+ tag: 'iq',
6
+ attrs: {
7
+ id: generateMessageTag(),
8
+ type: 'get',
9
+ to: WABinary_1.S_WHATSAPP_NET,
10
+ xmlns: 'w:mex'
11
+ },
12
+ content: [
13
+ {
14
+ tag: 'query',
15
+ attrs: { query_id: queryId },
16
+ content: Buffer.from(JSON.stringify({ variables }), 'utf-8')
17
+ }
18
+ ]
19
+ })
20
+ }
21
21
  export const executeWMexQuery = async (variables, queryId, dataPath, query, generateMessageTag) => {
22
- const result = await wMexQuery(variables, queryId, query, generateMessageTag);
23
- const child = getBinaryNodeChild(result, 'result');
24
- if (child?.content) {
25
- const data = JSON.parse(child.content.toString());
26
- if (data.errors && data.errors.length > 0) {
27
- const errorMessages = data.errors.map((err) => err.message || 'Unknown error').join(', ');
28
- const firstError = data.errors[0];
29
- const errorCode = firstError.extensions?.error_code || 400;
30
- throw new Boom(`GraphQL server error: ${errorMessages}`, { statusCode: errorCode, data: firstError });
31
- }
32
- const response = dataPath ? data?.data?.[dataPath] : data?.data;
33
- if (typeof response !== 'undefined') {
34
- return response;
35
- }
36
- }
37
- const action = (dataPath || '').startsWith('xwa2_')
38
- ? dataPath.substring(5).replace(/_/g, ' ')
39
- : dataPath?.replace(/_/g, ' ');
40
- throw new Boom(`Failed to ${action}, unexpected response structure.`, { statusCode: 400, data: result });
41
- };
42
- //# sourceMappingURL=mex.js.map
22
+ const result = await wMexQuery(variables, queryId, query, generateMessageTag)
23
+ const child = (0, WABinary_1.getBinaryNodeChild)(result, 'result')
24
+ if (child?.content) {
25
+ const data = JSON.parse(child.content.toString())
26
+ if (data.errors && data.errors.length > 0) {
27
+ const errorMessages = data.errors.map(err => err.message || 'Unknown error').join(', ')
28
+ const firstError = data.errors[0]
29
+ const errorCode = firstError.extensions?.error_code || 400
30
+ throw new boom_1.Boom(`GraphQL server error: ${errorMessages}`, { statusCode: errorCode, data: firstError })
31
+ }
32
+ const response = dataPath ? data?.data?.[dataPath] : data?.data
33
+ if (typeof response !== 'undefined') {
34
+ return response
35
+ }
36
+ }
37
+ const action = (dataPath || '').startsWith('xwa2_')
38
+ ? dataPath.substring(5).replace(/_/g, ' ')
39
+ : dataPath?.replace(/_/g, ' ')
40
+ throw new boom_1.Boom(`Failed to ${action}, unexpected response structure.`, { statusCode: 400, data: result })
41
+ }
@@ -217,7 +217,9 @@ export const makeSocket = (config) => {
217
217
  return usyncQuery.parseUSyncQueryResult(result);
218
218
  };
219
219
  const onWhatsApp = async (...phoneNumber) => {
220
- let usyncQuery = new USyncQuery();
220
+ let usyncQuery = new USyncQuery()
221
+ .withContactProtocol()
222
+ .withLIDProtocol();
221
223
  let contactEnabled = false;
222
224
  for (const jid of phoneNumber) {
223
225
  if (isLidUser(jid)) {
@@ -238,7 +240,7 @@ export const makeSocket = (config) => {
238
240
  }
239
241
  const results = await executeUSyncQuery(usyncQuery);
240
242
  if (results) {
241
- return results.list.filter(a => !!a.contact).map(({ contact, id }) => ({ jid: id, exists: contact }));
243
+ return results.list.filter(a => !!a.contact).map(({ contact, id, lid }) => ({ jid: id, lid, exists: contact }));
242
244
  }
243
245
  };
244
246
  const pnFromLIDUSync = async (jids) => {
@@ -261,6 +263,14 @@ export const makeSocket = (config) => {
261
263
  }
262
264
  return [];
263
265
  };
266
+ const toPn = async (jid) => {
267
+ const res = await pnFromLIDUSync([jid]).list[0].id;
268
+ return res
269
+ }
270
+ const toLid = async (jid) => {
271
+ const [res] = await onWhatsApp(jid).lid;
272
+ return res
273
+ }
264
274
  const ev = makeEventBuffer(logger);
265
275
  const { creds } = authState;
266
276
  // add transaction capability
@@ -952,7 +962,10 @@ export const makeSocket = (config) => {
952
962
  executeUSyncQuery,
953
963
  onWhatsApp,
954
964
  fetchAccountReachoutTimelock,
955
- fetchNewChatMessageCap
965
+ fetchNewChatMessageCap,
966
+ toPn,
967
+ toLid,
968
+ pnFromLIDUSync
956
969
  };
957
970
  };
958
971
  /**
@@ -0,0 +1,234 @@
1
+ import { executeWMexQuery } from './mex.js'
2
+ import { USyncQuery, USyncUser } from '../WAUSync/index.js'
3
+ import { makeNewsletterSocket } from './newsletter.js'
4
+
5
+ /**
6
+ * w:mex query IDs for username operations.
7
+ *
8
+ * These numeric IDs are assigned by WhatsApp's Pando/MEX infrastructure.
9
+ * They can be obtained by capturing a real WA session that performs these
10
+ * operations and inspecting the query_id field in the <query> IQ node.
11
+ *
12
+ * Source: Java decompilation of WhatsApp 2.26.17.2 (C1568872p.java)
13
+ * Operations confirmed: UsernameCheck, UsernameSet, UsernameGet, UsernamePinSet
14
+ * Data path confirmed: xwa2_username_check (C164057Wg.java:81)
15
+ */
16
+ export const USERNAME_QUERY_IDS = {
17
+ CHECK: '26124072630599520', // UsernameCheck
18
+ CHECK_MULTI: '27134626522840290', // UsernameCheckMulti
19
+ SET: '27108705368767936', // UsernameSet
20
+ GET: '32618050064506056', // UsernameGet
21
+ GET_RECOMMENDATIONS: '26077456248616956', // UsernameGetRecommendationsQuery
22
+ PIN_SET: '25529696019976770' // UsernamePinSet
23
+ }
24
+
25
+ /**
26
+ * Source enum values from EnumC141106Vn (UsernameCheck result)
27
+ * and EnumC141056Vi (rejection reasons) confirmed via C164057Wg.java
28
+ */
29
+ export const USERNAME_CHECK_RESULT = {
30
+ SUCCESS: 'SUCCESS',
31
+ INVALID: 'INVALID'
32
+ }
33
+
34
+ export const USERNAME_SOURCE = {
35
+ FB: 'FB',
36
+ IG: 'IG',
37
+ USER_INPUT: 'USER_INPUT',
38
+ SUGGESTION: 'SUGGESTION'
39
+ }
40
+
41
+ export const makeUsernameSocket = config => {
42
+ const sock = makeNewsletterSocket(config)
43
+ const { query, generateMessageTag, executeUSyncQuery } = sock
44
+
45
+ const mexQuery = (variables, queryId, dataPath) =>
46
+ executeWMexQuery(variables, queryId, dataPath, query, generateMessageTag)
47
+
48
+ /**
49
+ * Check whether a username is available.
50
+ *
51
+ * @param {string} username - The @username to check (without @)
52
+ * @param {boolean} includeSuggestions - Request alternative suggestions when taken
53
+ * @returns {object}
54
+ * On success: { available: true, username }
55
+ * On taken: { available: false, username, suggestions: string[], rejectionReasons: string[], suggestionsEligible: boolean }
56
+ * On rate-limit: throws Boom with statusCode 429
57
+ *
58
+ * Confirmed fields from C164057Wg.java:
59
+ * data.xwa2_username_check.result → 'SUCCESS' | 'INVALID'
60
+ * data.xwa2_username_check.suggestions
61
+ * data.xwa2_username_check.rejection_reasons
62
+ * data.xwa2_username_check.suggestions_eligible
63
+ */
64
+ const checkUsername = async (username, includeSuggestions = true) => {
65
+ if (!USERNAME_QUERY_IDS.CHECK) {
66
+ throw new Error('Username CHECK query_id not configured — capture a live WA session to obtain it')
67
+ }
68
+ const data = await mexQuery(
69
+ { username, include_suggestions: includeSuggestions },
70
+ USERNAME_QUERY_IDS.CHECK,
71
+ 'xwa2_username_check'
72
+ )
73
+ if (data?.result === USERNAME_CHECK_RESULT.SUCCESS) {
74
+ return { available: true, username }
75
+ }
76
+ return {
77
+ available: false,
78
+ username,
79
+ suggestions: data?.suggestions?? [],
80
+ rejectionReasons: data?.rejection_reasons?? [],
81
+ suggestionsEligible: data?.suggestions_eligible?? true
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Set your own username.
87
+ *
88
+ * @param {string} username - The username to set (without @)
89
+ * @param {object} options
90
+ * @param {string} [options.source] - 'USER_INPUT' | 'FB' | 'IG' | 'SUGGESTION'
91
+ * @param {string} [options.sessionId] - Optional session tracking ID
92
+ * @param {string} [options.pin] - Optional PIN for protected usernames
93
+ *
94
+ * Confirmed variables from C1568872p.java A00():
95
+ * username, reserved (bool), session_id, source, pin
96
+ */
97
+ const setUsername = async (username, options = {}) => {
98
+ if (!USERNAME_QUERY_IDS.SET) {
99
+ throw new Error('Username SET query_id not configured — capture a live WA session to obtain it')
100
+ }
101
+ const { source = USERNAME_SOURCE.USER_INPUT, sessionId, pin } = options
102
+ const variables = {
103
+ username,
104
+ reserved: false,
105
+ source,
106
+ ...(sessionId? { session_id: sessionId } : {}),
107
+ ...(pin? { pin } : {})
108
+ }
109
+ return mexQuery(variables, USERNAME_QUERY_IDS.SET, 'xwa2_username_set')
110
+ }
111
+
112
+ /**
113
+ * Delete (unset) your own username.
114
+ *
115
+ * Confirmed from C1568872p.java:
116
+ * str4 = str == null? "delete" : "set"
117
+ * → sending username=null triggers the delete path on the server.
118
+ */
119
+ const deleteUsername = async () => {
120
+ if (!USERNAME_QUERY_IDS.SET) {
121
+ throw new Error('Username SET query_id not configured — capture a live WA session to obtain it')
122
+ }
123
+ return mexQuery({ username: null }, USERNAME_QUERY_IDS.SET, 'xwa2_username_delete')
124
+ }
125
+
126
+ /**
127
+ * Get your own current username.
128
+ *
129
+ * Confirmed from C1568872p.java A02():
130
+ * AbstractC41851rT.A0L(AbstractC130045pa.A0T(), C1363664w.class, "UsernameGet", false)
131
+ */
132
+ const getMyUsername = async () => {
133
+ if (!USERNAME_QUERY_IDS.GET) {
134
+ throw new Error('Username GET query_id not configured — capture a live WA session to obtain it')
135
+ }
136
+ const data = await mexQuery({}, USERNAME_QUERY_IDS.GET, 'xwa2_username_get')
137
+ return data?.username?? null
138
+ }
139
+
140
+ /**
141
+ * Set or delete the PIN that protects your username.
142
+ *
143
+ * @param {string|null} pin - New PIN, or null to delete the PIN
144
+ *
145
+ * Confirmed from MexUsernamePinProtocolApi.java:
146
+ * operation "UsernamePinSet", variable "pin"
147
+ * pin=null triggers the "delete" path on the server.
148
+ */
149
+ const setUsernamePin = async pin => {
150
+ if (!USERNAME_QUERY_IDS.PIN_SET) {
151
+ throw new Error('Username PIN_SET query_id not configured — capture a live WA session to obtain it')
152
+ }
153
+ return mexQuery({ pin }, USERNAME_QUERY_IDS.PIN_SET, 'xwa2_username_pin_set')
154
+ }
155
+
156
+ /**
157
+ * Look up a contact by their @username via USync.
158
+ *
159
+ * Confirmed via USyncContactProtocol.getUserElement():
160
+ * { tag: 'contact', attrs: { username, pin? } }
161
+ *
162
+ * @param {string} username - The username to look up (without @)
163
+ * @param {string} [pin] - Optional PIN if the username is PIN-protected
164
+ * @returns {{ jid, lid?, contact: boolean }|null}
165
+ */
166
+ const findUserByUsername = async (username, pin) => {
167
+ const usyncQuery = new USyncQuery().withContactProtocol()
168
+ const user = new USyncUser().withUsername(username)
169
+ if (pin) user.withUsernameKey(pin)
170
+ usyncQuery.withUser(user)
171
+ const result = await executeUSyncQuery(usyncQuery)
172
+ if (!result?.list?.length) return null
173
+ const entry = result.list[0]
174
+ return {
175
+ jid: entry.id,
176
+ contact: entry.contact?? false
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Fetch the username of one or more contacts by their JID.
182
+ * Uses USync with the username protocol.
183
+ *
184
+ * @param {...string} jids - One or more JIDs
185
+ * @returns {Array<{ id, username: string|null }>}
186
+ */
187
+ const fetchContactUsernames = async (...jids) => {
188
+ const usyncQuery = new USyncQuery().withUsernameProtocol()
189
+ for (const jid of jids) {
190
+ usyncQuery.withUser(new USyncUser().withId(jid))
191
+ }
192
+ const result = await executeUSyncQuery(usyncQuery)
193
+ return result?.list?? []
194
+ }
195
+
196
+ /**
197
+ * Check multiple usernames for availability at once.
198
+ * @param {string[]} usernames - Array of usernames (without @)
199
+ */
200
+ const checkUsernameMulti = async usernames => {
201
+ const data = await mexQuery(
202
+ { usernames },
203
+ USERNAME_QUERY_IDS.CHECK_MULTI,
204
+ 'xwa2_username_check_multi'
205
+ )
206
+ return data
207
+ }
208
+
209
+ /**
210
+ * Fetch username recommendations for the current user.
211
+ * @param {string} [source] - Source hint: 'FB' | 'IG' | 'USER_INPUT'
212
+ */
213
+ const getUsernameRecommendations = async (source = null) => {
214
+ const variables = {}
215
+ if (source) variables.source = source
216
+ return mexQuery(variables, USERNAME_QUERY_IDS.GET_RECOMMENDATIONS, 'xwa2_username_get_recommendations')
217
+ }
218
+
219
+ return {
220
+ ...sock,
221
+ checkUsername,
222
+ checkUsernameMulti,
223
+ setUsername,
224
+ deleteUsername,
225
+ getMyUsername,
226
+ getUsernameRecommendations,
227
+ setUsernamePin,
228
+ findUserByUsername,
229
+ fetchContactUsernames,
230
+ USERNAME_QUERY_IDS,
231
+ USERNAME_CHECK_RESULT,
232
+ USERNAME_SOURCE
233
+ }
234
+ }
@@ -633,6 +633,13 @@ export const generateWAMessageContent = async (message, options) => {
633
633
  }
634
634
  })
635
635
  }
636
+ else if ('botInvoke' in message && !!message.botInvoke) {
637
+ m = {
638
+ botInvokeMessage: {
639
+ message: message.botInvoke
640
+ }
641
+ }
642
+ }
636
643
  else if (hasNonNullishProperty(message, 'text')) {
637
644
  const extContent = { text: message.text };
638
645
  let urlInfo = message.linkPreview;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alannxd/baileys",
3
3
  "type": "module",
4
- "version": "6.1.0",
4
+ "version": "6.1.2",
5
5
  "description": "WhatsApp API Modification",
6
6
  "keywords": [
7
7
  "whatsapp",