davexbaileys 2.5.21 → 2.5.23

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.
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PreKeyManager = void 0;
4
+ const p_queue_1 = require("p-queue");
5
+
6
+ class PreKeyManager {
7
+ constructor(store, logger) {
8
+ this.store = store;
9
+ this.logger = logger;
10
+ this.queues = new Map();
11
+ }
12
+
13
+ getQueue(keyType) {
14
+ if (!this.queues.has(keyType)) {
15
+ this.queues.set(keyType, new p_queue_1.default({ concurrency: 1 }));
16
+ }
17
+ return this.queues.get(keyType);
18
+ }
19
+
20
+ async processOperations(data, keyType, transactionCache, mutations, isInTransaction) {
21
+ const keyData = data[keyType];
22
+ if (!keyData) return;
23
+
24
+ return this.getQueue(keyType).add(async () => {
25
+ transactionCache[keyType] = transactionCache[keyType] || {};
26
+ mutations[keyType] = mutations[keyType] || {};
27
+
28
+ const deletions = [];
29
+ const updates = {};
30
+
31
+ for (const keyId in keyData) {
32
+ if (keyData[keyId] === null) {
33
+ deletions.push(keyId);
34
+ }
35
+ else {
36
+ updates[keyId] = keyData[keyId];
37
+ }
38
+ }
39
+
40
+ if (Object.keys(updates).length > 0) {
41
+ Object.assign(transactionCache[keyType], updates);
42
+ Object.assign(mutations[keyType], updates);
43
+ }
44
+
45
+ if (deletions.length > 0) {
46
+ await this.processDeletions(keyType, deletions, transactionCache, mutations, isInTransaction);
47
+ }
48
+ });
49
+ }
50
+
51
+ async processDeletions(keyType, ids, transactionCache, mutations, isInTransaction) {
52
+ if (isInTransaction) {
53
+ for (const keyId of ids) {
54
+ if (transactionCache[keyType] && transactionCache[keyType][keyId]) {
55
+ transactionCache[keyType][keyId] = null;
56
+ mutations[keyType][keyId] = null;
57
+ }
58
+ else {
59
+ this.logger.warn(`Skipping deletion of non-existent ${keyType} in transaction: ${keyId}`);
60
+ }
61
+ }
62
+ }
63
+ else {
64
+ const existingKeys = await this.store.get(keyType, ids);
65
+ for (const keyId of ids) {
66
+ if (existingKeys[keyId]) {
67
+ transactionCache[keyType][keyId] = null;
68
+ mutations[keyType][keyId] = null;
69
+ }
70
+ else {
71
+ this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`);
72
+ }
73
+ }
74
+ }
75
+ }
76
+
77
+ async validateDeletions(data, keyType) {
78
+ const keyData = data[keyType];
79
+ if (!keyData) return;
80
+
81
+ return this.getQueue(keyType).add(async () => {
82
+ const deletionIds = Object.keys(keyData).filter(id => keyData[id] === null);
83
+ if (deletionIds.length === 0) return;
84
+
85
+ const existingKeys = await this.store.get(keyType, deletionIds);
86
+ for (const keyId of deletionIds) {
87
+ if (!existingKeys[keyId]) {
88
+ this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`);
89
+ delete data[keyType][keyId];
90
+ }
91
+ }
92
+ });
93
+ }
94
+ }
95
+ exports.PreKeyManager = PreKeyManager;
@@ -149,7 +149,8 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
149
149
  ev.emit('messaging-history.set', {
150
150
  ...data,
151
151
  isLatest: histNotification.syncType !== WAProto_1.proto.HistorySync.HistorySyncType.ON_DEMAND ? isLatest : undefined,
152
- peerDataRequestSessionId: histNotification.peerDataRequestSessionId
152
+ peerDataRequestSessionId: histNotification.peerDataRequestSessionId,
153
+ chunkOrder: histNotification.chunkOrder !== undefined ? histNotification.chunkOrder : undefined
153
154
  });
154
155
  }
155
156
  break;
@@ -248,13 +249,14 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
248
249
  const jid = (_f = message.key) === null || _f === void 0 ? void 0 : _f.remoteJid;
249
250
  //let actor = whatsappID (message.participant)
250
251
  let participants;
