@pney/whatsapp-web 1.34.6-3 → 1.34.7-1

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.
Files changed (59) hide show
  1. package/.env.example +0 -1
  2. package/.gitattributes +4 -0
  3. package/.husky/commit-msg +4 -0
  4. package/.husky/pre-commit +1 -0
  5. package/.lintstagedrc.json +6 -0
  6. package/.prettierignore +8 -0
  7. package/.prettierrc.json +10 -0
  8. package/README.md +83 -80
  9. package/commitlint.config.js +29 -0
  10. package/eslint.config.mjs +67 -0
  11. package/example.js +151 -71
  12. package/index.d.ts +982 -734
  13. package/index.js +4 -4
  14. package/package.json +1 -1
  15. package/shell.js +4 -4
  16. package/src/Client.js +1860 -921
  17. package/src/authStrategies/BaseAuthStrategy.js +4 -2
  18. package/src/authStrategies/LocalAuth.js +25 -12
  19. package/src/authStrategies/NoAuth.js +3 -4
  20. package/src/authStrategies/RemoteAuth.js +92 -43
  21. package/src/factories/ChatFactory.js +1 -1
  22. package/src/factories/ContactFactory.js +2 -2
  23. package/src/structures/Base.js +5 -3
  24. package/src/structures/Broadcast.js +1 -2
  25. package/src/structures/BusinessContact.js +1 -2
  26. package/src/structures/Buttons.js +14 -10
  27. package/src/structures/Call.js +10 -6
  28. package/src/structures/Channel.js +171 -91
  29. package/src/structures/Chat.js +57 -41
  30. package/src/structures/ClientInfo.js +1 -1
  31. package/src/structures/Contact.js +37 -16
  32. package/src/structures/GroupChat.js +425 -228
  33. package/src/structures/GroupNotification.js +21 -12
  34. package/src/structures/Label.js +6 -6
  35. package/src/structures/List.js +22 -14
  36. package/src/structures/Location.js +5 -4
  37. package/src/structures/Message.js +412 -160
  38. package/src/structures/MessageMedia.js +31 -18
  39. package/src/structures/Order.js +4 -4
  40. package/src/structures/Payment.js +6 -3
  41. package/src/structures/Poll.js +2 -2
  42. package/src/structures/PollVote.js +9 -6
  43. package/src/structures/PrivateChat.js +2 -4
  44. package/src/structures/PrivateContact.js +2 -4
  45. package/src/structures/Product.js +1 -1
  46. package/src/structures/ProductMetadata.js +1 -2
  47. package/src/structures/Reaction.js +2 -4
  48. package/src/structures/ScheduledEvent.js +22 -10
  49. package/src/util/Constants.js +8 -6
  50. package/src/util/Injected/AuthStore/AuthStore.js +7 -3
  51. package/src/util/Injected/Utils.js +753 -345
  52. package/src/util/InterfaceController.js +72 -25
  53. package/src/util/Puppeteer.js +1 -1
  54. package/src/util/Util.js +28 -15
  55. package/src/webCache/LocalWebCache.js +7 -5
  56. package/src/webCache/RemoteWebCache.js +10 -4
  57. package/src/webCache/WebCache.js +8 -5
  58. package/src/webCache/WebCacheFactory.js +9 -9
  59. package/CODE_OF_CONDUCT.md +0 -133
