whatsapp-web.js 1.28.1-alpha.0 → 1.30.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/src/Client.js CHANGED
@@ -15,7 +15,7 @@ const { LoadUtils } = require('./util/Injected/Utils');
15
15
  const ChatFactory = require('./factories/ChatFactory');
16
16
  const ContactFactory = require('./factories/ContactFactory');
17
17
  const WebCacheFactory = require('./webCache/WebCacheFactory');
18
- const { ClientInfo, Message, MessageMedia, Contact, Location, Poll, PollVote, GroupNotification, Label, Call, Buttons, List, Reaction, Broadcast} = require('./structures');
18
+ const { Broadcast, Buttons, Call, ClientInfo, Contact, GroupNotification, Label, List, Location, Message, MessageMedia, Poll, PollVote, Reaction } = require('./structures');
19
19
  const NoAuth = require('./authStrategies/NoAuth');
20
20
  const {exposeFunctionIfAbsent} = require('./util/Puppeteer');
21
21
 
@@ -820,11 +820,9 @@ class Client extends EventEmitter {
820
820
  *
821
821
  */
822
822
  async sendSeen(chatId) {
823
- const result = await this.pupPage.evaluate(async (chatId) => {
823
+ return await this.pupPage.evaluate(async (chatId) => {
824
824
  return window.WWebJS.sendSeen(chatId);
825
-
826
825
  }, chatId);
827
- return result;
828
826
  }
829
827
 
830
828
  /**
@@ -853,7 +851,9 @@ class Client extends EventEmitter {
853
851
  * @property {string} [stickerAuthor=undefined] - Sets the author of the sticker, (if sendMediaAsSticker is true).
854
852
  * @property {string} [stickerName=undefined] - Sets the name of the sticker, (if sendMediaAsSticker is true).
855
853
  * @property {string[]} [stickerCategories=undefined] - Sets the categories of the sticker, (if sendMediaAsSticker is true). Provide emoji char array, can be null.
854
+ * @property {boolean} [ignoreQuoteErrors = true] - Should the bot send a quoted message without the quoted message if it fails to get the quote?
856
855
  * @property {MessageMedia} [media] - Media to be sent
856
+ * @property {any} [extra] - Extra options
857
857
  */
858
858
 
859
859
  /**
@@ -865,6 +865,19 @@ class Client extends EventEmitter {
865
865
  * @returns {Promise<Message>} Message that was just sent
866
866
  */
867
867
  async sendMessage(chatId, content, options = {}) {
868
+ const isChannel = /@\w*newsletter\b/.test(chatId);
869
+
870
+ if (isChannel && [
871
+ options.sendMediaAsDocument, options.quotedMessageId,
872
+ options.parseVCards, options.isViewOnce,
873
+ content instanceof Location, content instanceof Contact,
874
+ content instanceof Buttons, content instanceof List,
875
+ Array.isArray(content) && content.length > 0 && content[0] instanceof Contact
876
+ ].includes(true)) {
877
+ console.warn('The message type is currently not supported for sending in channels,\nthe supported message types are: text, image, sticker, gif, video, voice and poll.');
878
+ return null;
879
+ }
880
+
868
881
  if (options.mentions) {
869
882
  !Array.isArray(options.mentions) && (options.mentions = [options.mentions]);
870
883
  if (options.mentions.some((possiblyContact) => possiblyContact instanceof Contact)) {
@@ -874,7 +887,7 @@ class Client extends EventEmitter {
874
887
  }
875
888
 
876
889
  options.groupMentions && !Array.isArray(options.groupMentions) && (options.groupMentions = [options.groupMentions]);
877
-
890
+
878
891
  let internalOptions = {
879
892
  linkPreview: options.linkPreview === false ? undefined : true,
880
893
  sendAudioAsVoice: options.sendAudioAsVoice,
@@ -887,17 +900,18 @@ class Client extends EventEmitter {
887
900
  mentionedJidList: options.mentions || [],
888
901
  groupMentions: options.groupMentions,
889
902
  invokedBotWid: options.invokedBotWid,
903
+ ignoreQuoteErrors: options.ignoreQuoteErrors !== false,
890
904
  extraOptions: options.extra
891
905
  };
892
906
 
893
- const sendSeen = typeof options.sendSeen === 'undefined' ? true : options.sendSeen;
907
+ const sendSeen = options.sendSeen !== false;
894
908
 
895
909
  if (content instanceof MessageMedia) {
896
- internalOptions.attachment = content;
910
+ internalOptions.media = content;
897
911
  internalOptions.isViewOnce = options.isViewOnce,
898
912
  content = '';
899
913
  } else if (options.media instanceof MessageMedia) {
900
- internalOptions.attachment = options.media;
914
+ internalOptions.media = options.media;
901
915
  internalOptions.caption = content;
902
916
  internalOptions.isViewOnce = options.isViewOnce,
903
917
  content = '';
@@ -914,17 +928,19 @@ class Client extends EventEmitter {
914
928
  internalOptions.contactCardList = content.map(contact => contact.id._serialized);
915
929
  content = '';
916
930
  } else if (content instanceof Buttons) {
931
+ console.warn('Buttons are now deprecated. See more at https://www.youtube.com/watch?v=hv1R1rLeVVE.');
917
932
  if (content.type !== 'chat') { internalOptions.attachment = content.body; }
918
933
  internalOptions.buttons = content;
919
934
  content = '';
920
935
  } else if (content instanceof List) {
936
+ console.warn('Lists are now deprecated. See more at https://www.youtube.com/watch?v=hv1R1rLeVVE.');
921
937
  internalOptions.list = content;
922
938
  content = '';
923
939
  }
924
940
 
925
- if (internalOptions.sendMediaAsSticker && internalOptions.attachment) {
926
- internalOptions.attachment = await Util.formatToWebpSticker(
927
- internalOptions.attachment, {
941
+ if (internalOptions.sendMediaAsSticker && internalOptions.media) {
942
+ internalOptions.media = await Util.formatToWebpSticker(
943
+ internalOptions.media, {
928
944
  name: options.stickerName,
929
945
  author: options.stickerAuthor,
930
946
  categories: options.stickerCategories
@@ -932,20 +948,60 @@ class Client extends EventEmitter {
932
948
  );
933
949
  }
934
950
 
935
- const newMessage = await this.pupPage.evaluate(async (chatId, message, options, sendSeen) => {
936
- const chatWid = window.Store.WidFactory.createWid(chatId);
937
- const chat = await window.Store.Chat.find(chatWid);
951
+ const sentMsg = await this.pupPage.evaluate(async (chatId, content, options, sendSeen) => {
952
+ const chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
938
953
 
954
+ if (!chat) return null;
939
955
 
940
956
  if (sendSeen) {
941
957
  await window.WWebJS.sendSeen(chatId);
942
958
  }
943
959
 
944
- const msg = await window.WWebJS.sendMessage(chat, message, options, sendSeen);
945
- return window.WWebJS.getMessageModel(msg);
960
+ const msg = await window.WWebJS.sendMessage(chat, content, options);
961
+ return msg
962
+ ? window.WWebJS.getMessageModel(msg)
963
+ : undefined;
946
964
  }, chatId, content, internalOptions, sendSeen);
947
965
 
948
- return new Message(this, newMessage);
966
+ return sentMsg
967
+ ? new Message(this, sentMsg)
968
+ : undefined;
969
+ }
970
+
971
+ /**
972
+ * @typedef {Object} SendChannelAdminInviteOptions
973
+ * @property {?string} comment The comment to be added to an invitation
974
+ */
975
+
976
+ /**
977
+ * Sends a channel admin invitation to a user, allowing them to become an admin of the channel
978
+ * @param {string} chatId The ID of a user to send the channel admin invitation to
979
+ * @param {string} channelId The ID of a channel for which the invitation is being sent
980
+ * @param {SendChannelAdminInviteOptions} options
981
+ * @returns {Promise<boolean>} Returns true if an invitation was sent successfully, false otherwise
982
+ */
983
+ async sendChannelAdminInvite(chatId, channelId, options = {}) {
984
+ const response = await this.pupPage.evaluate(async (chatId, channelId, options) => {
985
+ const channelWid = window.Store.WidFactory.createWid(channelId);
986
+ const chatWid = window.Store.WidFactory.createWid(chatId);
987
+ const chat = window.Store.Chat.get(chatWid) || (await window.Store.Chat.find(chatWid));
988
+
989
+ if (!chatWid.isUser()) {
990
+ return false;
991
+ }
992
+
993
+ return await window.Store.SendChannelMessage.sendNewsletterAdminInviteMessage(
994
+ chat,
995
+ {
996
+ newsletterWid: channelWid,
997
+ invitee: chatWid,
998
+ inviteMessage: options.comment,
999
+ base64Thumb: await window.WWebJS.getProfilePicThumbToBase64(channelWid)
1000
+ }
1001
+ );
1002
+ }, chatId, channelId, options);
1003
+
1004
+ return response.messageSendResult === 'OK';
949
1005
  }
950
1006
 
951
1007
  /**
@@ -971,7 +1027,7 @@ class Client extends EventEmitter {
971
1027
  * @returns {Promise<Array<Chat>>}
972
1028
  */
973
1029
  async getChats() {
974
- let chats = await this.pupPage.evaluate(async () => {
1030
+ const chats = await this.pupPage.evaluate(async () => {
975
1031
  return await window.WWebJS.getChats();
976
1032
  });
977
1033
 
@@ -979,16 +1035,51 @@ class Client extends EventEmitter {
979
1035
  }
980
1036
 
981
1037
  /**
982
- * Get chat instance by ID
1038
+ * Gets all cached {@link Channel} instance
1039
+ * @returns {Promise<Array<Channel>>}
1040
+ */
1041
+ async getChannels() {
1042
+ const channels = await this.pupPage.evaluate(async () => {
1043
+ return await window.WWebJS.getChannels();
1044
+ });
1045
+
1046
+ return channels.map((channel) => ChatFactory.create(this, channel));
1047
+ }
1048
+
1049
+ /**
1050
+ * Gets chat or channel instance by ID
983
1051
  * @param {string} chatId
984
- * @returns {Promise<Chat>}
1052
+ * @returns {Promise<Chat|Channel>}
985
1053
  */
986
1054
  async getChatById(chatId) {
987
- let chat = await this.pupPage.evaluate(async chatId => {
1055
+ const chat = await this.pupPage.evaluate(async chatId => {
988
1056
  return await window.WWebJS.getChat(chatId);
989
1057
  }, chatId);
1058
+ return chat
1059
+ ? ChatFactory.create(this, chat)
1060
+ : undefined;
1061
+ }
990
1062
 
991
- return ChatFactory.create(this, chat);
1063
+ /**
1064
+ * Gets a {@link Channel} instance by invite code
1065
+ * @param {string} inviteCode The code that comes after the 'https://whatsapp.com/channel/'
1066
+ * @returns {Promise<Channel>}
1067
+ */
1068
+ async getChannelByInviteCode(inviteCode) {
1069
+ const channel = await this.pupPage.evaluate(async (inviteCode) => {
1070
+ let channelMetadata;
1071
+ try {
1072
+ channelMetadata = await window.WWebJS.getChannelMetadata(inviteCode);
1073
+ } catch (err) {
1074
+ if (err.name === 'ServerStatusCodeError') return null;
1075
+ throw err;
1076
+ }
1077
+ return await window.WWebJS.getChat(channelMetadata.id);
1078
+ }, inviteCode);
1079
+
1080
+ return channel
1081
+ ? ChatFactory.create(this, channel)
1082
+ : undefined;
992
1083
  }
993
1084
 
994
1085
  /**
@@ -1058,6 +1149,61 @@ class Client extends EventEmitter {
1058
1149
  return res.gid._serialized;
1059
1150
  }
1060
1151
 
1152
+ /**
1153
+ * Accepts a channel admin invitation and promotes the current user to a channel admin
1154
+ * @param {string} channelId The channel ID to accept the admin invitation from
1155
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1156
+ */
1157
+ async acceptChannelAdminInvite(channelId) {
1158
+ return await this.pupPage.evaluate(async (channelId) => {
1159
+ try {
1160
+ await window.Store.ChannelUtils.acceptNewsletterAdminInvite(channelId);
1161
+ return true;
1162
+ } catch (err) {
1163
+ if (err.name === 'ServerStatusCodeError') return false;
1164
+ throw err;
1165
+ }
1166
+ }, channelId);
1167
+ }
1168
+
1169
+ /**
1170
+ * Revokes a channel admin invitation sent to a user by a channel owner
1171
+ * @param {string} channelId The channel ID an invitation belongs to
1172
+ * @param {string} userId The user ID the invitation was sent to
1173
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1174
+ */
1175
+ async revokeChannelAdminInvite(channelId, userId) {
1176
+ return await this.pupPage.evaluate(async (channelId, userId) => {
1177
+ try {
1178
+ const userWid = window.Store.WidFactory.createWid(userId);
1179
+ await window.Store.ChannelUtils.revokeNewsletterAdminInvite(channelId, userWid);
1180
+ return true;
1181
+ } catch (err) {
1182
+ if (err.name === 'ServerStatusCodeError') return false;
1183
+ throw err;
1184
+ }
1185
+ }, channelId, userId);
1186
+ }
1187
+
1188
+ /**
1189
+ * Demotes a channel admin to a regular subscriber (can be used also for self-demotion)
1190
+ * @param {string} channelId The channel ID to demote an admin in
1191
+ * @param {string} userId The user ID to demote
1192
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1193
+ */
1194
+ async demoteChannelAdmin(channelId, userId) {
1195
+ return await this.pupPage.evaluate(async (channelId, userId) => {
1196
+ try {
1197
+ const userWid = window.Store.WidFactory.createWid(userId);
1198
+ await window.Store.ChannelUtils.demoteNewsletterAdmin(channelId, userWid);
1199
+ return true;
1200
+ } catch (err) {
1201
+ if (err.name === 'ServerStatusCodeError') return false;
1202
+ throw err;
1203
+ }
1204
+ }, channelId, userId);
1205
+ }
1206
+
1061
1207
  /**
1062
1208
  * Accepts a private invitation to join a group
1063
1209
  * @param {object} inviteInfo Invite V4 Info
@@ -1134,7 +1280,7 @@ class Client extends EventEmitter {
1134
1280
  */
1135
1281
  async archiveChat(chatId) {
1136
1282
  return await this.pupPage.evaluate(async chatId => {
1137
- let chat = await window.Store.Chat.get(chatId);
1283
+ let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
1138
1284
  await window.Store.Cmd.archiveChat(chat, true);
1139
1285
  return true;
1140
1286
  }, chatId);
@@ -1146,7 +1292,7 @@ class Client extends EventEmitter {
1146
1292
  */
1147
1293
  async unarchiveChat(chatId) {
1148
1294
  return await this.pupPage.evaluate(async chatId => {
1149
- let chat = await window.Store.Chat.get(chatId);
1295
+ let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
1150
1296
  await window.Store.Cmd.archiveChat(chat, false);
1151
1297
  return false;
1152
1298
  }, chatId);
@@ -1158,7 +1304,7 @@ class Client extends EventEmitter {
1158
1304
  */
1159
1305
  async pinChat(chatId) {
1160
1306
  return this.pupPage.evaluate(async chatId => {
1161
- let chat = window.Store.Chat.get(chatId);
1307
+ let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
1162
1308
  if (chat.pin) {
1163
1309
  return true;
1164
1310
  }
@@ -1181,7 +1327,7 @@ class Client extends EventEmitter {
1181
1327
  */
1182
1328
  async unpinChat(chatId) {
1183
1329
  return this.pupPage.evaluate(async chatId => {
1184
- let chat = window.Store.Chat.get(chatId);
1330
+ let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
1185
1331
  if (!chat.pin) {
1186
1332
  return false;
1187
1333
  }
@@ -1233,7 +1379,7 @@ class Client extends EventEmitter {
1233
1379
  */
1234
1380
  async markChatUnread(chatId) {
1235
1381
  await this.pupPage.evaluate(async chatId => {
1236
- let chat = await window.Store.Chat.get(chatId);
1382
+ let chat = await window.WWebJS.getChat(chatId, { getAsModel: false });
1237
1383
  await window.Store.Cmd.markChatUnread(chat, true);
1238
1384
  }, chatId);
1239
1385
  }
@@ -1435,7 +1581,7 @@ class Client extends EventEmitter {
1435
1581
  for (const participant of createGroupResult.participants) {
1436
1582
  let isInviteV4Sent = false;
1437
1583
  const participantId = participant.wid._serialized;
1438
- const statusCode = participant.error ?? 200;
1584
+ const statusCode = participant.error || 200;
1439
1585
 
1440
1586
  if (autoSendInviteV4 && statusCode === 403) {
1441
1587
  window.Store.Contact.gadd(participant.wid, { silent: true });
@@ -1474,6 +1620,219 @@ class Client extends EventEmitter {
1474
1620
  }, title, participants, options);
1475
1621
  }
1476
1622
 
1623
+ /**
1624
+ * An object that handles the result for {@link createChannel} method
1625
+ * @typedef {Object} CreateChannelResult
1626
+ * @property {string} title A channel title
1627
+ * @property {ChatId} nid An object that handels the newly created channel ID
1628
+ * @property {string} nid.server 'newsletter'
1629
+ * @property {string} nid.user 'XXXXXXXXXX'
1630
+ * @property {string} nid._serialized 'XXXXXXXXXX@newsletter'
1631
+ * @property {string} inviteLink The channel invite link, starts with 'https://whatsapp.com/channel/'
1632
+ * @property {number} createdAtTs The timestamp the channel was created at
1633
+ */
1634
+
1635
+ /**
1636
+ * Options for the channel creation
1637
+ * @typedef {Object} CreateChannelOptions
1638
+ * @property {?string} description The channel description
1639
+ * @property {?MessageMedia} picture The channel profile picture
1640
+ */
1641
+
1642
+ /**
1643
+ * Creates a new channel
1644
+ * @param {string} title The channel name
1645
+ * @param {CreateChannelOptions} options
1646
+ * @returns {Promise<CreateChannelResult|string>} Returns an object that handles the result for the channel creation or an error message as a string
1647
+ */
1648
+ async createChannel(title, options = {}) {
1649
+ return await this.pupPage.evaluate(async (title, options) => {
1650
+ let response, { description = null, picture = null } = options;
1651
+
1652
+ if (!window.Store.ChannelUtils.isNewsletterCreationEnabled()) {
1653
+ return 'CreateChannelError: A channel creation is not enabled';
1654
+ }
1655
+
1656
+ if (picture) {
1657
+ picture = await window.WWebJS.cropAndResizeImage(picture, {
1658
+ asDataUrl: true,
1659
+ mimetype: 'image/jpeg',
1660
+ size: 640,
1661
+ quality: 1
1662
+ });
1663
+ }
1664
+
1665
+ try {
1666
+ response = await window.Store.ChannelUtils.createNewsletterQuery({
1667
+ name: title,
1668
+ description: description,
1669
+ picture: picture,
1670
+ });
1671
+ } catch (err) {
1672
+ if (err.name === 'ServerStatusCodeError') {
1673
+ return 'CreateChannelError: An error occupied while creating a channel';
1674
+ }
1675
+ throw err;
1676
+ }
1677
+
1678
+ return {
1679
+ title: title,
1680
+ nid: window.Store.JidToWid.newsletterJidToWid(response.idJid),
1681
+ inviteLink: `https://whatsapp.com/channel/${response.newsletterInviteLinkMetadataMixin.inviteCode}`,
1682
+ createdAtTs: response.newsletterCreationTimeMetadataMixin.creationTimeValue
1683
+ };
1684
+ }, title, options);
1685
+ }
1686
+
1687
+ /**
1688
+ * Subscribe to channel
1689
+ * @param {string} channelId The channel ID
1690
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1691
+ */
1692
+ async subscribeToChannel(channelId) {
1693
+ return await this.pupPage.evaluate(async (channelId) => {
1694
+ return await window.WWebJS.subscribeToUnsubscribeFromChannel(channelId, 'Subscribe');
1695
+ }, channelId);
1696
+ }
1697
+
1698
+ /**
1699
+ * Options for unsubscribe from a channel
1700
+ * @typedef {Object} UnsubscribeOptions
1701
+ * @property {boolean} [deleteLocalModels = false] If true, after an unsubscription, it will completely remove a channel from the channel collection making it seem like the current user have never interacted with it. Otherwise it will only remove a channel from the list of channels the current user is subscribed to and will set the membership type for that channel to GUEST
1702
+ */
1703
+
1704
+ /**
1705
+ * Unsubscribe from channel
1706
+ * @param {string} channelId The channel ID
1707
+ * @param {UnsubscribeOptions} options
1708
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1709
+ */
1710
+ async unsubscribeFromChannel(channelId, options) {
1711
+ return await this.pupPage.evaluate(async (channelId, options) => {
1712
+ return await window.WWebJS.subscribeToUnsubscribeFromChannel(channelId, 'Unsubscribe', options);
1713
+ }, channelId, options);
1714
+ }
1715
+
1716
+ /**
1717
+ * Options for transferring a channel ownership to another user
1718
+ * @typedef {Object} TransferChannelOwnershipOptions
1719
+ * @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.
1720
+ */
1721
+
1722
+ /**
1723
+ * Transfers a channel ownership to another user.
1724
+ * Note: the user you are transferring the channel ownership to must be a channel admin.
1725
+ * @param {string} channelId
1726
+ * @param {string} newOwnerId
1727
+ * @param {TransferChannelOwnershipOptions} options
1728
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1729
+ */
1730
+ async transferChannelOwnership(channelId, newOwnerId, options = {}) {
1731
+ return await this.pupPage.evaluate(async (channelId, newOwnerId, options) => {
1732
+ const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
1733
+ const newOwner = window.Store.Contact.get(newOwnerId) || (await window.Store.Contact.find(newOwnerId));
1734
+ if (!channel.newsletterMetadata) {
1735
+ await window.Store.NewsletterMetadataCollection.update(channel.id);
1736
+ }
1737
+
1738
+ try {
1739
+ await window.Store.ChannelUtils.changeNewsletterOwnerAction(channel, newOwner);
1740
+
1741
+ if (options.shouldDismissSelfAsAdmin) {
1742
+ const meContact = window.Store.ContactCollection.getMeContact();
1743
+ meContact && (await window.Store.ChannelUtils.demoteNewsletterAdminAction(channel, meContact));
1744
+ }
1745
+ } catch (error) {
1746
+ return false;
1747
+ }
1748
+
1749
+ return true;
1750
+ }, channelId, newOwnerId, options);
1751
+ }
1752
+
1753
+ /**
1754
+ * Searches for channels based on search criteria, there are some notes:
1755
+ * 1. The method finds only channels you are not subscribed to currently
1756
+ * 2. If you have never been subscribed to a found channel
1757
+ * or you have unsubscribed from it with {@link UnsubscribeOptions.deleteLocalModels} set to 'true',
1758
+ * the lastMessage property of a found channel will be 'null'
1759
+ *
1760
+ * @param {Object} searchOptions Search options
1761
+ * @param {string} [searchOptions.searchText = ''] Text to search
1762
+ * @param {Array<string>} [searchOptions.countryCodes = [your local region]] Array of country codes in 'ISO 3166-1 alpha-2' standart (@see https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) to search for channels created in these countries
1763
+ * @param {boolean} [searchOptions.skipSubscribedNewsletters = false] If true, channels that user is subscribed to won't appear in found channels
1764
+ * @param {number} [searchOptions.view = 0] View type, makes sense only when the searchText is empty. Valid values to provide are:
1765
+ * 0 for RECOMMENDED channels
1766
+ * 1 for TRENDING channels
1767
+ * 2 for POPULAR channels
1768
+ * 3 for NEW channels
1769
+ * @param {number} [searchOptions.limit = 50] The limit of found channels to be appear in the returnig result
1770
+ * @returns {Promise<Array<Channel>|[]>} Returns an array of Channel objects or an empty array if no channels were found
1771
+ */
1772
+ async searchChannels(searchOptions = {}) {
1773
+ return await this.pupPage.evaluate(async ({
1774
+ searchText = '',
1775
+ countryCodes = [window.Store.ChannelUtils.currentRegion],
1776
+ skipSubscribedNewsletters = false,
1777
+ view = 0,
1778
+ limit = 50
1779
+ }) => {
1780
+ searchText = searchText.trim();
1781
+ const currentRegion = window.Store.ChannelUtils.currentRegion;
1782
+ if (![0, 1, 2, 3].includes(view)) view = 0;
1783
+
1784
+ countryCodes = countryCodes.length === 1 && countryCodes[0] === currentRegion
1785
+ ? countryCodes
1786
+ : countryCodes.filter((code) => Object.keys(window.Store.ChannelUtils.countryCodesIso).includes(code));
1787
+
1788
+ const viewTypeMapping = {
1789
+ 0: 'RECOMMENDED',
1790
+ 1: 'TRENDING',
1791
+ 2: 'POPULAR',
1792
+ 3: 'NEW'
1793
+ };
1794
+
1795
+ searchOptions = {
1796
+ searchText: searchText,
1797
+ countryCodes: countryCodes,
1798
+ skipSubscribedNewsletters: skipSubscribedNewsletters,
1799
+ view: viewTypeMapping[view],
1800
+ categories: [],
1801
+ cursorToken: ''
1802
+ };
1803
+
1804
+ const originalFunction = window.Store.ChannelUtils.getNewsletterDirectoryPageSize;
1805
+ limit !== 50 && (window.Store.ChannelUtils.getNewsletterDirectoryPageSize = () => limit);
1806
+
1807
+ const channels = (await window.Store.ChannelUtils.fetchNewsletterDirectories(searchOptions)).newsletters;
1808
+
1809
+ limit !== 50 && (window.Store.ChannelUtils.getNewsletterDirectoryPageSize = originalFunction);
1810
+
1811
+ return channels
1812
+ ? await Promise.all(channels.map((channel) => window.WWebJS.getChatModel(channel, { isChannel: true })))
1813
+ : [];
1814
+ }, searchOptions);
1815
+ }
1816
+
1817
+ /**
1818
+ * Deletes the channel you created
1819
+ * @param {string} channelId The ID of a channel to delete
1820
+ * @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
1821
+ */
1822
+ async deleteChannel(channelId) {
1823
+ return await this.client.pupPage.evaluate(async (channelId) => {
1824
+ const channel = await window.WWebJS.getChat(channelId, { getAsModel: false });
1825
+ if (!channel) return false;
1826
+ try {
1827
+ await window.Store.ChannelUtils.deleteNewsletterAction(channel);
1828
+ return true;
1829
+ } catch (err) {
1830
+ if (err.name === 'ServerStatusCodeError') return false;
1831
+ throw err;
1832
+ }
1833
+ }, channelId);
1834
+ }
1835
+
1477
1836
  /**
1478
1837
  * Get all current Labels
1479
1838
  * @returns {Promise<Array<Label>>}
@@ -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;