251
- const emitParticipantsUpdate = (action) => ev.emit('group-participants.update', { id: jid, author: message.participant, participants, action });
252
+ const authorUsername = message.key && message.key.participantUsername;
253
+ const emitParticipantsUpdate = (action) => ev.emit('group-participants.update', { id: jid, author: message.participant, authorUsername, participants, action });
252
254
  const emitGroupUpdate = (update) => {
253
255
  var _a;
254
- ev.emit('groups.update', [{ id: jid, ...update, author: (_a = message.participant) !== null && _a !== void 0 ? _a : undefined }]);
256
+ ev.emit('groups.update', [{ id: jid, ...update, author: (_a = message.participant) !== null && _a !== void 0 ? _a : undefined, authorUsername }]);
255
257
  };
256
258
  const emitGroupRequestJoin = (participant, action, method) => {
257
- ev.emit('group.join-request', { id: jid, author: message.participant, participant, action, method: method });
259
+ ev.emit('group.join-request', { id: jid, author: message.participant, authorUsername, participant, action, method: method });
258
260
  };
259
261
  const participantsIncludesMe = () => participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid));
260
262
  switch (message.messageStubType) {
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAckStanza = void 0;
4
+ /**
5
+ * Builds an ACK stanza for a received node.
6
+ * Pure function -- no I/O, no side effects.
7
+ *
8
+ * Mirrors WhatsApp Web's ACK construction:
9
+ * - WAWebHandleMsgSendAck.sendAck / sendNack
10
+ * - WAWebCreateNackFromStanza.createNackFromStanza
11
+ *
12
+ * @param node - the received binary node to acknowledge
13
+ * @param errorCode - optional NACK error code
14
+ * @param meId - own JID, required for message-class ACKs
15
+ */
16
+ const buildAckStanza = (node, errorCode, meId) => {
17
+ const { tag, attrs } = node;
18
+ const stanza = {
19
+ tag: 'ack',
20
+ attrs: {
21
+ id: attrs.id,
22
+ to: attrs.from,
23
+ class: tag
24
+ }
25
+ };
26
+ if (errorCode) {
27
+ stanza.attrs.error = errorCode.toString();
28
+ }
29
+ if (attrs.participant) {
30
+ stanza.attrs.participant = attrs.participant;
31
+ }
32
+ if (attrs.recipient) {
33
+ stanza.attrs.recipient = attrs.recipient;
34
+ }
35
+ // WA Web always includes type when present
36
+ if (attrs.type) {
37
+ stanza.attrs.type = attrs.type;
38
+ }
39
+ // WA Web WAWebHandleMsgSendAck.sendAck/sendNack always includes `from` for message-class ACKs
40
+ if (tag === 'message' && meId) {
41
+ stanza.attrs.from = meId;
42
+ }
43
+ return stanza;
44
+ };
45
+ exports.buildAckStanza = buildAckStanza;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isAppStateSyncIrrecoverable = exports.isMissingKeyError = void 0;
4
+ /**
5
+ * Returns true when the error indicates that an app-state sync key is missing.
6
+ * WA Web treats these as "Blocked" (waits for key arrival), not fatal.
7
+ * Errors are tagged via { data: { isMissingKey: true } } in the Boom payload.
8
+ */
9
+ const isMissingKeyError = (error) => {
10
+ var _a;
11
+ return ((_a = error === null || error === void 0 ? void 0 : error.data) === null || _a === void 0 ? void 0 : _a.isMissingKey) === true;
12
+ };
13
+ exports.isMissingKeyError = isMissingKeyError;
14
+ /**
15
+ * Determines if an app state sync error is unrecoverable.
16
+ * TypeError indicates a WASM crash; otherwise we give up after MAX_SYNC_ATTEMPTS.
17
+ * Missing keys are NOT checked here — they are handled separately as "Blocked".
18
+ */
19
+ const isAppStateSyncIrrecoverable = (error, attemptsForName, maxAttempts) => {
20
+ return (attemptsForName >= maxAttempts ||
21
+ (error === null || error === void 0 ? void 0 : error.name) === 'TypeError');
22
+ };
23
+ exports.isAppStateSyncIrrecoverable = isAppStateSyncIrrecoverable;
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.storeTcTokensFromIqResult = exports.buildTcTokenFromJid = exports.resolveIssuanceJid = exports.resolveTcTokenJid = exports.shouldSendNewTcToken = exports.isTcTokenExpired = exports.buildMergedTcTokenIndexWrite = exports.readTcTokenIndex = exports.TC_TOKEN_INDEX_KEY = exports.storeTcTokensFromHistorySync = exports.getTcTokenKey = void 0;
4
+ const WABinary_1 = require("../WABinary");
5
+
6
+ // Same phone-number pattern as WABinary's isJidBot, applied against the user
7
+ // part so the check is invariant to @c.us ↔ @s.whatsapp.net normalization.
8
+ const BOT_PHONE_REGEX = /^1313555\d{4}$|^131655500\d{2}$/;
9
+
10
+ /**
11
+ * Mirrors WA Web's `Wid.isRegularUser()` (user ∧ ¬PSA ∧ ¬Bot). Used to gate tctoken
12
+ * storage against malformed notifications — WA Web filters server-side but we
13
+ * defend here for parity with `WAWebSetTcTokenChatAction.handleIncomingTcToken`.
14
+ * Works for both pre- and post-normalized JIDs (`@c.us` vs `@s.whatsapp.net`).
15
+ */
16
+ function isRegularUser(jid) {
17
+ if (!jid) return false;
18
+ const user = jid.split('@')[0] || '';
19
+ if (user === '0') return false;
20
+ if (BOT_PHONE_REGEX.test(user)) return false;
21
+ if ((0, WABinary_1.isJidMetaIa)(jid)) return false;
22
+ return !!(
23
+ (0, WABinary_1.isLidUser)(jid) ||
24
+ (0, WABinary_1.isJidUser)(jid) ||
25
+ jid.endsWith('@c.us')
26
+ );
27
+ }
28
+
29
+ const TC_TOKEN_BUCKET_DURATION = 604800;
30
+ const TC_TOKEN_NUM_BUCKETS = 4;
31
+
32
+ /** Sentinel key under `tctoken` store holding a JSON array of tracked storage JIDs for cross-session pruning. */
33
+ exports.TC_TOKEN_INDEX_KEY = '__index';
34
+
35
+ /**
36
+ * Returns the key used to store a tc-token for a given JID.
37
+ * @deprecated use resolveTcTokenJid instead
38
+ */
39
+ const getTcTokenKey = (jid) => {
40
+ return `tc-token:${(0, WABinary_1.jidNormalizedUser)(jid)}`;
41
+ };
42
+ exports.getTcTokenKey = getTcTokenKey;
43
+
44
+ /** Read the persisted tctoken JID index and return its entries (never contains the sentinel key itself). */
45
+ const readTcTokenIndex = async (keys) => {
46
+ const data = await keys.get('tctoken', [exports.TC_TOKEN_INDEX_KEY]);
47
+ const entry = data[exports.TC_TOKEN_INDEX_KEY];
48
+ if (!(entry === null || entry === void 0 ? void 0 : entry.token) || !entry.token.length) return [];
49
+ try {
50
+ const parsed = JSON.parse(Buffer.from(entry.token).toString());
51
+ if (!Array.isArray(parsed)) return [];
52
+ return parsed.filter(j => typeof j === 'string' && j.length > 0 && j !== exports.TC_TOKEN_INDEX_KEY);
53
+ }
54
+ catch {
55
+ return [];
56
+ }
57
+ };
58
+ exports.readTcTokenIndex = readTcTokenIndex;
59
+
60
+ /** Build a SignalDataSet fragment that writes the merged index (persisted ∪ added) under the sentinel key. */
61
+ const buildMergedTcTokenIndexWrite = async (keys, addedJids) => {
62
+ const persisted = await (0, exports.readTcTokenIndex)(keys);
63
+ const merged = new Set(persisted);
64
+ for (const jid of addedJids) {
65
+ if (jid && jid !== exports.TC_TOKEN_INDEX_KEY) merged.add(jid);
66
+ }
67
+ return {
68
+ [exports.TC_TOKEN_INDEX_KEY]: { token: Buffer.from(JSON.stringify([...merged])) }
69
+ };
70
+ };
71
+ exports.buildMergedTcTokenIndexWrite = buildMergedTcTokenIndexWrite;
72
+
73
+ /** Returns true when a tc-token timestamp is past the rolling 28-day window. */
74
+ const isTcTokenExpired = (timestamp) => {
75
+ if (timestamp === null || timestamp === undefined) return true;
76
+ const ts = typeof timestamp === 'string' ? parseInt(timestamp) : timestamp;
77
+ if (isNaN(ts)) return true;
78
+ const now = Math.floor(Date.now() / 1000);
79
+ const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
80
+ const cutoffBucket = currentBucket - (TC_TOKEN_NUM_BUCKETS - 1);
81
+ const cutoffTimestamp = cutoffBucket * TC_TOKEN_BUCKET_DURATION;
82
+ return ts < cutoffTimestamp;
83
+ };
84
+ exports.isTcTokenExpired = isTcTokenExpired;
85
+
86
+ /** Returns true if we should send a new tc-token to this contact (bucket-based deduplication). */
87
+ const shouldSendNewTcToken = (senderTimestamp) => {
88
+ if (senderTimestamp === undefined) return true;
89
+ const now = Math.floor(Date.now() / 1000);
90
+ const currentBucket = Math.floor(now / TC_TOKEN_BUCKET_DURATION);
91
+ const senderBucket = Math.floor(senderTimestamp / TC_TOKEN_BUCKET_DURATION);
92
+ return currentBucket > senderBucket;
93
+ };
94
+ exports.shouldSendNewTcToken = shouldSendNewTcToken;
95
+
96
+ /** Resolve JID to LID for tctoken storage (WA Web stores under LID) */
97
+ const resolveTcTokenJid = async (jid, getLIDForPN) => {
98
+ if ((0, WABinary_1.isLidUser)(jid)) return jid;
99
+ const lid = await getLIDForPN(jid);
100
+ return lid !== null && lid !== void 0 ? lid : jid;
101
+ };
102
+ exports.resolveTcTokenJid = resolveTcTokenJid;
103
+
104
+ /** Resolve target JID for issuing privacy token based on AB prop 14303 */
105
+ const resolveIssuanceJid = async (jid, issueToLid, getLIDForPN, getPNForLID) => {
106
+ if (issueToLid) {
107
+ if ((0, WABinary_1.isLidUser)(jid)) return jid;
108
+ const lid = await getLIDForPN(jid);
109
+ return lid !== null && lid !== void 0 ? lid : jid;
110
+ }
111
+ if (!(0, WABinary_1.isLidUser)(jid)) return jid;
112
+ if (getPNForLID) {
113
+ const pn = await getPNForLID(jid);
114
+ return pn !== null && pn !== void 0 ? pn : jid;
115
+ }
116
+ return jid;
117
+ };
118
+ exports.resolveIssuanceJid = resolveIssuanceJid;
119
+
120
+ /**
121
+ * Build tc-token content array from a stored token for a given JID.
122
+ * Returns undefined if no valid token exists.
123
+ */
124
+ const buildTcTokenFromJid = async ({ authState, jid, baseContent = [], getLIDForPN }) => {
125
+ try {
126
+ const storageJid = await (0, exports.resolveTcTokenJid)(jid, getLIDForPN);
127
+ const tcTokenData = await authState.keys.get('tctoken', [storageJid]);
128
+ const entry = tcTokenData === null || tcTokenData === void 0 ? void 0 : tcTokenData[storageJid];
129
+ const tcTokenBuffer = entry === null || entry === void 0 ? void 0 : entry.token;
130
+ if (!(tcTokenBuffer === null || tcTokenBuffer === void 0 ? void 0 : tcTokenBuffer.length) || (0, exports.isTcTokenExpired)(entry === null || entry === void 0 ? void 0 : entry.timestamp)) {
131
+ if (tcTokenBuffer) {
132
+ const cleared = (entry === null || entry === void 0 ? void 0 : entry.senderTimestamp) !== undefined
133
+ ? { token: Buffer.alloc(0), senderTimestamp: entry.senderTimestamp }
134
+ : null;
135
+ await authState.keys.set({ tctoken: { [storageJid]: cleared } });
136
+ }
137
+ return baseContent.length > 0 ? baseContent : undefined;
138
+ }
139
+ baseContent.push({
140
+ tag: 'tctoken',
141
+ attrs: {},
142
+ content: tcTokenBuffer
143
+ });
144
+ return baseContent;
145
+ }
146
+ catch (error) {
147
+ return baseContent.length > 0 ? baseContent : undefined;
148
+ }
149
+ };
150
+ exports.buildTcTokenFromJid = buildTcTokenFromJid;
151
+
152
+ /**
153
+ * Store tc-tokens received from a privacy_token IQ response.
154
+ */
155
+ const storeTcTokensFromIqResult = async ({ result, fallbackJid, keys, getLIDForPN, onNewJidStored }) => {
156
+ const { getBinaryNodeChild, getBinaryNodeChildren } = require('../WABinary');
157
+ const tokensNode = getBinaryNodeChild(result, 'tokens');
158
+ if (!tokensNode) return;
159
+ const tokenNodes = getBinaryNodeChildren(tokensNode, 'token');
160
+ for (const tokenNode of tokenNodes) {
161
+ if (tokenNode.attrs.type !== 'trusted_contact' || !(tokenNode.content instanceof Uint8Array)) {
162
+ continue;
163
+ }
164
+ const rawJid = (0, WABinary_1.jidNormalizedUser)(fallbackJid || tokenNode.attrs.jid);
165
+ if (!isRegularUser(rawJid)) continue;
166
+ const storageJid = await (0, exports.resolveTcTokenJid)(rawJid, getLIDForPN);
167
+ const existingTcData = await keys.get('tctoken', [storageJid]);
168
+ const existingEntry = existingTcData[storageJid];
169
+ const existingTs = (existingEntry === null || existingEntry === void 0 ? void 0 : existingEntry.timestamp) ? Number(existingEntry.timestamp) : 0;
170
+ const incomingTs = tokenNode.attrs.t ? Number(tokenNode.attrs.t) : 0;
171
+ if (!incomingTs) continue;
172
+ if (existingTs > 0 && existingTs > incomingTs) continue;
173
+ await keys.set({
174
+ tctoken: {
175
+ [storageJid]: Object.assign(Object.assign({}, existingEntry), { token: Buffer.from(tokenNode.content), timestamp: tokenNode.attrs.t })
176
+ }
177
+ });
178
+ if (onNewJidStored) onNewJidStored(storageJid);
179
+ }
180
+ };
181
+ exports.storeTcTokensFromIqResult = storeTcTokensFromIqResult;
182
+
183
+ /**
184
+ * Extracts and stores tc-tokens from a history sync payload.
185
+ * Conversations in the history sync may carry tcToken fields that should
186
+ * be stored so that presenceSubscribe / relayMessage can include them.
187
+ */
188
+ const storeTcTokensFromHistorySync = async (ev, conversations) => {
189
+ if (!conversations || !conversations.length) {
190
+ return;
191
+ }
192
+ const chatUpdates = [];
193
+ for (const conv of conversations) {
194
+ if (conv.id && conv.tcToken) {
195
+ chatUpdates.push({
196
+ id: conv.id,
197
+ tcToken: conv.tcToken instanceof Uint8Array
198
+ ? Buffer.from(conv.tcToken)
199
+ : Buffer.isBuffer(conv.tcToken)
200
+ ? conv.tcToken
201
+ : Buffer.from(Object.values(conv.tcToken))
202
+ });
203
+ }
204
+ }
205
+ if (chatUpdates.length) {
206
+ ev.emit('chats.update', chatUpdates);
207
+ }
208
+ };
209
+ exports.storeTcTokensFromHistorySync = storeTcTokensFromHistorySync;
@@ -13,11 +13,34 @@ class USyncContactProtocol {
13
13
  };
14
14
  }