@@ -8,15 +8,17 @@ class BaseAuthStrategy {
8
8
  setup(client) {
9
9
  this.client = client;
10
10
  }
11
+
11
12
  async beforeBrowserInitialized() {}
12
13
  async afterBrowserInitialized() {}
13
14
  async onAuthenticationNeeded() {
14
15
  return {
15
16
  failed: false,
16
17
  restart: false,
17
- failureEventPayload: undefined
18
+ failureEventPayload: undefined,
18
19
  };
19
20
  }
21
+
20
22
  async getAuthEventPayload() {}
21
23
  async afterAuthReady() {}
22
24
  async disconnect() {}
@@ -24,4 +26,4 @@ class BaseAuthStrategy {
24
26
  async logout() {}
25
27
  }
26
28
 
27
- module.exports = BaseAuthStrategy;
29
+ module.exports = BaseAuthStrategy;
@@ -8,16 +8,18 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
8
8
  * Local directory-based authentication
9
9
  * @param {object} options - options
10
10
  * @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
11
- * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
11
+ * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
12
12
  * @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
13
- */
13
+ */
14
14
  class LocalAuth extends BaseAuthStrategy {
15
- constructor({ clientId, dataPath, rmMaxRetries }={}) {
15
+ constructor({ clientId, dataPath, rmMaxRetries } = {}) {
16
16
  super();
17
17
 
18
18
  const idRegex = /^[-_\w]+$/i;
19
- if(clientId && !idRegex.test(clientId)) {
20
- throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
19
+ if (clientId && !idRegex.test(clientId)) {
20
+ throw new Error(
21
+ 'Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.',
22
+ );
21
23
  }
22
24
 
23
25
  this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
@@ -27,18 +29,25 @@ class LocalAuth extends BaseAuthStrategy {
27
29
 
28
30
  async beforeBrowserInitialized() {
29
31
  const puppeteerOpts = this.client.options.puppeteer;
30
- const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
32
+ const sessionDirName = this.clientId
33
+ ? `session-${this.clientId}`
34
+ : 'session';
31
35
  const dirPath = path.join(this.dataPath, sessionDirName);
32
36
 
33
- if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
34
- throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
37
+ if (
38
+ puppeteerOpts.userDataDir &&
39
+ puppeteerOpts.userDataDir !== dirPath
40
+ ) {
41
+ throw new Error(
42
+ 'LocalAuth is not compatible with a user-supplied userDataDir.',
43
+ );
35
44
  }
36
45
 
37
46
  fs.mkdirSync(dirPath, { recursive: true });
38
-
47
+
39
48
  this.client.options.puppeteer = {
40
49
  ...puppeteerOpts,
41
- userDataDir: dirPath
50
+ userDataDir: dirPath,
42
51
  };
43
52
 
44
53
  this.userDataDir = dirPath;
@@ -46,13 +55,17 @@ class LocalAuth extends BaseAuthStrategy {
46
55
 
47
56
  async logout() {
48
57
  if (this.userDataDir) {
49
- await fs.promises.rm(this.userDataDir, { recursive: true, force: true, maxRetries: this.rmMaxRetries })
58
+ await fs.promises
59
+ .rm(this.userDataDir, {
60
+ recursive: true,
61
+ force: true,
62
+ maxRetries: this.rmMaxRetries,
63
+ })
50
64
  .catch((e) => {
51
65
  throw new Error(e);
52
66
  });
53
67
  }
54
68
  }
55
-
56
69
  }
57
70
 
58
71
  module.exports = LocalAuth;
@@ -5,8 +5,7 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
5
5
  /**
6
6
  * No session restoring functionality
7
7
  * Will need to authenticate via QR code every time
8
- */
9
- class NoAuth extends BaseAuthStrategy { }
8
+ */
9
+ class NoAuth extends BaseAuthStrategy {}
10
10
 
11
-
12
- module.exports = NoAuth;
11
+ module.exports = NoAuth;
@@ -20,40 +20,64 @@ const BaseAuthStrategy = require('./BaseAuthStrategy');
20
20
  * @param {object} options - options
21
21
  * @param {object} options.store - Remote database store instance
22
22
  * @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
23
- * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
23
+ * @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
24
24
  * @param {number} options.backupSyncIntervalMs - Sets the time interval for periodic session backups. Accepts values starting from 60000ms {1 minute}
25
25
  * @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
26
26
  */
27
27
  class RemoteAuth extends BaseAuthStrategy {
28
- constructor({ clientId, dataPath, store, backupSyncIntervalMs, rmMaxRetries } = {}) {
29
- if (!fs && !unzipper && !archiver) throw new Error('Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag');
28
+ constructor({
29
+ clientId,
30
+ dataPath,
31
+ store,
32
+ backupSyncIntervalMs,
33
+ rmMaxRetries,
34
+ } = {}) {
35
+ if (!fs && !unzipper && !archiver)
36
+ throw new Error(
37
+ 'Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag',
38
+ );
30
39
  super();
31
40
 
32
41
  const idRegex = /^[-_\w]+$/i;
33
42
  if (clientId && !idRegex.test(clientId)) {
34
- throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
43
+ throw new Error(
44
+ 'Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.',
45
+ );
35
46
  }
36
47
  if (!backupSyncIntervalMs || backupSyncIntervalMs < 60000) {
37
- throw new Error('Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.');
48
+ throw new Error(
49
+ 'Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.',
50
+ );
38
51
  }
39
- if(!store) throw new Error('Remote database store is required.');
52
+ if (!store) throw new Error('Remote database store is required.');
40
53
 
41
54
  this.store = store;
42
55
  this.clientId = clientId;
43
56
  this.backupSyncIntervalMs = backupSyncIntervalMs;
44
57
  this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
45
58
  this.tempDir = `${this.dataPath}/wwebjs_temp_session_${this.clientId}`;
46
- this.requiredDirs = ['Default', 'IndexedDB', 'Local Storage']; /* => Required Files & Dirs in WWebJS to restore session */
59
+ this.requiredDirs = [
60
+ 'Default',
61
+ 'IndexedDB',
62
+ 'Local Storage',
63
+ ]; /* => Required Files & Dirs in WWebJS to restore session */
47
64
  this.rmMaxRetries = rmMaxRetries ?? 4;
48
65
  }
49
66
 
50
67
  async beforeBrowserInitialized() {
51
68
  const puppeteerOpts = this.client.options.puppeteer;
52
- const sessionDirName = this.clientId ? `RemoteAuth-${this.clientId}` : 'RemoteAuth';
69
+ const sessionDirName = this.clientId
70
+ ? `RemoteAuth-${this.clientId}`
71
+ : 'RemoteAuth';
53
72
  const dirPath = path.join(this.dataPath, sessionDirName);
54
73
 
55
- if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
56
- throw new Error('RemoteAuth is not compatible with a user-supplied userDataDir.');
74
+ if (
75
+ puppeteerOpts.userDataDir &&
76
+ puppeteerOpts.userDataDir !== dirPath
77
+ ) {
78
+ throw new Error(
79
+ 'RemoteAuth is not compatible with a user-supplied userDataDir.',
80
+ );
57
81
  }
58
82
 
59
83
  this.userDataDir = dirPath;
@@ -63,7 +87,7 @@ class RemoteAuth extends BaseAuthStrategy {
63
87
 
64
88
  this.client.options.puppeteer = {
65
89
  ...puppeteerOpts,
66
- userDataDir: dirPath
90
+ userDataDir: dirPath,
67
91
  };
68
92
  }
69
93
 
@@ -80,20 +104,26 @@ class RemoteAuth extends BaseAuthStrategy {
80
104
 
81
105
  let pathExists = await this.isValidPath(this.userDataDir);
82
106
  if (pathExists) {
83
- await fs.promises.rm(this.userDataDir, {
84
- recursive: true,
85
- force: true,
86
- maxRetries: this.rmMaxRetries,
87
- }).catch(() => {});
107
+ await fs.promises
108
+ .rm(this.userDataDir, {
109
+ recursive: true,
110
+ force: true,
111
+ maxRetries: this.rmMaxRetries,
112
+ })
113
+ .catch(() => {});
88
114
  }
89
115
  clearInterval(this.backupSync);
90
116
  }
91
117
 
92
118
  async afterAuthReady() {
93
- const sessionExists = await this.store.sessionExists({session: this.sessionName});
94
- if(!sessionExists) {
95
- await this.delay(60000); /* Initial delay sync required for session to be stable enough to recover */
96
- await this.storeRemoteSession({emit: true});
119
+ const sessionExists = await this.store.sessionExists({
120
+ session: this.sessionName,
121
+ });
122
+ if (!sessionExists) {
123
+ await this.delay(
124
+ 60000,
125
+ ); /* Initial delay sync required for session to be stable enough to recover */
126
+ await this.storeRemoteSession({ emit: true });
97
127
  }
98
128
  var self = this;
99
129
  this.backupSync = setInterval(async function () {
@@ -108,12 +138,15 @@ class RemoteAuth extends BaseAuthStrategy {
108
138
  let compressedSessionPath;
109
139
  try {
110
140
  compressedSessionPath = await this.compressSession();
111
- await this.store.save({ session: path.join(this.dataPath, this.sessionName) });
112
- if(options && options.emit) this.client.emit(Events.REMOTE_SESSION_SAVED);
141
+ await this.store.save({
142
+ session: this.sessionName,
143
+ });
144
+ if (options && options.emit)
145
+ this.client.emit(Events.REMOTE_SESSION_SAVED);
113
146
  } finally {
114
147
  const paths = [
115
148
  this.tempDir,
116
- ...(compressedSessionPath ? [compressedSessionPath] : [])
149
+ ...(compressedSessionPath ? [compressedSessionPath] : []),
117
150
  ];
118
151
  await Promise.allSettled(
119
152
  paths.map((p) =>
@@ -121,25 +154,35 @@ class RemoteAuth extends BaseAuthStrategy {
121
154
  recursive: true,
122
155
  force: true,
123
156
  maxRetries: this.rmMaxRetries,
124
- })
125
- )
157
+ }),
158
+ ),
126
159
  );
127
160
  }
128
161
  }
129
162
 
130
163
  async extractRemoteSession() {
131
164
  const pathExists = await this.isValidPath(this.userDataDir);
132
- const compressedSessionPath = path.join(this.dataPath, `${this.sessionName}.zip`);
133
- const sessionExists = await this.store.sessionExists({session: this.sessionName});
165
+ const compressedSessionPath = path.join(
166
+ this.dataPath,
167
+ `${this.sessionName}.zip`,
168
+ );
169
+ const sessionExists = await this.store.sessionExists({
170
+ session: this.sessionName,
171
+ });
134
172
  if (pathExists) {
135
- await fs.promises.rm(this.userDataDir, {
136
- recursive: true,
137
- force: true,
138
- maxRetries: this.rmMaxRetries,
139
- }).catch(() => {});
173
+ await fs.promises
174
+ .rm(this.userDataDir, {
175
+ recursive: true,
176
+ force: true,
177
+ maxRetries: this.rmMaxRetries,
178
+ })
179
+ .catch(() => {});
140
180
  }
141
181
  if (sessionExists) {
142
- await this.store.extract({session: this.sessionName, path: compressedSessionPath});
182
+ await this.store.extract({
183
+ session: this.sessionName,
184
+ path: compressedSessionPath,
185
+ });
143
186
  await this.unCompressSession(compressedSessionPath);
144
187
  } else {
145
188
  fs.mkdirSync(this.userDataDir, { recursive: true });
@@ -147,8 +190,11 @@ class RemoteAuth extends BaseAuthStrategy {
147
190
  }
148
191
 
149
192
  async deleteRemoteSession() {
150
- const sessionExists = await this.store.sessionExists({session: this.sessionName});
151
- if (sessionExists) await this.store.delete({session: this.sessionName});
193
+ const sessionExists = await this.store.sessionExists({
194
+ session: this.sessionName,
195
+ });
196
+ if (sessionExists)
197
+ await this.store.delete({ session: this.sessionName });
152
198
  }
153
199
 
154
200
  async compressSession() {
@@ -166,7 +212,7 @@ class RemoteAuth extends BaseAuthStrategy {
166
212
  out.once('close', resolve);
167
213
  out.once('error', reject);
168
214
  archive.once('error', reject);
169
-
215
+
170
216
  archive.pipe(out);
171
217
  archive.directory(this.tempDir, false);
172
218
  archive.finalize();
@@ -177,11 +223,14 @@ class RemoteAuth extends BaseAuthStrategy {
177
223
  async unCompressSession(compressedSessionPath) {
178
224
  var stream = fs.createReadStream(compressedSessionPath);
179
225
  await new Promise((resolve, reject) => {
180
- stream.pipe(unzipper.Extract({
181
- path: this.userDataDir,
182
- concurrency: 10
183
- }))
184
- .on('error', err => reject(err))
226
+ stream
227
+ .pipe(
228
+ unzipper.Extract({
229
+ path: this.userDataDir,
230
+ concurrency: 10,
231
+ }),
232
+ )
233
+ .on('error', (err) => reject(err))
185
234
  .on('finish', () => resolve());
186
235
  });
187
236
  await fs.promises.unlink(compressedSessionPath);
@@ -195,7 +244,7 @@ class RemoteAuth extends BaseAuthStrategy {
195
244
  await fs.promises.cp(src, dest, {
196
245
  recursive: true,
197
246
  force: true,
198
- errorOnExist: false
247
+ errorOnExist: false,
199
248
  });
200
249
  }
201
250
  }
@@ -211,7 +260,7 @@ class RemoteAuth extends BaseAuthStrategy {
211
260
  }
212
261
 
213
262
  async delay(ms) {
214
- return new Promise(resolve => setTimeout(resolve, ms));
263
+ return new Promise((resolve) => setTimeout(resolve, ms));
215
264
  }
216
265
  }
217
266
 
@@ -9,7 +9,7 @@ class ChatFactory {
9
9
  if (data.isGroup) {
10
10
  return new GroupChat(client, data);
11
11
  }
12
-
12
+
13
13
  if (data.isChannel) {
14
14
  return new Channel(client, data);
15
15
  }
@@ -5,7 +5,7 @@ const BusinessContact = require('../structures/BusinessContact');
5
5
 
6
6
  class ContactFactory {
7
7
  static create(client, data) {
8
- if(data.isBusiness) {
8
+ if (data.isBusiness) {
9
9
  return new BusinessContact(client, data);
10
10
  }
11
11
 
@@ -13,4 +13,4 @@ class ContactFactory {
13
13
  }
14
14
  }
15
15
 
16
- module.exports = ContactFactory;
16
+ module.exports = ContactFactory;
@@ -15,8 +15,10 @@ class Base {
15
15
  _clone() {
16
16
  return Object.assign(Object.create(this), this);
17
17
  }
18
-
19
- _patch(data) { return data; }
18
+
19
+ _patch(data) {
20
+ return data;
21
+ }
20
22
  }
21
23
 
22
- module.exports = Base;
24
+ module.exports = Base;
@@ -43,7 +43,7 @@ class Broadcast extends Base {
43
43
  * Messages statuses
44
44
  * @type {Message[]}
45
45
  */
46
- this.msgs = data.msgs?.map(msg => new Message(this.client, msg));
46
+ this.msgs = data.msgs?.map((msg) => new Message(this.client, msg));
47
47
 
48
48
  return super._patch(data);
49
49
  }
@@ -63,7 +63,6 @@ class Broadcast extends Base {
63
63
  getContact() {
64
64
  return this.client.getContactById(this.id._serialized);
65
65
  }
66
-
67
66
  }
68
67
 
69
68
  module.exports = Broadcast;
@@ -15,7 +15,6 @@ class BusinessContact extends Contact {
15
15
 
16
16
  return super._patch(data);
17
17
  }
18
-
19
18
  }
20
19
 
21
- module.exports = BusinessContact;
20
+ module.exports = BusinessContact;
@@ -39,7 +39,7 @@ class Buttons {
39
39
  * @type {string}
40
40
  */
41
41
  this.title = title;
42
-
42
+
43
43
  /**
44
44
  * footer of message
45
45
  * @type {string}
@@ -49,7 +49,7 @@ class Buttons {
49
49
  if (body instanceof MessageMedia) {
50
50
  this.type = 'media';
51
51
  this.title = '';
52
- }else{
52
+ } else {
53
53
  this.type = 'chat';
54
54
  }
55
55
 
@@ -58,25 +58,29 @@ class Buttons {
58
58
  * @type {FormattedButtonSpec[]}
59
59
  */
60
60
  this.buttons = this._format(buttons);
61
- if(!this.buttons.length){ throw '[BT01] No buttons';}
62
-
61
+ if (!this.buttons.length) {
62
+ throw '[BT01] No buttons';
63
+ }
63
64
  }
64
65
 
65
66
  /**
66
67
  * Creates button array from simple array
67
68
  * @param {ButtonSpec[]} buttons
68
69
  * @returns {FormattedButtonSpec[]}
69
- * @example
70
+ * @example
70
71
  * Input: [{id:'customId',body:'button1'},{body:'button2'},{body:'button3'},{body:'button4'}]
71
72
  * Returns: [{ buttonId:'customId',buttonText:{'displayText':'button1'},type: 1 },{buttonId:'n3XKsL',buttonText:{'displayText':'button2'},type:1},{buttonId:'NDJk0a',buttonText:{'displayText':'button3'},type:1}]
72
73
  */
73
- _format(buttons){
74
- buttons = buttons.slice(0,3); // phone users can only see 3 buttons, so lets limit this
74
+ _format(buttons) {
75
+ buttons = buttons.slice(0, 3); // phone users can only see 3 buttons, so lets limit this
75
76
  return buttons.map((btn) => {
76
- return {'buttonId':btn.id ? String(btn.id) : Util.generateHash(6),'buttonText':{'displayText':btn.body},'type':1};
77
+ return {
78
+ buttonId: btn.id ? String(btn.id) : Util.generateHash(6),
79
+ buttonText: { displayText: btn.body },
80
+ type: 1,
81
+ };
77
82
  });
78
83
  }
79
-
80
84
  }
81
85
 
82
- module.exports = Buttons;
86
+ module.exports = Buttons;
@@ -59,18 +59,22 @@ class Call extends Base {
59
59
  * @type {object}
60
60
  */
61
61
  this.participants = data.participants;
62
-
62
+
63
63
  return super._patch(data);
64
64
  }
65
65
 
66
66
  /**
67
67
  * Reject the call
68
- */
68
+ */
69
69
  async reject() {
70
- return this.client.pupPage.evaluate((peerJid, id) => {
71
- return window.WWebJS.rejectCall(peerJid, id);
72
- }, this.from, this.id);
70
+ return this.client.pupPage.evaluate(
71
+ (peerJid, id) => {
72
+ return window.WWebJS.rejectCall(peerJid, id);
73
+ },
74
+ this.from,
75
+ this.id,
76
+ );
73
77
  }
74
78
  }
75
79
 
76
- module.exports = Call;
80
+ module.exports = Call;