whatsapp-web.js 1.28.0 → 1.29.0
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/example.js +4 -0
- package/index.d.ts +206 -12
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/Client.js +463 -42
- package/src/factories/ChatFactory.js +7 -2
- package/src/structures/Broadcast.js +1 -1
- package/src/structures/Channel.js +382 -0
- package/src/structures/Chat.js +14 -6
- package/src/structures/GroupChat.js +4 -8
- package/src/structures/Location.js +1 -0
- package/src/structures/Message.js +15 -12
- package/src/structures/index.js +1 -0
- package/src/util/Injected/Store.js +44 -7
- package/src/util/Injected/Utils.js +242 -173
- package/src/util/InterfaceController.js +8 -9
|
@@ -2,15 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
const PrivateChat = require('../structures/PrivateChat');
|
|
4
4
|
const GroupChat = require('../structures/GroupChat');
|
|
5
|
+
const Channel = require('../structures/Channel');
|
|
5
6
|
|
|
6
7
|
class ChatFactory {
|
|
7
8
|
static create(client, data) {
|
|
8
|
-
if(data.isGroup) {
|
|
9
|
+
if (data.isGroup) {
|
|
9
10
|
return new GroupChat(client, data);
|
|
10
11
|
}
|
|
12
|
+
|
|
13
|
+
if (data.isChannel) {
|
|
14
|
+
return new Channel(client, data);
|
|
15
|
+
}
|
|
11
16
|
|
|
12
17
|
return new PrivateChat(client, data);
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
module.exports = ChatFactory;
|
|
21
|
+
module.exports = ChatFactory;
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Base = require('./Base');
|
|
4
|
+
const Message = require('./Message');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Channel ID structure
|
|
8
|
+
* @typedef {Object} ChannelId
|
|
9
|
+
* @property {string} server
|
|
10
|
+
* @property {string} user
|
|
11
|
+
* @property {string} _serialized
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Represents a Channel on WhatsApp
|
|
16
|
+
* @extends {Base}
|
|
17
|
+
*/
|
|
18
|
+
class Channel extends Base {
|
|
19
|
+
constructor(client, data) {
|
|
20
|
+
super(client);
|
|
21
|
+
|
|
22
|
+
if (data) this._patch(data);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
_patch(data) {
|
|
26
|
+
this.channelMetadata = data.channelMetadata;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* ID that represents the channel
|
|
30
|
+
* @type {ChannelId}
|
|
31
|
+
*/
|
|
32
|
+
this.id = data.id;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Title of the channel
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
this.name = data.name;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The channel description
|
|
42
|
+
* @type {string}
|
|
43
|
+
*/
|
|
44
|
+
this.description = data.channelMetadata.description;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Indicates if it is a Channel
|
|
48
|
+
* @type {boolean}
|
|
49
|
+
*/
|
|
50
|
+
this.isChannel = data.isChannel;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Indicates if it is a Group
|
|
54
|
+
* @type {boolean}
|
|
55
|
+
*/
|
|
56
|
+
this.isGroup = data.isGroup;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Indicates if the channel is readonly
|
|
60
|
+
* @type {boolean}
|
|
61
|
+
*/
|
|
62
|
+
this.isReadOnly = data.isReadOnly;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Amount of messages unread
|
|
66
|
+
* @type {number}
|
|
67
|
+
*/
|
|
68
|
+
this.unreadCount = data.unreadCount;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Unix timestamp for when the last activity occurred
|
|
72
|
+
* @type {number}
|
|
73
|
+
*/
|
|
74
|
+
this.timestamp = data.t;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Indicates if the channel is muted or not
|
|
78
|
+
* @type {boolean}
|
|
79
|
+
*/
|
|
80
|
+
this.isMuted = data.isMuted;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Unix timestamp for when the mute expires
|
|
84
|
+
* @type {number}
|
|
85
|
+
*/
|
|
86
|
+
this.muteExpiration = data.muteExpiration;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Last message in the channel
|
|
90
|
+
* @type {Message}
|
|
91
|
+
*/
|
|
92
|
+
this.lastMessage = data.lastMessage ? new Message(super.client, data.lastMessage) : undefined;
|
|
93
|
+
|
|
94
|
+
return super._patch(data);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Gets the subscribers of the channel (only those who are in your contact list)
|
|
99
|
+
* @param {?number} limit Optional parameter to specify the limit of subscribers to retrieve
|
|
100
|
+
* @returns {Promise<{contact: Contact, role: string}[]>} Returns an array of objects that handle the subscribed contacts and their roles in the channel
|
|
101
|
+
*/
|
|
102
|
+
async getSubscribers(limit) {
|
|
103
|
+
return await this.client.pupPage.evaluate(async (channelId, limit) => {
|
|
104
|
+
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
|
105
|
+
if (!channel) return [];
|
|
106
|
+
!limit && (limit = window.Store.ChannelUtils.getMaxSubscriberNumber());
|
|
107
|
+
const response = await window.Store.ChannelSubscribers.mexFetchNewsletterSubscribers(channelId, limit);
|
|
108
|
+
const contacts = window.Store.ChannelSubscribers.getSubscribersInContacts(response.subscribers);
|
|
109
|
+
return Promise.all(contacts.map((obj) => ({
|
|
110
|
+
...obj,
|
|
111
|
+
contact: window.WWebJS.getContactModel(obj.contact)
|
|
112
|
+
})));
|
|
113
|
+
}, this.id._serialized, limit);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Updates the channel subject
|
|
118
|
+
* @param {string} newSubject
|
|
119
|
+
* @returns {Promise<boolean>} Returns true if the subject was properly updated. This can return false if the user does not have the necessary permissions.
|
|
120
|
+
*/
|
|
121
|
+
async setSubject(newSubject) {
|
|
122
|
+
const success = await this._setChannelMetadata({ name: newSubject }, { editName: true });
|
|
123
|
+
success && (this.name = newSubject);
|
|
124
|
+
return success;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Updates the channel description
|
|
129
|
+
* @param {string} newDescription
|
|
130
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
131
|
+
*/
|
|
132
|
+
async setDescription(newDescription) {
|
|
133
|
+
const success = await this._setChannelMetadata({ description: newDescription }, { editDescription: true });
|
|
134
|
+
success && (this.description = newDescription);
|
|
135
|
+
return success;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Updates the channel profile picture
|
|
140
|
+
* @param {MessageMedia} newProfilePicture
|
|
141
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
142
|
+
*/
|
|
143
|
+
async setProfilePicture(newProfilePicture) {
|
|
144
|
+
return await this._setChannelMetadata({ picture: newProfilePicture }, { editPicture: true });
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Updates available reactions to use in the channel
|
|
149
|
+
*
|
|
150
|
+
* Valid values for passing to the method are:
|
|
151
|
+
* 0 for NONE reactions to be avaliable
|
|
152
|
+
* 1 for BASIC reactions to be available: 👍, ❤️, 😂, 😮, 😢, 🙏
|
|
153
|
+
* 2 for ALL reactions to be available
|
|
154
|
+
* @param {number} reactionCode
|
|
155
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
156
|
+
*/
|
|
157
|
+
async setReactionSetting(reactionCode) {
|
|
158
|
+
if (![0, 1, 2].includes(reactionCode)) return false;
|
|
159
|
+
const reactionMapper = {
|
|
160
|
+
0: 3,
|
|
161
|
+
1: 1,
|
|
162
|
+
2: 0
|
|
163
|
+
};
|
|
164
|
+
const success = await this._setChannelMetadata(
|
|
165
|
+
{ reactionCodesSetting: reactionMapper[reactionCode] },
|
|
166
|
+
{ editReactionCodesSetting: true }
|
|
167
|
+
);
|
|
168
|
+
success && (this.channelMetadata.reactionCodesSetting = reactionCode);
|
|
169
|
+
return success;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Mutes the channel
|
|
174
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
175
|
+
*/
|
|
176
|
+
async mute() {
|
|
177
|
+
const success = await this._muteUnmuteChannel('MUTE');
|
|
178
|
+
if (success) {
|
|
179
|
+
this.isMuted = true;
|
|
180
|
+
this.muteExpiration = -1;
|
|
181
|
+
}
|
|
182
|
+
return success;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Unmutes the channel
|
|
187
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
188
|
+
*/
|
|
189
|
+
async unmute() {
|
|
190
|
+
const success = await this._muteUnmuteChannel('UNMUTE');
|
|
191
|
+
if (success) {
|
|
192
|
+
this.isMuted = false;
|
|
193
|
+
this.muteExpiration = 0;
|
|
194
|
+
}
|
|
195
|
+
return success;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Message options
|
|
200
|
+
* @typedef {Object} MessageSendOptions
|
|
201
|
+
* @property {?string} caption Image or video caption
|
|
202
|
+
* @property {?string[]} mentions User IDs of user that will be mentioned in the message
|
|
203
|
+
* @property {?MessageMedia} media Image or video to be sent
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Sends a message to this channel
|
|
208
|
+
* @param {string|MessageMedia} content
|
|
209
|
+
* @param {?MessageSendOptions} options
|
|
210
|
+
* @returns {Promise<Message>} Message that was just sent
|
|
211
|
+
*/
|
|
212
|
+
async sendMessage(content, options) {
|
|
213
|
+
return this.client.sendMessage(this.id._serialized, content, options);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Sets the channel as seen
|
|
218
|
+
* @returns {Promise<boolean>}
|
|
219
|
+
*/
|
|
220
|
+
async sendSeen() {
|
|
221
|
+
return this.client.sendSeen(this.id._serialized);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* @typedef {Object} SendChannelAdminInviteOptions
|
|
226
|
+
* @property {?string} comment The comment to be added to an invitation
|
|
227
|
+
*/
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Sends a channel admin invitation to a user, allowing them to become an admin of the channel
|
|
231
|
+
* @param {string} chatId The ID of a user to send the channel admin invitation to
|
|
232
|
+
* @param {SendChannelAdminInviteOptions} options
|
|
233
|
+
* @returns {Promise<boolean>} Returns true if an invitation was sent successfully, false otherwise
|
|
234
|
+
*/
|
|
235
|
+
async sendChannelAdminInvite(chatId, options = {}) {
|
|
236
|
+
return this.client.sendChannelAdminInvite(chatId, this.id._serialized, options);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Accepts a channel admin invitation and promotes the current user to a channel admin
|
|
241
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
242
|
+
*/
|
|
243
|
+
async acceptChannelAdminInvite() {
|
|
244
|
+
return this.client.acceptChannelAdminInvite(this.id._serialized);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Revokes a channel admin invitation sent to a user by a channel owner
|
|
249
|
+
* @param {string} userId The user ID the invitation was sent to
|
|
250
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
251
|
+
*/
|
|
252
|
+
async revokeChannelAdminInvite(userId) {
|
|
253
|
+
return this.client.revokeChannelAdminInvite(this.id._serialized, userId);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Demotes a channel admin to a regular subscriber (can be used also for self-demotion)
|
|
258
|
+
* @param {string} userId The user ID to demote
|
|
259
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
260
|
+
*/
|
|
261
|
+
async demoteChannelAdmin(userId) {
|
|
262
|
+
return this.client.demoteChannelAdmin(this.id._serialized, userId);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Options for transferring a channel ownership to another user
|
|
267
|
+
* @typedef {Object} TransferChannelOwnershipOptions
|
|
268
|
+
* @property {boolean} [shouldDismissSelfAsAdmin = false] If true, after the channel ownership is being transferred to another user, the current user will be dismissed as a channel admin and will become to a channel subscriber.
|
|
269
|
+
*/
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Transfers a channel ownership to another user.
|
|
273
|
+
* Note: the user you are transferring the channel ownership to must be a channel admin.
|
|
274
|
+
* @param {string} newOwnerId
|
|
275
|
+
* @param {TransferChannelOwnershipOptions} options
|
|
276
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
277
|
+
*/
|
|
278
|
+
async transferChannelOwnership(newOwnerId, options = {}) {
|
|
279
|
+
return this.client.transferChannelOwnership(this.id._serialized, newOwnerId, options);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Loads channel messages, sorted from earliest to latest
|
|
284
|
+
* @param {Object} searchOptions Options for searching messages. Right now only limit and fromMe is supported
|
|
285
|
+
* @param {Number} [searchOptions.limit] The amount of messages to return. If no limit is specified, the available messages will be returned. Note that the actual number of returned messages may be smaller if there aren't enough messages in the conversation. Set this to Infinity to load all messages
|
|
286
|
+
* @param {Boolean} [searchOptions.fromMe] Return only messages from the bot number or vise versa. To get all messages, leave the option undefined
|
|
287
|
+
* @returns {Promise<Array<Message>>}
|
|
288
|
+
*/
|
|
289
|
+
async fetchMessages(searchOptions) {
|
|
290
|
+
let messages = await this.client.pupPage.evaluate(async (channelId, searchOptions) => {
|
|
291
|
+
const msgFilter = (m) => {
|
|
292
|
+
if (m.isNotification || m.type === 'newsletter_notification') {
|
|
293
|
+
return false; // dont include notification messages
|
|
294
|
+
}
|
|
295
|
+
if (searchOptions && searchOptions.fromMe !== undefined && m.id.fromMe !== searchOptions.fromMe) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
return true;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
|
302
|
+
let msgs = channel.msgs.getModelsArray().filter(msgFilter);
|
|
303
|
+
|
|
304
|
+
if (searchOptions && searchOptions.limit > 0) {
|
|
305
|
+
while (msgs.length < searchOptions.limit) {
|
|
306
|
+
const loadedMessages = await window.Store.ConversationMsgs.loadEarlierMsgs(channel);
|
|
307
|
+
if (!loadedMessages || !loadedMessages.length) break;
|
|
308
|
+
msgs = [...loadedMessages.filter(msgFilter), ...msgs];
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (msgs.length > searchOptions.limit) {
|
|
312
|
+
msgs.sort((a, b) => (a.t > b.t) ? 1 : -1);
|
|
313
|
+
msgs = msgs.splice(msgs.length - searchOptions.limit);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return msgs.map(m => window.WWebJS.getMessageModel(m));
|
|
318
|
+
|
|
319
|
+
}, this.id._serialized, searchOptions);
|
|
320
|
+
|
|
321
|
+
return messages.map((msg) => new Message(this.client, msg));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Deletes the channel you created
|
|
326
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
327
|
+
*/
|
|
328
|
+
async deleteChannel() {
|
|
329
|
+
return this.client.deleteChannel(this.id._serialized);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Internal method to change the channel metadata
|
|
334
|
+
* @param {string|number|MessageMedia} value The new value to set
|
|
335
|
+
* @param {string} property The property of a channel metadata to change
|
|
336
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
337
|
+
*/
|
|
338
|
+
async _setChannelMetadata(value, property) {
|
|
339
|
+
return await this.client.pupPage.evaluate(async (channelId, value, property) => {
|
|
340
|
+
const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
|
|
341
|
+
if (!channel) return false;
|
|
342
|
+
if (property.editPicture) {
|
|
343
|
+
value.picture = value.picture
|
|
344
|
+
? await window.WWebJS.cropAndResizeImage(value.picture, {
|
|
345
|
+
asDataUrl: true,
|
|
346
|
+
mimetype: 'image/jpeg',
|
|
347
|
+
size: 640,
|
|
348
|
+
quality: 1
|
|
349
|
+
})
|
|
350
|
+
: null;
|
|
351
|
+
}
|
|
352
|
+
try {
|
|
353
|
+
await window.Store.ChannelUtils.editNewsletterMetadataAction(channel, property, value);
|
|
354
|
+
return true;
|
|
355
|
+
} catch (err) {
|
|
356
|
+
if (err.name === 'ServerStatusCodeError') return false;
|
|
357
|
+
throw err;
|
|
358
|
+
}
|
|
359
|
+
}, this.id._serialized, value, property);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Internal method to mute or unmute the channel
|
|
364
|
+
* @param {string} action The action: 'MUTE' or 'UNMUTE'
|
|
365
|
+
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
366
|
+
*/
|
|
367
|
+
async _muteUnmuteChannel(action) {
|
|
368
|
+
return await this.client.pupPage.evaluate(async (channelId, action) => {
|
|
369
|
+
try {
|
|
370
|
+
action === 'MUTE'
|
|
371
|
+
? await window.Store.ChannelUtils.muteNewsletter([channelId])
|
|
372
|
+
: await window.Store.ChannelUtils.unmuteNewsletter([channelId]);
|
|
373
|
+
return true;
|
|
374
|
+
} catch (err) {
|
|
375
|
+
if (err.name === 'ServerStatusCodeError') return false;
|
|
376
|
+
throw err;
|
|
377
|
+
}
|
|
378
|
+
}, this.id._serialized, action);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
module.exports = Channel;
|
package/src/structures/Chat.js
CHANGED
|
@@ -95,7 +95,7 @@ class Chat extends Base {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/**
|
|
98
|
-
*
|
|
98
|
+
* Sets the chat as seen
|
|
99
99
|
* @returns {Promise<Boolean>} result
|
|
100
100
|
*/
|
|
101
101
|
async sendSeen() {
|
|
@@ -104,7 +104,7 @@ class Chat extends Base {
|
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Clears all messages from the chat
|
|
107
|
-
* @returns {Promise<
|
|
107
|
+
* @returns {Promise<boolean>} result
|
|
108
108
|
*/
|
|
109
109
|
async clearMessages() {
|
|
110
110
|
return this.client.pupPage.evaluate(chatId => {
|
|
@@ -154,17 +154,25 @@ class Chat extends Base {
|
|
|
154
154
|
|
|
155
155
|
/**
|
|
156
156
|
* Mutes this chat forever, unless a date is specified
|
|
157
|
-
* @param {?Date} unmuteDate Date
|
|
157
|
+
* @param {?Date} unmuteDate Date when the chat will be unmuted, don't provide a value to mute forever
|
|
158
|
+
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
|
158
159
|
*/
|
|
159
160
|
async mute(unmuteDate) {
|
|
160
|
-
|
|
161
|
+
const result = await this.client.muteChat(this.id._serialized, unmuteDate);
|
|
162
|
+
this.isMuted = result.isMuted;
|
|
163
|
+
this.muteExpiration = result.muteExpiration;
|
|
164
|
+
return result;
|
|
161
165
|
}
|
|
162
166
|
|
|
163
167
|
/**
|
|
164
168
|
* Unmutes this chat
|
|
169
|
+
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
|
165
170
|
*/
|
|
166
171
|
async unmute() {
|
|
167
|
-
|
|
172
|
+
const result = await this.client.unmuteChat(this.id._serialized);
|
|
173
|
+
this.isMuted = result.isMuted;
|
|
174
|
+
this.muteExpiration = result.muteExpiration;
|
|
175
|
+
return result;
|
|
168
176
|
}
|
|
169
177
|
|
|
170
178
|
/**
|
|
@@ -193,7 +201,7 @@ class Chat extends Base {
|
|
|
193
201
|
return true;
|
|
194
202
|
};
|
|
195
203
|
|
|
196
|
-
const chat = window.
|
|
204
|
+
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
|
197
205
|
let msgs = chat.msgs.getModelsArray().filter(msgFilter);
|
|
198
206
|
|
|
199
207
|
if (searchOptions && searchOptions.limit > 0) {
|
|
@@ -191,8 +191,7 @@ class GroupChat extends Chat {
|
|
|
191
191
|
*/
|
|
192
192
|
async removeParticipants(participantIds) {
|
|
193
193
|
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
|
194
|
-
const
|
|
195
|
-
const chat = await window.Store.Chat.find(chatWid);
|
|
194
|
+
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
|
196
195
|
const participants = participantIds.map(p => {
|
|
197
196
|
return chat.groupMetadata.participants.get(p);
|
|
198
197
|
}).filter(p => Boolean(p));
|
|
@@ -208,8 +207,7 @@ class GroupChat extends Chat {
|
|
|
208
207
|
*/
|
|
209
208
|
async promoteParticipants(participantIds) {
|
|
210
209
|
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
|
211
|
-
const
|
|
212
|
-
const chat = await window.Store.Chat.find(chatWid);
|
|
210
|
+
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
|
213
211
|
const participants = participantIds.map(p => {
|
|
214
212
|
return chat.groupMetadata.participants.get(p);
|
|
215
213
|
}).filter(p => Boolean(p));
|
|
@@ -225,8 +223,7 @@ class GroupChat extends Chat {
|
|
|
225
223
|
*/
|
|
226
224
|
async demoteParticipants(participantIds) {
|
|
227
225
|
return await this.client.pupPage.evaluate(async (chatId, participantIds) => {
|
|
228
|
-
const
|
|
229
|
-
const chat = await window.Store.Chat.find(chatWid);
|
|
226
|
+
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
|
230
227
|
const participants = participantIds.map(p => {
|
|
231
228
|
return chat.groupMetadata.participants.get(p);
|
|
232
229
|
}).filter(p => Boolean(p));
|
|
@@ -466,8 +463,7 @@ class GroupChat extends Chat {
|
|
|
466
463
|
*/
|
|
467
464
|
async leave() {
|
|
468
465
|
await this.client.pupPage.evaluate(async chatId => {
|
|
469
|
-
const
|
|
470
|
-
const chat = await window.Store.Chat.find(chatWid);
|
|
466
|
+
const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
|
|
471
467
|
return window.Store.GroupUtils.sendExitGroup(chat);
|
|
472
468
|
}, this.id._serialized);
|
|
473
469
|
}
|
|
@@ -45,7 +45,7 @@ class Message extends Base {
|
|
|
45
45
|
* Indicates if the message has media available for download
|
|
46
46
|
* @type {boolean}
|
|
47
47
|
*/
|
|
48
|
-
this.hasMedia = Boolean(data.
|
|
48
|
+
this.hasMedia = Boolean(data.directPath);
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Message content
|
|
@@ -498,23 +498,26 @@ class Message extends Base {
|
|
|
498
498
|
/**
|
|
499
499
|
* Deletes a message from the chat
|
|
500
500
|
* @param {?boolean} everyone If true and the message is sent by the current user or the user is an admin, will delete it for everyone in the chat.
|
|
501
|
+
* @param {?boolean} [clearMedia = true] If true, any associated media will also be deleted from a device.
|
|
501
502
|
*/
|
|
502
|
-
async delete(everyone) {
|
|
503
|
-
await this.client.pupPage.evaluate(async (msgId, everyone) => {
|
|
503
|
+
async delete(everyone, clearMedia = true) {
|
|
504
|
+
await this.client.pupPage.evaluate(async (msgId, everyone, clearMedia) => {
|
|
504
505
|
const msg = window.Store.Msg.get(msgId) || (await window.Store.Msg.getMessagesById([msgId]))?.messages?.[0];
|
|
505
|
-
|
|
506
|
+
const chat = window.Store.Chat.get(msg.id.remote) || (await window.Store.Chat.find(msg.id.remote));
|
|
506
507
|
|
|
507
|
-
const canRevoke =
|
|
508
|
+
const canRevoke =
|
|
509
|
+
window.Store.MsgActionChecks.canSenderRevokeMsg(msg) || window.Store.MsgActionChecks.canAdminRevokeMsg(msg);
|
|
510
|
+
|
|
508
511
|
if (everyone && canRevoke) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
return window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
|
|
513
|
-
}
|
|
512
|
+
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
|
513
|
+
? window.Store.Cmd.sendRevokeMsgs(chat, { list: [msg], type: 'message' }, { clearMedia: clearMedia })
|
|
514
|
+
: window.Store.Cmd.sendRevokeMsgs(chat, [msg], { clearMedia: true, type: msg.id.fromMe ? 'Sender' : 'Admin' });
|
|
514
515
|
}
|
|
515
516
|
|
|
516
|
-
return window.
|
|
517
|
-
|
|
517
|
+
return window.compareWwebVersions(window.Debug.VERSION, '>=', '2.3000.0')
|
|
518
|
+
? window.Store.Cmd.sendDeleteMsgs(chat, { list: [msg], type: 'message' }, clearMedia)
|
|
519
|
+
: window.Store.Cmd.sendDeleteMsgs(chat, [msg], clearMedia);
|
|
520
|
+
}, this.id._serialized, everyone, clearMedia);
|
|
518
521
|
}
|
|
519
522
|
|
|
520
523
|
/**
|
package/src/structures/index.js
CHANGED
|
@@ -5,6 +5,7 @@ module.exports = {
|
|
|
5
5
|
ClientInfo: require('./ClientInfo'),
|
|
6
6
|
Contact: require('./Contact'),
|
|
7
7
|
GroupChat: require('./GroupChat'),
|
|
8
|
+
Channel: require('./Channel'),
|
|
8
9
|
Location: require('./Location'),
|
|
9
10
|
Message: require('./Message'),
|
|
10
11
|
MessageMedia: require('./MessageMedia'),
|
|
@@ -65,7 +65,6 @@ exports.ExposeStore = () => {
|
|
|
65
65
|
window.Store.SendSeen = window.require('WAWebUpdateUnreadChatAction');
|
|
66
66
|
window.Store.User = window.require('WAWebUserPrefsMeUser');
|
|
67
67
|
window.Store.ContactMethods = window.require('WAWebContactGetters');
|
|
68
|
-
window.Store.UploadUtils = window.require('WAWebUploadManager');
|
|
69
68
|
window.Store.UserConstructor = window.require('WAWebWid');
|
|
70
69
|
window.Store.Validators = window.require('WALinkify');
|
|
71
70
|
window.Store.VCard = window.require('WAWebFrontendVcardUtils');
|
|
@@ -84,7 +83,7 @@ exports.ExposeStore = () => {
|
|
|
84
83
|
window.Store.LinkPreview = window.require('WAWebLinkPreviewChatAction');
|
|
85
84
|
window.Store.Socket = window.require('WADeprecatedSendIq');
|
|
86
85
|
window.Store.SocketWap = window.require('WAWap');
|
|
87
|
-
window.Store.SearchContext = window.require('WAWebChatMessageSearch')
|
|
86
|
+
window.Store.SearchContext = window.require('WAWebChatMessageSearch');
|
|
88
87
|
window.Store.DrawerManager = window.require('WAWebDrawerManager').DrawerManager;
|
|
89
88
|
window.Store.LidUtils = window.require('WAWebApiContact');
|
|
90
89
|
window.Store.WidToJid = window.require('WAWebWidToJid');
|
|
@@ -93,23 +92,26 @@ exports.ExposeStore = () => {
|
|
|
93
92
|
window.Store.pinUnpinMsg = window.require('WAWebSendPinMessageAction').sendPinInChatMsg;
|
|
94
93
|
window.Store.QueryExist = window.require('WAWebQueryExistsJob').queryWidExists;
|
|
95
94
|
window.Store.ReplyUtils = window.require('WAWebMsgReply');
|
|
96
|
-
window.Store.Settings = window.require('WAWebUserPrefsGeneral');
|
|
97
95
|
window.Store.BotSecret = window.require('WAWebBotMessageSecret');
|
|
98
96
|
window.Store.BotProfiles = window.require('WAWebBotProfileCollection');
|
|
97
|
+
window.Store.ContactCollection = window.require('WAWebContactCollection').ContactCollection;
|
|
99
98
|
window.Store.DeviceList = window.require('WAWebApiDeviceList');
|
|
100
99
|
window.Store.HistorySync = window.require('WAWebSendNonMessageDataRequest');
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
window.Store.AddonReactionTable = window.require('WAWebAddonReactionTableMode').reactionTableMode;
|
|
101
|
+
window.Store.ChatGetters = window.require('WAWebChatGetters');
|
|
103
102
|
|
|
103
|
+
window.Store.Settings = {
|
|
104
|
+
...window.require('WAWebUserPrefsGeneral'),
|
|
105
|
+
...window.require('WAWebUserPrefsNotifications'),
|
|
106
|
+
setPushname: window.require('WAWebSetPushnameConnAction').setPushname
|
|
107
|
+
};
|
|
104
108
|
window.Store.NumberInfo = {
|
|
105
109
|
...window.require('WAPhoneUtils'),
|
|
106
110
|
...window.require('WAPhoneFindCC')
|
|
107
111
|
};
|
|
108
|
-
|
|
109
112
|
window.Store.ForwardUtils = {
|
|
110
113
|
...window.require('WAWebForwardMessagesToChat')
|
|
111
114
|
};
|
|
112
|
-
|
|
113
115
|
window.Store.StickerTools = {
|
|
114
116
|
...window.require('WAWebImageUtils'),
|
|
115
117
|
...window.require('WAWebAddWebpMetadata')
|
|
@@ -137,6 +139,41 @@ exports.ExposeStore = () => {
|
|
|
137
139
|
...window.require('WAWebApiMembershipApprovalRequestStore'),
|
|
138
140
|
...window.require('WASmaxGroupsMembershipRequestsActionRPC')
|
|
139
141
|
};
|
|
142
|
+
window.Store.ChannelUtils = {
|
|
143
|
+
...window.require('WAWebLoadNewsletterPreviewChatAction'),
|
|
144
|
+
...window.require('WAWebNewsletterMetadataQueryJob'),
|
|
145
|
+
...window.require('WAWebNewsletterCreateQueryJob'),
|
|
146
|
+
...window.require('WAWebEditNewsletterMetadataAction'),
|
|
147
|
+
...window.require('WAWebNewsletterDeleteAction'),
|
|
148
|
+
...window.require('WAWebNewsletterSubscribeAction'),
|
|
149
|
+
...window.require('WAWebNewsletterUnsubscribeAction'),
|
|
150
|
+
...window.require('WAWebNewsletterDirectorySearchAction'),
|
|
151
|
+
...window.require('WAWebNewsletterToggleMuteStateJob'),
|
|
152
|
+
...window.require('WAWebNewsletterGatingUtils'),
|
|
153
|
+
...window.require('WAWebNewsletterModelUtils'),
|
|
154
|
+
...window.require('WAWebMexAcceptNewsletterAdminInviteJob'),
|
|
155
|
+
...window.require('WAWebMexRevokeNewsletterAdminInviteJob'),
|
|
156
|
+
...window.require('WAWebChangeNewsletterOwnerAction'),
|
|
157
|
+
...window.require('WAWebDemoteNewsletterAdminAction'),
|
|
158
|
+
...window.require('WAWebNewsletterDemoteAdminJob'),
|
|
159
|
+
countryCodesIso: window.require('WAWebCountriesNativeCountryNames'),
|
|
160
|
+
currentRegion: window.require('WAWebL10N').getRegion(),
|
|
161
|
+
};
|
|
162
|
+
window.Store.SendChannelMessage = {
|
|
163
|
+
...window.require('WAWebNewsletterUpdateMsgsRecordsJob'),
|
|
164
|
+
...window.require('WAWebMsgDataFromModel'),
|
|
165
|
+
...window.require('WAWebNewsletterSendMessageJob'),
|
|
166
|
+
...window.require('WAWebNewsletterSendMsgAction'),
|
|
167
|
+
...window.require('WAMediaCalculateFilehash')
|
|
168
|
+
};
|
|
169
|
+
window.Store.ChannelSubscribers = {
|
|
170
|
+
...window.require('WAWebMexFetchNewsletterSubscribersJob'),
|
|
171
|
+
...window.require('WAWebNewsletterSubscriberListAction')
|
|
172
|
+
};
|
|
173
|
+
window.Store.AddressbookContactUtils = {
|
|
174
|
+
...window.require('WAWebSaveContactAction'),
|
|
175
|
+
...window.require('WAWebDeleteContactAction')
|
|
176
|
+
};
|
|
140
177
|
|
|
141
178
|
if (!window.Store.Chat._find || !window.Store.Chat.findImpl) {
|
|
142
179
|
window.Store.Chat._find = e => {
|