15
15
  getUserElement(user) {
16
- //TODO: Implement type / username fields (not yet supported)
16
+ if (user.phone) {
17
+ return {
18
+ tag: 'contact',
19
+ attrs: {},
20
+ content: user.phone
21
+ };
22
+ }
23
+ if (user.username) {
24
+ return {
25
+ tag: 'contact',
26
+ attrs: {
27
+ username: user.username,
28
+ ...(user.usernameKey ? { pin: user.usernameKey } : {}),
29
+ ...(user.lid ? { lid: user.lid } : {})
30
+ }
31
+ };
32
+ }
33
+ if (user.type) {
34
+ return {
35
+ tag: 'contact',
36
+ attrs: {
37
+ type: user.type
38
+ }
39
+ };
40
+ }
17
41
  return {
18
42
  tag: 'contact',
19
- attrs: {},
20
- content: user.phone
43
+ attrs: {}
21
44
  };
22
45
  }
23
46
  parser(node) {
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.USyncUsernameProtocol = void 0;
4
+ class USyncUsernameProtocol {
5
+ constructor() {
6
+ this.name = 'username';
7
+ }
8
+ getQueryElement() {
9
+ return {
10
+ tag: 'username',
11
+ attrs: {}
12
+ };
13
+ }
14
+ getUserElement(user) {
15
+ if (user.usernameKey) {
16
+ return {
17
+ tag: 'username',
18
+ attrs: { key: user.usernameKey }
19
+ };
20
+ }
21
+ return {
22
+ tag: 'username',
23
+ attrs: {}
24
+ };
25
+ }
26
+ parser(node) {
27
+ var _a, _b;
28
+ if (node.tag === 'username') {
29
+ const username = (_a = node === null || node === void 0 ? void 0 : node.attrs) === null || _a === void 0 ? void 0 : _a.value;
30
+ const key = (_b = node === null || node === void 0 ? void 0 : node.attrs) === null || _b === void 0 ? void 0 : _b.key;
31
+ if (username) {
32
+ return { username, key };
33
+ }
34
+ }
35
+ return null;
36
+ }
37
+ }
38
+ exports.USyncUsernameProtocol = USyncUsernameProtocol;
@@ -18,3 +18,4 @@ __exportStar(require("./USyncDeviceProtocol"), exports);
18
18
  __exportStar(require("./USyncContactProtocol"), exports);
19
19
  __exportStar(require("./USyncStatusProtocol"), exports);
20
20
  __exportStar(require("./USyncDisappearingModeProtocol"), exports);
21
+ __exportStar(require("./USyncUsernameProtocol"), exports);
@@ -5,6 +5,7 @@ const WABinary_1 = require("../WABinary");
5
5
  const UsyncBotProfileProtocol_1 = require("./Protocols/UsyncBotProfileProtocol");
6
6
  const UsyncLIDProtocol_1 = require("./Protocols/UsyncLIDProtocol");
7
7
  const Protocols_1 = require("./Protocols");
8
+ const USyncUsernameProtocol_1 = require("./Protocols/USyncUsernameProtocol");
8
9
  class USyncQuery {
9
10
  constructor() {
10
11
  this.protocols = [];
@@ -89,5 +90,9 @@ class USyncQuery {
89
90
  this.protocols.push(new UsyncLIDProtocol_1.USyncLIDProtocol());
90
91
  return this;
91
92
  }
93
+ withUsernameProtocol() {
94
+ this.protocols.push(new USyncUsernameProtocol_1.USyncUsernameProtocol());
95
+ return this;
96
+ }
92
97
  }
93
98
  exports.USyncQuery = USyncQuery;
@@ -22,5 +22,13 @@ class USyncUser {
22
22
  this.personaId = personaId;
23
23
  return this;
24
24
  }
25
+ withUsername(username) {
26
+ this.username = username;
27
+ return this;
28
+ }
29
+ withUsernameKey(usernameKey) {
30
+ this.usernameKey = usernameKey;
31
+ return this;
32
+ }
25
33
  }
26
34
  exports.USyncUser = USyncUser;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davexbaileys",
3
- "version": "2.5.21",
3
+ "version": "2.5.23",
4
4
  "description": "A lightweight, full-featured WhatsApp Web API library for Node.js — maintained by Dave Tech",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -20,7 +20,8 @@
20
20
  "whatsapp-bot",
21
21
  "messaging",
22
22
  "chat",
23
- "newsletter"
23
+ "newsletter",
24
+ "communities"
24
25
  ],
25
26
  "dependencies": {
26
27
  "@cacheable/node-cache": "^1.4.0",
@@ -29,10 +30,20 @@
29
30
  "axios": "^1.6.0",
30
31
  "libsignal": "github:WhiskeySockets/libsignal-node",
31
32
  "lodash": "^4.17.21",
33
+ "lru-cache": "^11.3.5",
32
34
  "music-metadata": "^7.12.3",
33
35
  "node-fetch": "^2.6.1",
36
+ "p-queue": "^9.2.0",
34
37
  "pino": "^9.6",
35
38
  "protobufjs": "^7.2.4",
36
39
  "ws": "^8.13.0"
37
- }
38
- }
40
+ },
41
+ "engines": {
42
+ "node": ">=20.0.0"
43
+ },
44
+ "files": [
45
+ "lib/**/*",
46
+ "WAProto/**/*",
47
+ "engine-requirements.js"
48
+ ]
49
+ }