@pney/whatsapp-web 1.34.6 → 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.
- package/.env.example +0 -1
- package/.gitattributes +4 -0
- package/.husky/commit-msg +4 -0
- package/.husky/pre-commit +1 -0
- package/.lintstagedrc.json +6 -0
- package/.prettierignore +8 -0
- package/.prettierrc.json +10 -0
- package/README.md +83 -80
- package/commitlint.config.js +29 -0
- package/eslint.config.mjs +67 -0
- package/example.js +151 -71
- package/index.d.ts +982 -734
- package/index.js +4 -4
- package/package.json +3 -3
- package/shell.js +4 -4
- package/src/Client.js +1860 -920
- package/src/authStrategies/BaseAuthStrategy.js +4 -2
- package/src/authStrategies/LocalAuth.js +25 -12
- package/src/authStrategies/NoAuth.js +3 -4
- package/src/authStrategies/RemoteAuth.js +92 -43
- package/src/factories/ChatFactory.js +1 -1
- package/src/factories/ContactFactory.js +2 -2
- package/src/structures/Base.js +5 -3
- package/src/structures/Broadcast.js +1 -2
- package/src/structures/BusinessContact.js +1 -2
- package/src/structures/Buttons.js +14 -10
- package/src/structures/Call.js +10 -6
- package/src/structures/Channel.js +171 -91
- package/src/structures/Chat.js +57 -41
- package/src/structures/ClientInfo.js +1 -1
- package/src/structures/Contact.js +37 -16
- package/src/structures/GroupChat.js +425 -228
- package/src/structures/GroupNotification.js +21 -12
- package/src/structures/Label.js +6 -6
- package/src/structures/List.js +22 -14
- package/src/structures/Location.js +5 -4
- package/src/structures/Message.js +412 -168
- package/src/structures/MessageMedia.js +31 -18
- package/src/structures/Order.js +4 -4
- package/src/structures/Payment.js +6 -3
- package/src/structures/Poll.js +2 -2
- package/src/structures/PollVote.js +9 -6
- package/src/structures/PrivateChat.js +2 -4
- package/src/structures/PrivateContact.js +2 -4
- package/src/structures/Product.js +1 -1
- package/src/structures/ProductMetadata.js +1 -2
- package/src/structures/Reaction.js +2 -4
- package/src/structures/ScheduledEvent.js +22 -10
- package/src/util/Constants.js +8 -6
- package/src/util/Injected/AuthStore/AuthStore.js +7 -3
- package/src/util/Injected/Utils.js +753 -345
- package/src/util/InterfaceController.js +72 -25
- package/src/util/Puppeteer.js +1 -1
- package/src/util/Util.js +28 -15
- package/src/webCache/LocalWebCache.js +7 -5
- package/src/webCache/RemoteWebCache.js +10 -4
- package/src/webCache/WebCache.js +8 -5
- package/src/webCache/WebCacheFactory.js +9 -9
- package/CODE_OF_CONDUCT.md +0 -133
package/src/Client.js
CHANGED
|
@@ -5,15 +5,37 @@ const puppeteer = require('puppeteer');
|
|
|
5
5
|
|
|
6
6
|
const Util = require('./util/Util');
|
|
7
7
|
const InterfaceController = require('./util/InterfaceController');
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
WhatsWebURL,
|
|
10
|
+
DefaultOptions,
|
|
11
|
+
Events,
|
|
12
|
+
WAState,
|
|
13
|
+
MessageTypes,
|
|
14
|
+
} = require('./util/Constants');
|
|
9
15
|
const { ExposeAuthStore } = require('./util/Injected/AuthStore/AuthStore');
|
|
10
16
|
const { LoadUtils } = require('./util/Injected/Utils');
|
|
11
17
|
const ChatFactory = require('./factories/ChatFactory');
|
|
12
18
|
const ContactFactory = require('./factories/ContactFactory');
|
|
13
19
|
const WebCacheFactory = require('./webCache/WebCacheFactory');
|
|
14
|
-
const {
|
|
20
|
+
const {
|
|
21
|
+
ClientInfo,
|
|
22
|
+
Message,
|
|
23
|
+
MessageMedia,
|
|
24
|
+
Contact,
|
|
25
|
+
Location,
|
|
26
|
+
Poll,
|
|
27
|
+
PollVote,
|
|
28
|
+
GroupNotification,
|
|
29
|
+
Label,
|
|
30
|
+
Call,
|
|
31
|
+
Buttons,
|
|
32
|
+
List,
|
|
33
|
+
Reaction,
|
|
34
|
+
Broadcast,
|
|
35
|
+
ScheduledEvent,
|
|
36
|
+
} = require('./structures');
|
|
15
37
|
const NoAuth = require('./authStrategies/NoAuth');
|
|
16
|
-
const {exposeFunctionIfAbsent} = require('./util/Puppeteer');
|
|
38
|
+
const { exposeFunctionIfAbsent } = require('./util/Puppeteer');
|
|
17
39
|
|
|
18
40
|
/**
|
|
19
41
|
* Starting point for interacting with the WhatsApp Web API
|
|
@@ -29,12 +51,12 @@ const {exposeFunctionIfAbsent} = require('./util/Puppeteer');
|
|
|
29
51
|
* @param {number} options.takeoverOnConflict - If another whatsapp web session is detected (another browser), take over the session in the current browser
|
|
30
52
|
* @param {number} options.takeoverTimeoutMs - How much time to wait before taking over the session
|
|
31
53
|
* @param {string} options.userAgent - User agent to use in puppeteer
|
|
32
|
-
* @param {string} options.ffmpegPath - Ffmpeg path to use when formatting videos to webp while sending stickers
|
|
54
|
+
* @param {string} options.ffmpegPath - Ffmpeg path to use when formatting videos to webp while sending stickers
|
|
33
55
|
* @param {boolean} options.bypassCSP - Sets bypassing of page's Content-Security-Policy.
|
|
34
56
|
* @param {string} options.deviceName - Sets the device name of a current linked device., i.e.: 'TEST'.
|
|
35
57
|
* @param {string} options.browserName - Sets the browser name of a current linked device, i.e.: 'Firefox'.
|
|
36
58
|
* @param {object} options.proxyAuthentication - Proxy Authentication object.
|
|
37
|
-
*
|
|
59
|
+
*
|
|
38
60
|
* @fires Client#qr
|
|
39
61
|
* @fires Client#authenticated
|
|
40
62
|
* @fires Client#auth_failure
|
|
@@ -62,8 +84,8 @@ class Client extends EventEmitter {
|
|
|
62
84
|
super();
|
|
63
85
|
|
|
64
86
|
this.options = Util.mergeDefault(DefaultOptions, options);
|
|
65
|
-
|
|
66
|
-
if(!this.options.authStrategy) {
|
|
87
|
+
|
|
88
|
+
if (!this.options.authStrategy) {
|
|
67
89
|
this.authStrategy = new NoAuth();
|
|
68
90
|
} else {
|
|
69
91
|
this.authStrategy = this.options.authStrategy;
|
|
@@ -85,26 +107,37 @@ class Client extends EventEmitter {
|
|
|
85
107
|
|
|
86
108
|
Util.setFfmpegPath(this.options.ffmpegPath);
|
|
87
109
|
}
|
|
110
|
+
|
|
88
111
|
/**
|
|
89
112
|
* Injection logic
|
|
90
113
|
* Private function
|
|
91
114
|
*/
|
|
92
115
|
async inject() {
|
|
93
|
-
if(
|
|
116
|
+
if (
|
|
117
|
+
this.options.authTimeoutMs === undefined ||
|
|
118
|
+
this.options.authTimeoutMs == 0
|
|
119
|
+
) {
|
|
94
120
|
this.options.authTimeoutMs = 30000;
|
|
95
121
|
}
|
|
96
122
|
let start = Date.now();
|
|
97
123
|
let timeout = this.options.authTimeoutMs;
|
|
98
124
|
let res = false;
|
|
99
|
-
while(start >
|
|
100
|
-
res = await this.pupPage.evaluate(
|
|
101
|
-
|
|
102
|
-
|
|
125
|
+
while (start > Date.now() - timeout) {
|
|
126
|
+
res = await this.pupPage.evaluate(
|
|
127
|
+
'window.Debug?.VERSION != undefined',
|
|
128
|
+
);
|
|
129
|
+
if (res) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
103
133
|
}
|
|
104
|
-
if(!res){
|
|
134
|
+
if (!res) {
|
|
105
135
|
throw 'auth timeout';
|
|
106
|
-
}
|
|
107
|
-
await this.setDeviceName(
|
|
136
|
+
}
|
|
137
|
+
await this.setDeviceName(
|
|
138
|
+
this.options.deviceName,
|
|
139
|
+
this.options.browserName,
|
|
140
|
+
);
|
|
108
141
|
const pairWithPhoneNumber = this.options.pairWithPhoneNumber;
|
|
109
142
|
const version = await this.getWWebVersion();
|
|
110
143
|
|
|
@@ -113,25 +146,44 @@ class Client extends EventEmitter {
|
|
|
113
146
|
const needAuthentication = await this.pupPage.evaluate(async () => {
|
|
114
147
|
let state = window.require('WAWebSocketModel').Socket.state;
|
|
115
148
|
|
|
116
|
-
if (
|
|
149
|
+
if (
|
|
150
|
+
state === 'OPENING' ||
|
|
151
|
+
state === 'UNLAUNCHED' ||
|
|
152
|
+
state === 'PAIRING'
|
|
153
|
+
) {
|
|
117
154
|
// wait till state changes
|
|
118
|
-
await new Promise(r => {
|
|
119
|
-
window
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
155
|
+
await new Promise((r) => {
|
|
156
|
+
window
|
|
157
|
+
.require('WAWebSocketModel')
|
|
158
|
+
.Socket.on(
|
|
159
|
+
'change:state',
|
|
160
|
+
function waitTillInit(_AppState, state) {
|
|
161
|
+
if (
|
|
162
|
+
state !== 'OPENING' &&
|
|
163
|
+
state !== 'UNLAUNCHED' &&
|
|
164
|
+
state !== 'PAIRING'
|
|
165
|
+
) {
|
|
166
|
+
window
|
|
167
|
+
.require('WAWebSocketModel')
|
|
168
|
+
.Socket.off(
|
|
169
|
+
'change:state',
|
|
170
|
+
waitTillInit,
|
|
171
|
+
);
|
|
172
|
+
r();
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
);
|
|
176
|
+
});
|
|
126
177
|
}
|
|
127
178
|
state = window.require('WAWebSocketModel').Socket.state;
|
|
128
179
|
return state == 'UNPAIRED' || state == 'UNPAIRED_IDLE';
|
|
129
180
|
});
|
|
130
181
|
|
|
131
182
|
if (needAuthentication) {
|
|
132
|
-
const { failed, failureEventPayload, restart } =
|
|
183
|
+
const { failed, failureEventPayload, restart } =
|
|
184
|
+
await this.authStrategy.onAuthenticationNeeded();
|
|
133
185
|
|
|
134
|
-
if(failed) {
|
|
186
|
+
if (failed) {
|
|
135
187
|
/**
|
|
136
188
|
* Emitted when there has been an error while trying to restore an existing session
|
|
137
189
|
* @event Client#auth_failure
|
|
@@ -148,129 +200,219 @@ class Client extends EventEmitter {
|
|
|
148
200
|
|
|
149
201
|
// Register qr/code events
|
|
150
202
|
if (pairWithPhoneNumber.phoneNumber) {
|
|
151
|
-
await exposeFunctionIfAbsent(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
203
|
+
await exposeFunctionIfAbsent(
|
|
204
|
+
this.pupPage,
|
|
205
|
+
'onCodeReceivedEvent',
|
|
206
|
+
async (code) => {
|
|
207
|
+
/**
|
|
208
|
+
* Emitted when a pairing code is received
|
|
209
|
+
* @event Client#code
|
|
210
|
+
* @param {string} code Code
|
|
211
|
+
* @returns {string} Code that was just received
|
|
212
|
+
*/
|
|
213
|
+
this.emit(Events.CODE_RECEIVED, code);
|
|
214
|
+
return code;
|
|
215
|
+
},
|
|
216
|
+
);
|
|
217
|
+
this.requestPairingCode(
|
|
218
|
+
pairWithPhoneNumber.phoneNumber,
|
|
219
|
+
pairWithPhoneNumber.showNotification,
|
|
220
|
+
pairWithPhoneNumber.intervalMs,
|
|
221
|
+
);
|
|
162
222
|
} else {
|
|
163
223
|
let qrRetries = 0;
|
|
164
|
-
await exposeFunctionIfAbsent(
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
224
|
+
await exposeFunctionIfAbsent(
|
|
225
|
+
this.pupPage,
|
|
226
|
+
'onQRChangedEvent',
|
|
227
|
+
async (qr) => {
|
|
228
|
+
/**
|
|
229
|
+
* Emitted when a QR code is received
|
|
230
|
+
* @event Client#qr
|
|
231
|
+
* @param {string} qr QR Code
|
|
232
|
+
*/
|
|
233
|
+
this.emit(Events.QR_RECEIVED, qr);
|
|
234
|
+
if (this.options.qrMaxRetries > 0) {
|
|
235
|
+
qrRetries++;
|
|
236
|
+
if (qrRetries > this.options.qrMaxRetries) {
|
|
237
|
+
this.emit(
|
|
238
|
+
Events.DISCONNECTED,
|
|
239
|
+
'Max qrcode retries reached',
|
|
240
|
+
);
|
|
241
|
+
await this.destroy();
|
|
242
|
+
}
|
|
176
243
|
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
|
|
244
|
+
},
|
|
245
|
+
);
|
|
180
246
|
|
|
181
247
|
await this.pupPage.evaluate(async () => {
|
|
182
|
-
const registrationInfo =
|
|
183
|
-
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
248
|
+
const registrationInfo =
|
|
249
|
+
await window.AuthStore.RegistrationUtils.waSignalStore.getRegistrationInfo();
|
|
250
|
+
const noiseKeyPair =
|
|
251
|
+
await window.AuthStore.RegistrationUtils.waNoiseInfo.get();
|
|
252
|
+
const staticKeyB64 = window.AuthStore.Base64Tools.encodeB64(
|
|
253
|
+
noiseKeyPair.staticKeyPair.pubKey,
|
|
254
|
+
);
|
|
255
|
+
const identityKeyB64 =
|
|
256
|
+
window.AuthStore.Base64Tools.encodeB64(
|
|
257
|
+
registrationInfo.identityKeyPair.pubKey,
|
|
258
|
+
);
|
|
259
|
+
const platform =
|
|
260
|
+
window.AuthStore.RegistrationUtils.DEVICE_PLATFORM;
|
|
261
|
+
const getQR = (ref) =>
|
|
262
|
+
ref +
|
|
263
|
+
',' +
|
|
264
|
+
staticKeyB64 +
|
|
265
|
+
',' +
|
|
266
|
+
identityKeyB64 +
|
|
267
|
+
',' +
|
|
268
|
+
window
|
|
269
|
+
.require('WAWebUserPrefsMultiDevice')
|
|
270
|
+
.getADVSecretKey() +
|
|
271
|
+
',' +
|
|
272
|
+
platform;
|
|
190
273
|
window.onQRChangedEvent(getQR(window.AuthStore.Conn.ref)); // initial qr
|
|
191
|
-
window.AuthStore.Conn.on('change:ref', (_, ref) => {
|
|
274
|
+
window.AuthStore.Conn.on('change:ref', (_, ref) => {
|
|
275
|
+
window.onQRChangedEvent(getQR(ref));
|
|
276
|
+
}); // future QR changes
|
|
192
277
|
});
|
|
193
278
|
}
|
|
194
279
|
}
|
|
195
280
|
|
|
196
|
-
await exposeFunctionIfAbsent(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
281
|
+
await exposeFunctionIfAbsent(
|
|
282
|
+
this.pupPage,
|
|
283
|
+
'onAuthAppStateChangedEvent',
|
|
284
|
+
async (state) => {
|
|
285
|
+
if (
|
|
286
|
+
state == 'UNPAIRED_IDLE' &&
|
|
287
|
+
!pairWithPhoneNumber.phoneNumber
|
|
288
|
+
) {
|
|
289
|
+
// refresh qr code
|
|
290
|
+
window.require('WAWebCmd').Cmd.refreshQR();
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
await exposeFunctionIfAbsent(
|
|
296
|
+
this.pupPage,
|
|
297
|
+
'onAppStateHasSyncedEvent',
|
|
298
|
+
async () => {
|
|
299
|
+
const authEventPayload =
|
|
300
|
+
await this.authStrategy.getAuthEventPayload();
|
|
301
|
+
/**
|
|
206
302
|
* Emitted when authentication is successful
|
|
207
303
|
* @event Client#authenticated
|
|
208
304
|
*/
|
|
209
|
-
|
|
305
|
+
this.emit(Events.AUTHENTICATED, authEventPayload);
|
|
210
306
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
307
|
+
const injected = await this.pupPage.evaluate(async () => {
|
|
308
|
+
return typeof window.WWebJS !== 'undefined';
|
|
309
|
+
});
|
|
214
310
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
311
|
+
if (!injected) {
|
|
312
|
+
if (
|
|
313
|
+
this.options.webVersionCache.type === 'local' &&
|
|
314
|
+
this.currentIndexHtml
|
|
315
|
+
) {
|
|
316
|
+
const { type: webCacheType, ...webCacheOptions } =
|
|
317
|
+
this.options.webVersionCache;
|
|
318
|
+
const webCache = WebCacheFactory.createWebCache(
|
|
319
|
+
webCacheType,
|
|
320
|
+
webCacheOptions,
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
await webCache.persist(this.currentIndexHtml, version);
|
|
324
|
+
}
|
|
222
325
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
326
|
+
// Load util functions (serializers, helper functions)
|
|
327
|
+
await this.pupPage.evaluate(LoadUtils);
|
|
328
|
+
|
|
329
|
+
let start = Date.now();
|
|
330
|
+
let res = false;
|
|
331
|
+
while (start > Date.now() - 30000) {
|
|
332
|
+
// Check window.WWebJS Injection
|
|
333
|
+
res = await this.pupPage.evaluate(
|
|
334
|
+
'window.WWebJS != undefined',
|
|
335
|
+
);
|
|
336
|
+
if (res) {
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
340
|
+
}
|
|
341
|
+
if (!res) {
|
|
342
|
+
throw 'ready timeout';
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
239
346
|
* Current connection information
|
|
240
347
|
* @type {ClientInfo}
|
|
241
348
|
*/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
349
|
+
this.info = new ClientInfo(
|
|
350
|
+
this,
|
|
351
|
+
await this.pupPage.evaluate(() => {
|
|
352
|
+
return {
|
|
353
|
+
...window
|
|
354
|
+
.require('WAWebConnModel')
|
|
355
|
+
.Conn.serialize(),
|
|
356
|
+
wid:
|
|
357
|
+
window
|
|
358
|
+
.require('WAWebUserPrefsMeUser')
|
|
359
|
+
.getMaybeMePnUser() ||
|
|
360
|
+
window
|
|
361
|
+
.require('WAWebUserPrefsMeUser')
|
|
362
|
+
.getMaybeMeLidUser(),
|
|
363
|
+
};
|
|
364
|
+
}),
|
|
365
|
+
);
|
|
245
366
|
|
|
246
|
-
|
|
367
|
+
this.interface = new InterfaceController(this);
|
|
247
368
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
369
|
+
await this.attachEventListeners();
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
251
372
|
* Emitted when the client has initialized and is ready to receive messages.
|
|
252
373
|
* @event Client#ready
|
|
253
374
|
*/
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
375
|
+
this.emit(Events.READY);
|
|
376
|
+
this.authStrategy.afterAuthReady();
|
|
377
|
+
},
|
|
378
|
+
);
|
|
257
379
|
let lastPercent = null;
|
|
258
|
-
await exposeFunctionIfAbsent(
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
380
|
+
await exposeFunctionIfAbsent(
|
|
381
|
+
this.pupPage,
|
|
382
|
+
'onOfflineProgressUpdateEvent',
|
|
383
|
+
async (percent) => {
|
|
384
|
+
if (lastPercent !== percent) {
|
|
385
|
+
lastPercent = percent;
|
|
386
|
+
this.emit(Events.LOADING_SCREEN, percent, 'WhatsApp'); // Message is hardcoded as "WhatsApp" for now
|
|
387
|
+
}
|
|
388
|
+
},
|
|
389
|
+
);
|
|
390
|
+
await exposeFunctionIfAbsent(
|
|
391
|
+
this.pupPage,
|
|
392
|
+
'onLogoutEvent',
|
|
393
|
+
async () => {
|
|
394
|
+
this.lastLoggedOut = true;
|
|
395
|
+
await this.pupPage
|
|
396
|
+
.waitForNavigation({ waitUntil: 'load', timeout: 5000 })
|
|
397
|
+
.catch((_) => _);
|
|
398
|
+
},
|
|
399
|
+
);
|
|
268
400
|
await this.pupPage.evaluate(() => {
|
|
269
|
-
window
|
|
270
|
-
|
|
401
|
+
window
|
|
402
|
+
.require('WAWebSocketModel')
|
|
403
|
+
.Socket.on('change:state', (_AppState, state) => {
|
|
404
|
+
window.onAuthAppStateChangedEvent(state);
|
|
405
|
+
});
|
|
406
|
+
window
|
|
407
|
+
.require('WAWebSocketModel')
|
|
408
|
+
.Socket.on('change:hasSynced', () => {
|
|
409
|
+
window.onAppStateHasSyncedEvent();
|
|
410
|
+
});
|
|
271
411
|
const Cmd = window.require('WAWebCmd').Cmd;
|
|
272
412
|
Cmd.on('offline_progress_update_from_bridge', () => {
|
|
273
|
-
window.onOfflineProgressUpdateEvent(
|
|
413
|
+
window.onOfflineProgressUpdateEvent(
|
|
414
|
+
window.AuthStore.OfflineMessageHandler.getOfflineDeliveryProgress(),
|
|
415
|
+
);
|
|
274
416
|
});
|
|
275
417
|
Cmd.on('logout', async () => {
|
|
276
418
|
await window.onLogoutEvent();
|
|
@@ -285,12 +427,10 @@ class Client extends EventEmitter {
|
|
|
285
427
|
* Sets up events and requirements, kicks off authentication request
|
|
286
428
|
*/
|
|
287
429
|
async initialize() {
|
|
288
|
-
|
|
289
|
-
let
|
|
290
|
-
/**
|
|
430
|
+
let /**
|
|
291
431
|
* @type {puppeteer.Browser}
|
|
292
432
|
*/
|
|
293
|
-
browser,
|
|
433
|
+
browser,
|
|
294
434
|
/**
|
|
295
435
|
* @type {puppeteer.Page}
|
|
296
436
|
*/
|
|
@@ -302,25 +442,34 @@ class Client extends EventEmitter {
|
|
|
302
442
|
await this.authStrategy.beforeBrowserInitialized();
|
|
303
443
|
|
|
304
444
|
const puppeteerOpts = this.options.puppeteer;
|
|
305
|
-
if (
|
|
445
|
+
if (
|
|
446
|
+
puppeteerOpts &&
|
|
447
|
+
(puppeteerOpts.browserWSEndpoint || puppeteerOpts.browserURL)
|
|
448
|
+
) {
|
|
306
449
|
browser = await puppeteer.connect(puppeteerOpts);
|
|
307
450
|
page = await browser.newPage();
|
|
308
451
|
} else {
|
|
309
452
|
const browserArgs = [...(puppeteerOpts.args || [])];
|
|
310
|
-
if
|
|
453
|
+
if (
|
|
454
|
+
this.options.userAgent !== false &&
|
|
455
|
+
!browserArgs.find((arg) => arg.includes('--user-agent'))
|
|
456
|
+
) {
|
|
311
457
|
browserArgs.push(`--user-agent=${this.options.userAgent}`);
|
|
312
458
|
}
|
|
313
459
|
// navigator.webdriver fix
|
|
314
460
|
browserArgs.push('--disable-blink-features=AutomationControlled');
|
|
315
461
|
|
|
316
|
-
browser = await puppeteer.launch({
|
|
462
|
+
browser = await puppeteer.launch({
|
|
463
|
+
...puppeteerOpts,
|
|
464
|
+
args: browserArgs,
|
|
465
|
+
});
|
|
317
466
|
page = (await browser.pages())[0];
|
|
318
467
|
}
|
|
319
468
|
|
|
320
469
|
if (this.options.proxyAuthentication !== undefined) {
|
|
321
470
|
await page.authenticate(this.options.proxyAuthentication);
|
|
322
471
|
}
|
|
323
|
-
if(this.options.userAgent !== false) {
|
|
472
|
+
if (this.options.userAgent !== false) {
|
|
324
473
|
await page.setUserAgent(this.options.userAgent);
|
|
325
474
|
}
|
|
326
475
|
if (this.options.bypassCSP) await page.setBypassCSP(true);
|
|
@@ -330,21 +479,21 @@ class Client extends EventEmitter {
|
|
|
330
479
|
|
|
331
480
|
await this.authStrategy.afterBrowserInitialized();
|
|
332
481
|
await this.initWebVersionCache();
|
|
333
|
-
|
|
482
|
+
|
|
334
483
|
if (this.options.evalOnNewDoc !== undefined) {
|
|
335
484
|
await page.evaluateOnNewDocument(this.options.evalOnNewDoc);
|
|
336
485
|
}
|
|
337
|
-
|
|
486
|
+
|
|
338
487
|
await page.goto(WhatsWebURL, {
|
|
339
488
|
waitUntil: 'load',
|
|
340
489
|
timeout: 0,
|
|
341
|
-
referer: 'https://whatsapp.com/'
|
|
490
|
+
referer: 'https://whatsapp.com/',
|
|
342
491
|
});
|
|
343
492
|
|
|
344
493
|
await this.inject();
|
|
345
494
|
|
|
346
495
|
this.pupPage.on('framenavigated', async (frame) => {
|
|
347
|
-
if(frame.url().includes('post_logout=1') || this.lastLoggedOut) {
|
|
496
|
+
if (frame.url().includes('post_logout=1') || this.lastLoggedOut) {
|
|
348
497
|
this.emit(Events.DISCONNECTED, 'LOGOUT');
|
|
349
498
|
await this.authStrategy.logout();
|
|
350
499
|
await this.authStrategy.beforeBrowserInitialized();
|
|
@@ -362,29 +511,70 @@ class Client extends EventEmitter {
|
|
|
362
511
|
* @param {number} [intervalMs = 180000] - The interval in milliseconds on how frequent to generate pairing code (WhatsApp default to 3 minutes)
|
|
363
512
|
* @returns {Promise<string>} - Returns a pairing code in format "ABCDEFGH"
|
|
364
513
|
*/
|
|
365
|
-
async requestPairingCode(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
514
|
+
async requestPairingCode(
|
|
515
|
+
phoneNumber,
|
|
516
|
+
showNotification = true,
|
|
517
|
+
intervalMs = 180000,
|
|
518
|
+
) {
|
|
519
|
+
await exposeFunctionIfAbsent(
|
|
520
|
+
this.pupPage,
|
|
521
|
+
'onCodeReceivedEvent',
|
|
522
|
+
async (code) => {
|
|
523
|
+
this.emit(Events.CODE_RECEIVED, code);
|
|
524
|
+
return code;
|
|
525
|
+
},
|
|
526
|
+
);
|
|
527
|
+
return await this.pupPage.evaluate(
|
|
528
|
+
async (phoneNumber, showNotification, intervalMs) => {
|
|
529
|
+
const getCode = async () => {
|
|
530
|
+
while (!window.AuthStore.PairingCodeLinkUtils) {
|
|
531
|
+
await new Promise((resolve) =>
|
|
532
|
+
setTimeout(resolve, 250),
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
window.AuthStore.PairingCodeLinkUtils.setPairingType(
|
|
536
|
+
'ALT_DEVICE_LINKING',
|
|
537
|
+
);
|
|
538
|
+
await window.AuthStore.PairingCodeLinkUtils.initializeAltDeviceLinking();
|
|
539
|
+
return window.AuthStore.PairingCodeLinkUtils.startAltLinkingFlow(
|
|
540
|
+
phoneNumber,
|
|
541
|
+
showNotification,
|
|
542
|
+
);
|
|
543
|
+
};
|
|
544
|
+
if (window.codeInterval) {
|
|
545
|
+
clearInterval(window.codeInterval); // remove existing interval
|
|
370
546
|
}
|
|
371
|
-
window.
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
547
|
+
window.codeInterval = setInterval(async () => {
|
|
548
|
+
const state =
|
|
549
|
+
window.require('WAWebSocketModel').Socket.state;
|
|
550
|
+
if (state != 'UNPAIRED' && state != 'UNPAIRED_IDLE') {
|
|
551
|
+
clearInterval(window.codeInterval);
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
window.onCodeReceivedEvent(await getCode());
|
|
555
|
+
}, intervalMs);
|
|
556
|
+
return window.onCodeReceivedEvent(await getCode());
|
|
557
|
+
},
|
|
558
|
+
phoneNumber,
|
|
559
|
+
showNotification,
|
|
560
|
+
intervalMs,
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Cancels an active pairing code session and returns to QR code mode
|
|
566
|
+
*/
|
|
567
|
+
async cancelPairingCode() {
|
|
568
|
+
await this.pupPage.evaluate(async () => {
|
|
375
569
|
if (window.codeInterval) {
|
|
376
|
-
clearInterval(window.codeInterval);
|
|
570
|
+
clearInterval(window.codeInterval);
|
|
571
|
+
window.codeInterval = undefined;
|
|
377
572
|
}
|
|
378
|
-
window.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
}
|
|
384
|
-
window.onCodeReceivedEvent(await getCode());
|
|
385
|
-
}, intervalMs);
|
|
386
|
-
return window.onCodeReceivedEvent(await getCode());
|
|
387
|
-
}, phoneNumber, showNotification, intervalMs);
|
|
573
|
+
window.require('WAWebLaunchSocketUtils').refreshQR();
|
|
574
|
+
await window
|
|
575
|
+
.require('WAWebAltDeviceLinkingApi')
|
|
576
|
+
.initializeQRLinking();
|
|
577
|
+
});
|
|
388
578
|
}
|
|
389
579
|
|
|
390
580
|
/**
|
|
@@ -393,32 +583,45 @@ class Client extends EventEmitter {
|
|
|
393
583
|
* @property {boolean} reinject is this a reinject?
|
|
394
584
|
*/
|
|
395
585
|
async attachEventListeners() {
|
|
396
|
-
await exposeFunctionIfAbsent(
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
586
|
+
await exposeFunctionIfAbsent(
|
|
587
|
+
this.pupPage,
|
|
588
|
+
'onAddMessageEvent',
|
|
589
|
+
(msg) => {
|
|
590
|
+
if (msg.type === 'gp2') {
|
|
591
|
+
const notification = new GroupNotification(this, msg);
|
|
592
|
+
if (
|
|
593
|
+
['add', 'invite', 'linked_group_join'].includes(
|
|
594
|
+
msg.subtype,
|
|
595
|
+
)
|
|
596
|
+
) {
|
|
597
|
+
/**
|
|
401
598
|
* Emitted when a user joins the chat via invite link or is added by an admin.
|
|
402
599
|
* @event Client#group_join
|
|
403
600
|
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
404
601
|
*/
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
602
|
+
this.emit(Events.GROUP_JOIN, notification);
|
|
603
|
+
} else if (
|
|
604
|
+
msg.subtype === 'remove' ||
|
|
605
|
+
msg.subtype === 'leave'
|
|
606
|
+
) {
|
|
607
|
+
/**
|
|
408
608
|
* Emitted when a user leaves the chat or is removed by an admin.
|
|
409
609
|
* @event Client#group_leave
|
|
410
610
|
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
411
611
|
*/
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
612
|
+
this.emit(Events.GROUP_LEAVE, notification);
|
|
613
|
+
} else if (
|
|
614
|
+
msg.subtype === 'promote' ||
|
|
615
|
+
msg.subtype === 'demote'
|
|
616
|
+
) {
|
|
617
|
+
/**
|
|
415
618
|
* Emitted when a current user is promoted to an admin or demoted to a regular user.
|
|
416
619
|
* @event Client#group_admin_changed
|
|
417
620
|
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
418
621
|
*/
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
622
|
+
this.emit(Events.GROUP_ADMIN_CHANGED, notification);
|
|
623
|
+
} else if (msg.subtype === 'membership_approval_request') {
|
|
624
|
+
/**
|
|
422
625
|
* Emitted when some user requested to join the group
|
|
423
626
|
* that has the membership approval mode turned on
|
|
424
627
|
* @event Client#group_membership_request
|
|
@@ -427,89 +630,106 @@ class Client extends EventEmitter {
|
|
|
427
630
|
* @param {string} notification.author The user ID that made a request
|
|
428
631
|
* @param {number} notification.timestamp The timestamp the request was made at
|
|
429
632
|
*/
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
633
|
+
this.emit(
|
|
634
|
+
Events.GROUP_MEMBERSHIP_REQUEST,
|
|
635
|
+
notification,
|
|
636
|
+
);
|
|
637
|
+
} else {
|
|
638
|
+
/**
|
|
433
639
|
* Emitted when group settings are updated, such as subject, description or picture.
|
|
434
640
|
* @event Client#group_update
|
|
435
641
|
* @param {GroupNotification} notification GroupNotification with more information about the action
|
|
436
642
|
*/
|
|
437
|
-
|
|
643
|
+
this.emit(Events.GROUP_UPDATE, notification);
|
|
644
|
+
}
|
|
645
|
+
return;
|
|
438
646
|
}
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
647
|
|
|
442
|
-
|
|
648
|
+
const message = new Message(this, msg);
|
|
443
649
|
|
|
444
|
-
|
|
650
|
+
/**
|
|
445
651
|
* Emitted when a new message is created, which may include the current user's own messages.
|
|
446
652
|
* @event Client#message_create
|
|
447
653
|
* @param {Message} message The message that was created
|
|
448
654
|
*/
|
|
449
|
-
|
|
655
|
+
this.emit(Events.MESSAGE_CREATE, message);
|
|
450
656
|
|
|
451
|
-
|
|
657
|
+
if (msg.id.fromMe) return;
|
|
452
658
|
|
|
453
|
-
|
|
659
|
+
/**
|
|
454
660
|
* Emitted when a new message is received.
|
|
455
661
|
* @event Client#message
|
|
456
662
|
* @param {Message} message The message that was received
|
|
457
663
|
*/
|
|
458
|
-
|
|
459
|
-
|
|
664
|
+
this.emit(Events.MESSAGE_RECEIVED, message);
|
|
665
|
+
},
|
|
666
|
+
);
|
|
460
667
|
|
|
461
668
|
let last_message;
|
|
462
669
|
|
|
463
|
-
await exposeFunctionIfAbsent(
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
revoked_msg
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
670
|
+
await exposeFunctionIfAbsent(
|
|
671
|
+
this.pupPage,
|
|
672
|
+
'onChangeMessageTypeEvent',
|
|
673
|
+
(msg) => {
|
|
674
|
+
if (msg.type === 'revoked') {
|
|
675
|
+
const message = new Message(this, msg);
|
|
676
|
+
let revoked_msg;
|
|
677
|
+
if (last_message && msg.id.id === last_message.id.id) {
|
|
678
|
+
revoked_msg = new Message(this, last_message);
|
|
679
|
+
|
|
680
|
+
if (message.protocolMessageKey)
|
|
681
|
+
revoked_msg.id = { ...message.protocolMessageKey };
|
|
682
|
+
}
|
|
474
683
|
|
|
475
|
-
|
|
684
|
+
/**
|
|
476
685
|
* Emitted when a message is deleted for everyone in the chat.
|
|
477
686
|
* @event Client#message_revoke_everyone
|
|
478
687
|
* @param {Message} message The message that was revoked, in its current state. It will not contain the original message's data.
|
|
479
|
-
* @param {?Message} revoked_msg The message that was revoked, before it was revoked. It will contain the message's original data.
|
|
688
|
+
* @param {?Message} revoked_msg The message that was revoked, before it was revoked. It will contain the message's original data.
|
|
480
689
|
* Note that due to the way this data is captured, it may be possible that this param will be undefined.
|
|
481
690
|
*/
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
691
|
+
this.emit(
|
|
692
|
+
Events.MESSAGE_REVOKED_EVERYONE,
|
|
693
|
+
message,
|
|
694
|
+
revoked_msg,
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
},
|
|
698
|
+
);
|
|
699
|
+
|
|
700
|
+
await exposeFunctionIfAbsent(
|
|
701
|
+
this.pupPage,
|
|
702
|
+
'onChangeMessageEvent',
|
|
703
|
+
(msg) => {
|
|
704
|
+
if (msg.type !== 'revoked') {
|
|
705
|
+
last_message = msg;
|
|
706
|
+
}
|
|
492
707
|
|
|
493
|
-
|
|
708
|
+
/**
|
|
494
709
|
* The event notification that is received when one of
|
|
495
710
|
* the group participants changes their phone number.
|
|
496
711
|
*/
|
|
497
|
-
|
|
712
|
+
const isParticipant =
|
|
713
|
+
msg.type === 'gp2' && msg.subtype === 'modify';
|
|
498
714
|
|
|
499
|
-
|
|
715
|
+
/**
|
|
500
716
|
* The event notification that is received when one of
|
|
501
717
|
* the contacts changes their phone number.
|
|
502
718
|
*/
|
|
503
|
-
|
|
719
|
+
const isContact =
|
|
720
|
+
msg.type === 'notification_template' &&
|
|
721
|
+
msg.subtype === 'change_number';
|
|
504
722
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
723
|
+
if (isParticipant || isContact) {
|
|
724
|
+
/** @type {GroupNotification} object does not provide enough information about this event, so a @type {Message} object is used. */
|
|
725
|
+
const message = new Message(this, msg);
|
|
508
726
|
|
|
509
|
-
|
|
510
|
-
|
|
727
|
+
const newId = isParticipant ? msg.recipients[0] : msg.to;
|
|
728
|
+
const oldId = isParticipant
|
|
729
|
+
? msg.author
|
|
730
|
+
: msg.templateParams.find((id) => id !== newId);
|
|
511
731
|
|
|
512
|
-
|
|
732
|
+
/**
|
|
513
733
|
* Emitted when a contact or a group participant changes their phone number.
|
|
514
734
|
* @event Client#contact_changed
|
|
515
735
|
* @param {Message} message Message with more information about the event.
|
|
@@ -518,98 +738,132 @@ class Client extends EventEmitter {
|
|
|
518
738
|
* @param {String} newId The user's new id after the change.
|
|
519
739
|
* @param {Boolean} isContact Indicates if a contact or a group participant changed their phone number.
|
|
520
740
|
*/
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
741
|
+
this.emit(
|
|
742
|
+
Events.CONTACT_CHANGED,
|
|
743
|
+
message,
|
|
744
|
+
oldId,
|
|
745
|
+
newId,
|
|
746
|
+
isContact,
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
},
|
|
750
|
+
);
|
|
526
751
|
|
|
527
|
-
|
|
752
|
+
await exposeFunctionIfAbsent(
|
|
753
|
+
this.pupPage,
|
|
754
|
+
'onRemoveMessageEvent',
|
|
755
|
+
(msg) => {
|
|
756
|
+
if (!msg.isNewMsg) return;
|
|
528
757
|
|
|
529
|
-
|
|
758
|
+
const message = new Message(this, msg);
|
|
530
759
|
|
|
531
|
-
|
|
760
|
+
/**
|
|
532
761
|
* Emitted when a message is deleted by the current user.
|
|
533
762
|
* @event Client#message_revoke_me
|
|
534
763
|
* @param {Message} message The message that was revoked
|
|
535
764
|
*/
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
await exposeFunctionIfAbsent(
|
|
541
|
-
|
|
542
|
-
|
|
765
|
+
this.emit(Events.MESSAGE_REVOKED_ME, message);
|
|
766
|
+
},
|
|
767
|
+
);
|
|
768
|
+
|
|
769
|
+
await exposeFunctionIfAbsent(
|
|
770
|
+
this.pupPage,
|
|
771
|
+
'onMessageAckEvent',
|
|
772
|
+
(msg, ack) => {
|
|
773
|
+
const message = new Message(this, msg);
|
|
543
774
|
|
|
544
|
-
|
|
775
|
+
/**
|
|
545
776
|
* Emitted when an ack event occurrs on message type.
|
|
546
777
|
* @event Client#message_ack
|
|
547
778
|
* @param {Message} message The message that was affected
|
|
548
779
|
* @param {MessageAck} ack The new ACK value
|
|
549
780
|
*/
|
|
550
|
-
|
|
781
|
+
this.emit(Events.MESSAGE_ACK, message, ack);
|
|
782
|
+
},
|
|
783
|
+
);
|
|
551
784
|
|
|
552
|
-
|
|
785
|
+
await exposeFunctionIfAbsent(
|
|
786
|
+
this.pupPage,
|
|
787
|
+
'onChatUnreadCountEvent',
|
|
788
|
+
async (data) => {
|
|
789
|
+
const chat = await this.getChatById(data.id);
|
|
553
790
|
|
|
554
|
-
|
|
555
|
-
const chat = await this.getChatById(data.id);
|
|
556
|
-
|
|
557
|
-
/**
|
|
791
|
+
/**
|
|
558
792
|
* Emitted when the chat unread count changes
|
|
559
793
|
*/
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
794
|
+
this.emit(Events.UNREAD_COUNT, chat);
|
|
795
|
+
},
|
|
796
|
+
);
|
|
797
|
+
|
|
798
|
+
await exposeFunctionIfAbsent(
|
|
799
|
+
this.pupPage,
|
|
800
|
+
'onMessageMediaUploadedEvent',
|
|
801
|
+
(msg) => {
|
|
802
|
+
const message = new Message(this, msg);
|
|
566
803
|
|
|
567
|
-
|
|
804
|
+
/**
|
|
568
805
|
* Emitted when media has been uploaded for a message sent by the client.
|
|
569
806
|
* @event Client#media_uploaded
|
|
570
807
|
* @param {Message} message The message with media that was uploaded
|
|
571
808
|
*/
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
809
|
+
this.emit(Events.MEDIA_UPLOADED, message);
|
|
810
|
+
},
|
|
811
|
+
);
|
|
812
|
+
|
|
813
|
+
await exposeFunctionIfAbsent(
|
|
814
|
+
this.pupPage,
|
|
815
|
+
'onAppStateChangedEvent',
|
|
816
|
+
async (state) => {
|
|
817
|
+
/**
|
|
577
818
|
* Emitted when the connection state changes
|
|
578
819
|
* @event Client#change_state
|
|
579
820
|
* @param {WAState} state the new connection state
|
|
580
821
|
*/
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
822
|
+
this.emit(Events.STATE_CHANGED, state);
|
|
823
|
+
|
|
824
|
+
const ACCEPTED_STATES = [
|
|
825
|
+
WAState.CONNECTED,
|
|
826
|
+
WAState.OPENING,
|
|
827
|
+
WAState.PAIRING,
|
|
828
|
+
WAState.TIMEOUT,
|
|
829
|
+
];
|
|
830
|
+
|
|
831
|
+
if (this.options.takeoverOnConflict) {
|
|
832
|
+
ACCEPTED_STATES.push(WAState.CONFLICT);
|
|
833
|
+
|
|
834
|
+
if (state === WAState.CONFLICT) {
|
|
835
|
+
setTimeout(() => {
|
|
836
|
+
this.pupPage.evaluate(() =>
|
|
837
|
+
window
|
|
838
|
+
.require('WAWebSocketModel')
|
|
839
|
+
.Socket.takeover(),
|
|
840
|
+
);
|
|
841
|
+
}, this.options.takeoverTimeoutMs);
|
|
842
|
+
}
|
|
592
843
|
}
|
|
593
|
-
}
|
|
594
844
|
|
|
595
|
-
|
|
596
|
-
|
|
845
|
+
if (!ACCEPTED_STATES.includes(state)) {
|
|
846
|
+
/**
|
|
597
847
|
* Emitted when the client has been disconnected
|
|
598
848
|
* @event Client#disconnected
|
|
599
849
|
* @param {WAState|"LOGOUT"} reason reason that caused the disconnect
|
|
600
850
|
*/
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
851
|
+
await this.authStrategy.disconnect();
|
|
852
|
+
this.emit(Events.DISCONNECTED, state);
|
|
853
|
+
this.destroy();
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
);
|
|
606
857
|
|
|
607
|
-
await exposeFunctionIfAbsent(
|
|
608
|
-
|
|
858
|
+
await exposeFunctionIfAbsent(
|
|
859
|
+
this.pupPage,
|
|
860
|
+
'onBatteryStateChangedEvent',
|
|
861
|
+
(state) => {
|
|
862
|
+
const { battery, plugged } = state;
|
|
609
863
|
|
|
610
|
-
|
|
864
|
+
if (battery === undefined) return;
|
|
611
865
|
|
|
612
|
-
|
|
866
|
+
/**
|
|
613
867
|
* Emitted when the battery percentage for the attached device changes. Will not be sent if using multi-device.
|
|
614
868
|
* @event Client#change_battery
|
|
615
869
|
* @param {object} batteryInfo
|
|
@@ -617,30 +871,34 @@ class Client extends EventEmitter {
|
|
|
617
871
|
* @param {boolean} batteryInfo.plugged - Indicates if the phone is plugged in (true) or not (false)
|
|
618
872
|
* @deprecated
|
|
619
873
|
*/
|
|
620
|
-
|
|
621
|
-
|
|
874
|
+
this.emit(Events.BATTERY_CHANGED, { battery, plugged });
|
|
875
|
+
},
|
|
876
|
+
);
|
|
622
877
|
|
|
623
878
|
await exposeFunctionIfAbsent(this.pupPage, 'onIncomingCall', (call) => {
|
|
624
879
|
/**
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
880
|
+
* Emitted when a call is received
|
|
881
|
+
* @event Client#incoming_call
|
|
882
|
+
* @param {object} call
|
|
883
|
+
* @param {number} call.id - Call id
|
|
884
|
+
* @param {string} call.peerJid - Who called
|
|
885
|
+
* @param {boolean} call.isVideo - if is video
|
|
886
|
+
* @param {boolean} call.isGroup - if is group
|
|
887
|
+
* @param {boolean} call.canHandleLocally - if we can handle in waweb
|
|
888
|
+
* @param {boolean} call.outgoing - if is outgoing
|
|
889
|
+
* @param {boolean} call.webClientShouldHandle - If Waweb should handle
|
|
890
|
+
* @param {object} call.participants - Participants
|
|
891
|
+
*/
|
|
637
892
|
const cll = new Call(this, call);
|
|
638
893
|
this.emit(Events.INCOMING_CALL, cll);
|
|
639
894
|
});
|
|
640
895
|
|
|
641
|
-
await exposeFunctionIfAbsent(
|
|
642
|
-
|
|
643
|
-
|
|
896
|
+
await exposeFunctionIfAbsent(
|
|
897
|
+
this.pupPage,
|
|
898
|
+
'onReaction',
|
|
899
|
+
(reactions) => {
|
|
900
|
+
for (const reaction of reactions) {
|
|
901
|
+
/**
|
|
644
902
|
* Emitted when a reaction is sent, received, updated or removed
|
|
645
903
|
* @event Client#message_reaction
|
|
646
904
|
* @param {object} reaction
|
|
@@ -655,168 +913,357 @@ class Client extends EventEmitter {
|
|
|
655
913
|
* @param {?number} reaction.ack - Ack
|
|
656
914
|
*/
|
|
657
915
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
916
|
+
this.emit(
|
|
917
|
+
Events.MESSAGE_REACTION,
|
|
918
|
+
new Reaction(this, reaction),
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
);
|
|
661
923
|
|
|
662
|
-
await exposeFunctionIfAbsent(
|
|
663
|
-
|
|
924
|
+
await exposeFunctionIfAbsent(
|
|
925
|
+
this.pupPage,
|
|
926
|
+
'onRemoveChatEvent',
|
|
927
|
+
async (chat) => {
|
|
928
|
+
const _chat = await this.getChatById(chat.id);
|
|
664
929
|
|
|
665
|
-
|
|
930
|
+
/**
|
|
666
931
|
* Emitted when a chat is removed
|
|
667
932
|
* @event Client#chat_removed
|
|
668
933
|
* @param {Chat} chat
|
|
669
934
|
*/
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
935
|
+
this.emit(Events.CHAT_REMOVED, _chat);
|
|
936
|
+
},
|
|
937
|
+
);
|
|
938
|
+
|
|
939
|
+
await exposeFunctionIfAbsent(
|
|
940
|
+
this.pupPage,
|
|
941
|
+
'onArchiveChatEvent',
|
|
942
|
+
async (chat, currState, prevState) => {
|
|
943
|
+
const _chat = await this.getChatById(chat.id);
|
|
944
|
+
|
|
945
|
+
/**
|
|
677
946
|
* Emitted when a chat is archived/unarchived
|
|
678
947
|
* @event Client#chat_archived
|
|
679
948
|
* @param {Chat} chat
|
|
680
949
|
* @param {boolean} currState
|
|
681
950
|
* @param {boolean} prevState
|
|
682
951
|
*/
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
952
|
+
this.emit(Events.CHAT_ARCHIVED, _chat, currState, prevState);
|
|
953
|
+
},
|
|
954
|
+
);
|
|
955
|
+
|
|
956
|
+
await exposeFunctionIfAbsent(
|
|
957
|
+
this.pupPage,
|
|
958
|
+
'onEditMessageEvent',
|
|
959
|
+
(msg, newBody, prevBody) => {
|
|
960
|
+
if (msg.type === 'revoked') {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
692
964
|
* Emitted when messages are edited
|
|
693
965
|
* @event Client#message_edit
|
|
694
966
|
* @param {Message} message
|
|
695
967
|
* @param {string} newBody
|
|
696
968
|
* @param {string} prevBody
|
|
697
969
|
*/
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
970
|
+
this.emit(
|
|
971
|
+
Events.MESSAGE_EDIT,
|
|
972
|
+
new Message(this, msg),
|
|
973
|
+
newBody,
|
|
974
|
+
prevBody,
|
|
975
|
+
);
|
|
976
|
+
},
|
|
977
|
+
);
|
|
978
|
+
|
|
979
|
+
await exposeFunctionIfAbsent(
|
|
980
|
+
this.pupPage,
|
|
981
|
+
'onAddMessageCiphertextEvent',
|
|
982
|
+
(msg) => {
|
|
983
|
+
/**
|
|
984
|
+
* Emitted when a message is received as ciphertext (not yet decrypted)
|
|
705
985
|
* @event Client#message_ciphertext
|
|
706
986
|
* @param {Message} message
|
|
707
987
|
*/
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
988
|
+
this.emit(Events.MESSAGE_CIPHERTEXT, new Message(this, msg));
|
|
989
|
+
},
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
await exposeFunctionIfAbsent(
|
|
993
|
+
this.pupPage,
|
|
994
|
+
'onCiphertextFailedEvent',
|
|
995
|
+
(msg) => {
|
|
713
996
|
/**
|
|
714
|
-
* Emitted when
|
|
715
|
-
*
|
|
716
|
-
* @
|
|
997
|
+
* Emitted when a ciphertext message failed to decrypt after recovery attempt
|
|
998
|
+
* @event Client#message_ciphertext_failed
|
|
999
|
+
* @param {Message} message
|
|
717
1000
|
*/
|
|
718
|
-
this.emit(
|
|
719
|
-
|
|
720
|
-
|
|
1001
|
+
this.emit(
|
|
1002
|
+
Events.MESSAGE_CIPHERTEXT_FAILED,
|
|
1003
|
+
new Message(this, msg),
|
|
1004
|
+
);
|
|
1005
|
+
},
|
|
1006
|
+
);
|
|
1007
|
+
|
|
1008
|
+
await exposeFunctionIfAbsent(
|
|
1009
|
+
this.pupPage,
|
|
1010
|
+
'onPollVoteEvent',
|
|
1011
|
+
(votes) => {
|
|
1012
|
+
for (const vote of votes) {
|
|
1013
|
+
/**
|
|
1014
|
+
* Emitted when some poll option is selected or deselected,
|
|
1015
|
+
* shows a user's current selected option(s) on the poll
|
|
1016
|
+
* @event Client#vote_update
|
|
1017
|
+
*/
|
|
1018
|
+
this.emit(Events.VOTE_UPDATE, new PollVote(this, vote));
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
);
|
|
721
1022
|
|
|
722
1023
|
await this.pupPage.evaluate(() => {
|
|
723
|
-
const { Msg, Chat
|
|
1024
|
+
const { Msg, Chat } = window.require('WAWebCollections');
|
|
724
1025
|
const AppState = window.require('WAWebSocketModel').Socket;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
Msg.on('change
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
1026
|
+
|
|
1027
|
+
// Enable placeholder message resend (recovery for ciphertext messages)
|
|
1028
|
+
const gatingUtils = window.require('WAWebSyncGatingUtils');
|
|
1029
|
+
gatingUtils.isPlaceholderMessageResendEnabled = () => true;
|
|
1030
|
+
|
|
1031
|
+
Msg.on('change', (msg) => {
|
|
1032
|
+
window.onChangeMessageEvent(window.WWebJS.getMessageModel(msg));
|
|
1033
|
+
});
|
|
1034
|
+
Msg.on('change:type', (msg) => {
|
|
1035
|
+
window.onChangeMessageTypeEvent(
|
|
1036
|
+
window.WWebJS.getMessageModel(msg),
|
|
1037
|
+
);
|
|
1038
|
+
});
|
|
1039
|
+
Msg.on('change:ack', (msg, ack) => {
|
|
1040
|
+
window.onMessageAckEvent(
|
|
1041
|
+
window.WWebJS.getMessageModel(msg),
|
|
1042
|
+
ack,
|
|
1043
|
+
);
|
|
1044
|
+
});
|
|
1045
|
+
Msg.on('change:isUnsentMedia', (msg, unsent) => {
|
|
1046
|
+
if (msg.id.fromMe && !unsent)
|
|
1047
|
+
window.onMessageMediaUploadedEvent(
|
|
1048
|
+
window.WWebJS.getMessageModel(msg),
|
|
1049
|
+
);
|
|
1050
|
+
});
|
|
1051
|
+
Msg.on('remove', (msg) => {
|
|
1052
|
+
if (msg.isNewMsg)
|
|
1053
|
+
window.onRemoveMessageEvent(
|
|
1054
|
+
window.WWebJS.getMessageModel(msg),
|
|
1055
|
+
);
|
|
1056
|
+
});
|
|
1057
|
+
Msg.on('change:body change:caption', (msg, newBody, prevBody) => {
|
|
1058
|
+
window.onEditMessageEvent(
|
|
1059
|
+
window.WWebJS.getMessageModel(msg),
|
|
1060
|
+
newBody,
|
|
1061
|
+
prevBody,
|
|
1062
|
+
);
|
|
1063
|
+
});
|
|
1064
|
+
AppState.on('change:state', (_AppState, state) => {
|
|
1065
|
+
window.onAppStateChangedEvent(state);
|
|
1066
|
+
});
|
|
1067
|
+
window
|
|
1068
|
+
.require('WAWebConnModel')
|
|
1069
|
+
.Conn.on('change:battery', (state) => {
|
|
1070
|
+
window.onBatteryStateChangedEvent(state);
|
|
1071
|
+
});
|
|
1072
|
+
const WAWebCallCollection = window.require('WAWebCallCollection');
|
|
1073
|
+
if (
|
|
1074
|
+
WAWebCallCollection &&
|
|
1075
|
+
typeof WAWebCallCollection.on === 'function'
|
|
1076
|
+
) {
|
|
1077
|
+
const mapKey = Object.keys(WAWebCallCollection).find(
|
|
1078
|
+
(k) => WAWebCallCollection[k] instanceof Map,
|
|
1079
|
+
);
|
|
1080
|
+
const internalCallMap = WAWebCallCollection[mapKey];
|
|
1081
|
+
const originalMapSet =
|
|
1082
|
+
internalCallMap.set.bind(internalCallMap);
|
|
1083
|
+
|
|
1084
|
+
internalCallMap.set = function (key, value) {
|
|
1085
|
+
window.onIncomingCall({
|
|
1086
|
+
id: value.id,
|
|
1087
|
+
peerJid: value.peerJid,
|
|
1088
|
+
isVideo: value.isVideo,
|
|
1089
|
+
isGroup: value.isGroup,
|
|
1090
|
+
canHandleLocally: value.canHandleLocally,
|
|
1091
|
+
outgoing: value.outgoing,
|
|
1092
|
+
webClientShouldHandle: value.webClientShouldHandle,
|
|
1093
|
+
participants: value.participants,
|
|
1094
|
+
});
|
|
1095
|
+
return originalMapSet(key, value);
|
|
1096
|
+
};
|
|
735
1097
|
}
|
|
736
|
-
Chat.on('remove', async (chat) => {
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
}
|
|
1098
|
+
Chat.on('remove', async (chat) => {
|
|
1099
|
+
window.onRemoveChatEvent(
|
|
1100
|
+
await window.WWebJS.getChatModel(chat),
|
|
1101
|
+
);
|
|
1102
|
+
});
|
|
1103
|
+
Chat.on('change:archive', async (chat, currState, prevState) => {
|
|
1104
|
+
window.onArchiveChatEvent(
|
|
1105
|
+
await window.WWebJS.getChatModel(chat),
|
|
1106
|
+
currState,
|
|
1107
|
+
prevState,
|
|
1108
|
+
);
|
|
748
1109
|
});
|
|
749
|
-
|
|
1110
|
+
const pendingResend = new Set();
|
|
1111
|
+
let resendFlush = null;
|
|
1112
|
+
|
|
1113
|
+
function requestResend(msg) {
|
|
1114
|
+
pendingResend.add(msg);
|
|
1115
|
+
if (resendFlush) return;
|
|
1116
|
+
resendFlush = setTimeout(() => {
|
|
1117
|
+
resendFlush = null;
|
|
1118
|
+
const msgs = [...pendingResend];
|
|
1119
|
+
pendingResend.clear();
|
|
1120
|
+
if (msgs.length === 0) return;
|
|
1121
|
+
window
|
|
1122
|
+
.require(
|
|
1123
|
+
'WAWebNonMessageDataRequestPlaceholderMessageResendUtils',
|
|
1124
|
+
)
|
|
1125
|
+
.handlePlaceholderMsgsSeen(msgs, true);
|
|
1126
|
+
}, 5000);
|
|
1127
|
+
}
|
|
750
1128
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
const msgKey = reaction.id;
|
|
754
|
-
const parentMsgKey = reaction.reactionParentKey;
|
|
755
|
-
const timestamp = reaction.reactionTimestamp / 1000;
|
|
756
|
-
const sender = reaction.author ?? reaction.from;
|
|
757
|
-
const senderUserJid = sender._serialized;
|
|
1129
|
+
Msg.on('add', (msg) => {
|
|
1130
|
+
if (!msg.isNewMsg) return;
|
|
758
1131
|
|
|
759
|
-
|
|
760
|
-
|
|
1132
|
+
if (msg.type !== 'ciphertext') {
|
|
1133
|
+
window.onAddMessageEvent(
|
|
1134
|
+
window.WWebJS.getMessageModel(msg),
|
|
1135
|
+
);
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
761
1138
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
window.WWebJS.injectToFunction({ module: 'WAWebAddonPollVoteTableMode', function: 'pollVoteTableMode.bulkUpsert'}, async (module, origFunction, ...args) => {
|
|
766
|
-
const votes = await Promise.all(args[0].map(async vote => {
|
|
767
|
-
const msgKey = vote.id;
|
|
768
|
-
const parentMsgKey = vote.pollUpdateParentKey;
|
|
769
|
-
const timestamp = vote.t / 1000;
|
|
770
|
-
const sender = vote.author ?? vote.from;
|
|
771
|
-
const senderUserJid = sender._serialized;
|
|
772
|
-
|
|
773
|
-
let parentMessage = Msg.get(parentMsgKey._serialized);
|
|
774
|
-
if (!parentMessage) {
|
|
775
|
-
const fetched = await Msg.getMessagesById([parentMsgKey._serialized]);
|
|
776
|
-
parentMessage = fetched?.messages?.[0] || null;
|
|
777
|
-
}
|
|
1139
|
+
window.onAddMessageCiphertextEvent(
|
|
1140
|
+
window.WWebJS.getMessageModel(msg),
|
|
1141
|
+
);
|
|
778
1142
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
msgKey,
|
|
782
|
-
sender,
|
|
783
|
-
parentMsgKey,
|
|
784
|
-
senderUserJid,
|
|
785
|
-
timestamp,
|
|
786
|
-
parentMessage
|
|
787
|
-
};
|
|
788
|
-
}));
|
|
1143
|
+
if (msg.subtype && msg.subtype.endsWith('_unavailable_fanout'))
|
|
1144
|
+
return;
|
|
789
1145
|
|
|
790
|
-
|
|
1146
|
+
requestResend(msg);
|
|
791
1147
|
|
|
792
|
-
|
|
1148
|
+
const failTimer = setTimeout(() => {
|
|
1149
|
+
if (msg.type !== 'ciphertext') return;
|
|
1150
|
+
window.onCiphertextFailedEvent(
|
|
1151
|
+
window.WWebJS.getMessageModel(msg),
|
|
1152
|
+
);
|
|
1153
|
+
}, 15000);
|
|
1154
|
+
|
|
1155
|
+
msg.once('change:type', (_msg) => {
|
|
1156
|
+
clearTimeout(failTimer);
|
|
1157
|
+
pendingResend.delete(_msg);
|
|
1158
|
+
if (_msg.type === 'revoked') return;
|
|
1159
|
+
window.onAddMessageEvent(
|
|
1160
|
+
window.WWebJS.getMessageModel(_msg),
|
|
1161
|
+
);
|
|
1162
|
+
});
|
|
1163
|
+
});
|
|
1164
|
+
Chat.on('change:unreadCount', (chat) => {
|
|
1165
|
+
window.onChatUnreadCountEvent(chat);
|
|
793
1166
|
});
|
|
1167
|
+
|
|
1168
|
+
window.WWebJS.injectToFunction(
|
|
1169
|
+
{
|
|
1170
|
+
module: 'WAWebAddonReactionTableMode',
|
|
1171
|
+
function: 'reactionTableMode.bulkUpsert',
|
|
1172
|
+
},
|
|
1173
|
+
(module, origFunction, ...args) => {
|
|
1174
|
+
window.onReaction(
|
|
1175
|
+
args[0].map((reaction) => {
|
|
1176
|
+
const msgKey = reaction.id;
|
|
1177
|
+
const parentMsgKey = reaction.reactionParentKey;
|
|
1178
|
+
const timestamp = reaction.reactionTimestamp / 1000;
|
|
1179
|
+
const sender = reaction.author ?? reaction.from;
|
|
1180
|
+
const senderUserJid = sender._serialized;
|
|
1181
|
+
|
|
1182
|
+
return {
|
|
1183
|
+
...reaction,
|
|
1184
|
+
msgKey,
|
|
1185
|
+
parentMsgKey,
|
|
1186
|
+
senderUserJid,
|
|
1187
|
+
timestamp,
|
|
1188
|
+
};
|
|
1189
|
+
}),
|
|
1190
|
+
);
|
|
1191
|
+
|
|
1192
|
+
return origFunction.apply(module, args);
|
|
1193
|
+
},
|
|
1194
|
+
);
|
|
1195
|
+
|
|
1196
|
+
window.WWebJS.injectToFunction(
|
|
1197
|
+
{
|
|
1198
|
+
module: 'WAWebAddonPollVoteTableMode',
|
|
1199
|
+
function: 'pollVoteTableMode.bulkUpsert',
|
|
1200
|
+
},
|
|
1201
|
+
async (module, origFunction, ...args) => {
|
|
1202
|
+
const votes = await Promise.all(
|
|
1203
|
+
args[0].map(async (vote) => {
|
|
1204
|
+
const msgKey = vote.id;
|
|
1205
|
+
const parentMsgKey = vote.pollUpdateParentKey;
|
|
1206
|
+
const timestamp = vote.t / 1000;
|
|
1207
|
+
const sender = vote.author ?? vote.from;
|
|
1208
|
+
const senderUserJid = sender._serialized;
|
|
1209
|
+
|
|
1210
|
+
let parentMessage = Msg.get(
|
|
1211
|
+
parentMsgKey._serialized,
|
|
1212
|
+
);
|
|
1213
|
+
if (!parentMessage) {
|
|
1214
|
+
const fetched = await Msg.getMessagesById([
|
|
1215
|
+
parentMsgKey._serialized,
|
|
1216
|
+
]);
|
|
1217
|
+
parentMessage = fetched?.messages?.[0] || null;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
return {
|
|
1221
|
+
...vote,
|
|
1222
|
+
msgKey,
|
|
1223
|
+
sender,
|
|
1224
|
+
parentMsgKey,
|
|
1225
|
+
senderUserJid,
|
|
1226
|
+
timestamp,
|
|
1227
|
+
parentMessage,
|
|
1228
|
+
};
|
|
1229
|
+
}),
|
|
1230
|
+
);
|
|
1231
|
+
|
|
1232
|
+
window.onPollVoteEvent(votes);
|
|
1233
|
+
|
|
1234
|
+
return origFunction.apply(module, args);
|
|
1235
|
+
},
|
|
1236
|
+
);
|
|
794
1237
|
});
|
|
795
|
-
}
|
|
1238
|
+
}
|
|
796
1239
|
|
|
797
1240
|
async initWebVersionCache() {
|
|
798
|
-
const { type: webCacheType, ...webCacheOptions } =
|
|
799
|
-
|
|
1241
|
+
const { type: webCacheType, ...webCacheOptions } =
|
|
1242
|
+
this.options.webVersionCache;
|
|
1243
|
+
const webCache = WebCacheFactory.createWebCache(
|
|
1244
|
+
webCacheType,
|
|
1245
|
+
webCacheOptions,
|
|
1246
|
+
);
|
|
800
1247
|
|
|
801
1248
|
const requestedVersion = this.options.webVersion;
|
|
802
1249
|
const versionContent = await webCache.resolve(requestedVersion);
|
|
803
1250
|
|
|
804
|
-
if(versionContent) {
|
|
1251
|
+
if (versionContent) {
|
|
805
1252
|
await this.pupPage.setRequestInterception(true);
|
|
806
1253
|
this.pupPage.on('request', async (req) => {
|
|
807
|
-
if(req.url() === WhatsWebURL) {
|
|
1254
|
+
if (req.url() === WhatsWebURL) {
|
|
808
1255
|
req.respond({
|
|
809
1256
|
status: 200,
|
|
810
1257
|
contentType: 'text/html',
|
|
811
|
-
body: versionContent
|
|
812
|
-
});
|
|
1258
|
+
body: versionContent,
|
|
1259
|
+
});
|
|
813
1260
|
} else {
|
|
814
1261
|
req.continue();
|
|
815
1262
|
}
|
|
816
1263
|
});
|
|
817
1264
|
} else {
|
|
818
1265
|
this.pupPage.on('response', async (res) => {
|
|
819
|
-
if(res.ok() && res.url() === WhatsWebURL) {
|
|
1266
|
+
if (res.ok() && res.url() === WhatsWebURL) {
|
|
820
1267
|
const indexHtml = await res.text();
|
|
821
1268
|
this.currentIndexHtml = indexHtml;
|
|
822
1269
|
}
|
|
@@ -844,13 +1291,14 @@ class Client extends EventEmitter {
|
|
|
844
1291
|
return window.require('WAWebSocketModel').Socket.logout();
|
|
845
1292
|
});
|
|
846
1293
|
await this.pupBrowser.close();
|
|
847
|
-
|
|
1294
|
+
|
|
848
1295
|
let maxDelay = 0;
|
|
849
|
-
while (this.pupBrowser.isConnected() &&
|
|
850
|
-
|
|
851
|
-
|
|
1296
|
+
while (this.pupBrowser.isConnected() && maxDelay < 10) {
|
|
1297
|
+
// waits a maximum of 1 second before calling the AuthStrategy
|
|
1298
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
1299
|
+
maxDelay++;
|
|
852
1300
|
}
|
|
853
|
-
|
|
1301
|
+
|
|
854
1302
|
await this.authStrategy.logout();
|
|
855
1303
|
}
|
|
856
1304
|
|
|
@@ -865,23 +1313,28 @@ class Client extends EventEmitter {
|
|
|
865
1313
|
}
|
|
866
1314
|
|
|
867
1315
|
async setDeviceName(deviceName, browserName) {
|
|
868
|
-
(deviceName || browserName) &&
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1316
|
+
(deviceName || browserName) &&
|
|
1317
|
+
(await this.pupPage.evaluate(
|
|
1318
|
+
(deviceName, browserName) => {
|
|
1319
|
+
const func = window.require('WAWebMiscBrowserUtils').info;
|
|
1320
|
+
window.require('WAWebMiscBrowserUtils').info = () => {
|
|
1321
|
+
return {
|
|
1322
|
+
...func(),
|
|
1323
|
+
...(deviceName ? { os: deviceName } : {}),
|
|
1324
|
+
...(browserName ? { name: browserName } : {}),
|
|
1325
|
+
};
|
|
1326
|
+
};
|
|
1327
|
+
},
|
|
1328
|
+
deviceName,
|
|
1329
|
+
browserName,
|
|
1330
|
+
));
|
|
878
1331
|
}
|
|
879
1332
|
|
|
880
1333
|
/**
|
|
881
1334
|
* Mark as seen for the Chat
|
|
882
1335
|
* @param {string} chatId
|
|
883
1336
|
* @returns {Promise<boolean>} result
|
|
884
|
-
*
|
|
1337
|
+
*
|
|
885
1338
|
*/
|
|
886
1339
|
async sendSeen(chatId) {
|
|
887
1340
|
return await this.pupPage.evaluate(async (chatId) => {
|
|
@@ -921,50 +1374,84 @@ class Client extends EventEmitter {
|
|
|
921
1374
|
* @property {MessageMedia} [media] - Media to be sent
|
|
922
1375
|
* @property {any} [extra] - Extra options
|
|
923
1376
|
*/
|
|
924
|
-
|
|
1377
|
+
|
|
925
1378
|
/**
|
|
926
1379
|
* Send a message to a specific chatId
|
|
927
1380
|
* @param {string} chatId
|
|
928
1381
|
* @param {string|MessageMedia|Location|Poll|Contact|Array<Contact>|Buttons|List} content
|
|
929
1382
|
* @param {MessageSendOptions} [options] - Options used when sending the message
|
|
930
|
-
*
|
|
1383
|
+
*
|
|
931
1384
|
* @returns {Promise<Message>} Message that was just sent
|
|
932
1385
|
*/
|
|
933
1386
|
async sendMessage(chatId, content, options = {}) {
|
|
934
1387
|
const isChannel = /@\w*newsletter\b/.test(chatId);
|
|
935
1388
|
const isStatus = /@\w*broadcast\b/.test(chatId);
|
|
936
1389
|
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1390
|
+
if (
|
|
1391
|
+
isChannel &&
|
|
1392
|
+
[
|
|
1393
|
+
options.sendMediaAsDocument,
|
|
1394
|
+
options.quotedMessageId,
|
|
1395
|
+
options.parseVCards,
|
|
1396
|
+
options.isViewOnce,
|
|
1397
|
+
content instanceof Location,
|
|
1398
|
+
content instanceof Contact,
|
|
1399
|
+
content instanceof Buttons,
|
|
1400
|
+
content instanceof List,
|
|
1401
|
+
Array.isArray(content) &&
|
|
1402
|
+
content.length > 0 &&
|
|
1403
|
+
content[0] instanceof Contact,
|
|
1404
|
+
].includes(true)
|
|
1405
|
+
) {
|
|
1406
|
+
console.warn(
|
|
1407
|
+
'The message type is currently not supported for sending in channels,\nthe supported message types are: text, image, sticker, gif, video, voice and poll.',
|
|
1408
|
+
);
|
|
945
1409
|
return null;
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
1410
|
+
} else if (
|
|
1411
|
+
isStatus &&
|
|
1412
|
+
[
|
|
1413
|
+
options.sendMediaAsDocument,
|
|
1414
|
+
options.quotedMessageId,
|
|
1415
|
+
options.parseVCards,
|
|
1416
|
+
options.isViewOnce,
|
|
1417
|
+
options.sendMediaAsSticker,
|
|
1418
|
+
content instanceof Location,
|
|
1419
|
+
content instanceof Contact,
|
|
1420
|
+
content instanceof Poll,
|
|
1421
|
+
content instanceof Buttons,
|
|
1422
|
+
content instanceof List,
|
|
1423
|
+
Array.isArray(content) &&
|
|
1424
|
+
content.length > 0 &&
|
|
1425
|
+
content[0] instanceof Contact,
|
|
1426
|
+
].includes(true)
|
|
1427
|
+
) {
|
|
1428
|
+
console.warn(
|
|
1429
|
+
'The message type is currently not supported for sending in status broadcast,\nthe supported message types are: text, image, gif, audio and video.',
|
|
1430
|
+
);
|
|
955
1431
|
return null;
|
|
956
1432
|
}
|
|
957
|
-
|
|
1433
|
+
|
|
958
1434
|
if (options.mentions) {
|
|
959
|
-
!Array.isArray(options.mentions) &&
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
options.mentions
|
|
1435
|
+
!Array.isArray(options.mentions) &&
|
|
1436
|
+
(options.mentions = [options.mentions]);
|
|
1437
|
+
if (
|
|
1438
|
+
options.mentions.some(
|
|
1439
|
+
(possiblyContact) => possiblyContact instanceof Contact,
|
|
1440
|
+
)
|
|
1441
|
+
) {
|
|
1442
|
+
console.warn(
|
|
1443
|
+
'Mentions with an array of Contact are now deprecated. See more at https://github.com/wwebjssapp-web.js/pull/2166.',
|
|
1444
|
+
);
|
|
1445
|
+
options.mentions = options.mentions.map(
|
|
1446
|
+
(a) => a.id._serialized,
|
|
1447
|
+
);
|
|
963
1448
|
}
|
|
964
1449
|
}
|
|
965
1450
|
|
|
966
|
-
options.groupMentions &&
|
|
967
|
-
|
|
1451
|
+
options.groupMentions &&
|
|
1452
|
+
!Array.isArray(options.groupMentions) &&
|
|
1453
|
+
(options.groupMentions = [options.groupMentions]);
|
|
1454
|
+
|
|
968
1455
|
let internalOptions = {
|
|
969
1456
|
linkPreview: options.linkPreview === false ? undefined : true,
|
|
970
1457
|
sendAudioAsVoice: options.sendAudioAsVoice,
|
|
@@ -981,20 +1468,18 @@ class Client extends EventEmitter {
|
|
|
981
1468
|
invokedBotWid: options.invokedBotWid,
|
|
982
1469
|
ignoreQuoteErrors: options.ignoreQuoteErrors !== false,
|
|
983
1470
|
waitUntilMsgSent: options.waitUntilMsgSent || false,
|
|
984
|
-
extraOptions: options.extra
|
|
1471
|
+
extraOptions: options.extra,
|
|
985
1472
|
};
|
|
986
1473
|
|
|
987
1474
|
const sendSeen = options.sendSeen !== false;
|
|
988
1475
|
|
|
989
1476
|
if (content instanceof MessageMedia) {
|
|
990
1477
|
internalOptions.media = content;
|
|
991
|
-
internalOptions.isViewOnce = options.isViewOnce,
|
|
992
|
-
content = '';
|
|
1478
|
+
((internalOptions.isViewOnce = options.isViewOnce), (content = ''));
|
|
993
1479
|
} else if (options.media instanceof MessageMedia) {
|
|
994
1480
|
internalOptions.media = options.media;
|
|
995
1481
|
internalOptions.caption = content;
|
|
996
|
-
internalOptions.isViewOnce = options.isViewOnce,
|
|
997
|
-
content = '';
|
|
1482
|
+
((internalOptions.isViewOnce = options.isViewOnce), (content = ''));
|
|
998
1483
|
} else if (content instanceof Location) {
|
|
999
1484
|
internalOptions.location = content;
|
|
1000
1485
|
content = '';
|
|
@@ -1007,48 +1492,97 @@ class Client extends EventEmitter {
|
|
|
1007
1492
|
} else if (content instanceof Contact) {
|
|
1008
1493
|
internalOptions.contactCard = content.id._serialized;
|
|
1009
1494
|
content = '';
|
|
1010
|
-
} else if (
|
|
1011
|
-
|
|
1495
|
+
} else if (
|
|
1496
|
+
Array.isArray(content) &&
|
|
1497
|
+
content.length > 0 &&
|
|
1498
|
+
content[0] instanceof Contact
|
|
1499
|
+
) {
|
|
1500
|
+
internalOptions.contactCardList = content.map(
|
|
1501
|
+
(contact) => contact.id._serialized,
|
|
1502
|
+
);
|
|
1012
1503
|
content = '';
|
|
1013
1504
|
} else if (content instanceof Buttons) {
|
|
1014
|
-
console.warn(
|
|
1015
|
-
|
|
1505
|
+
console.warn(
|
|
1506
|
+
'Buttons are now deprecated. See more at https://www.youtube.com/watch?v=hv1R1rLeVVE.',
|
|
1507
|
+
);
|
|
1508
|
+
if (content.type !== 'chat') {
|
|
1509
|
+
internalOptions.attachment = content.body;
|
|
1510
|
+
}
|
|
1016
1511
|
internalOptions.buttons = content;
|
|
1017
1512
|
content = '';
|
|
1018
1513
|
} else if (content instanceof List) {
|
|
1019
|
-
console.warn(
|
|
1514
|
+
console.warn(
|
|
1515
|
+
'Lists are now deprecated. See more at https://www.youtube.com/watch?v=hv1R1rLeVVE.',
|
|
1516
|
+
);
|
|
1020
1517
|
internalOptions.list = content;
|
|
1021
1518
|
content = '';
|
|
1022
1519
|
}
|
|
1023
1520
|
|
|
1024
1521
|
if (internalOptions.sendMediaAsSticker && internalOptions.media) {
|
|
1025
1522
|
internalOptions.media = await Util.formatToWebpSticker(
|
|
1026
|
-
internalOptions.media,
|
|
1523
|
+
internalOptions.media,
|
|
1524
|
+
{
|
|
1027
1525
|
name: options.stickerName,
|
|
1028
1526
|
author: options.stickerAuthor,
|
|
1029
|
-
categories: options.stickerCategories
|
|
1030
|
-
},
|
|
1527
|
+
categories: options.stickerCategories,
|
|
1528
|
+
},
|
|
1529
|
+
this.pupPage,
|
|
1031
1530
|
);
|
|
1032
1531
|
}
|
|
1033
1532
|
|
|
1034
|
-
const sentMsg = await this.pupPage.evaluate(
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1533
|
+
const sentMsg = await this.pupPage.evaluate(
|
|
1534
|
+
async (chatId, content, options, sendSeen) => {
|
|
1535
|
+
const chat = await window.WWebJS.getChat(chatId, {
|
|
1536
|
+
getAsModel: false,
|
|
1537
|
+
});
|
|
1038
1538
|
|
|
1039
|
-
|
|
1040
|
-
await window.WWebJS.sendSeen(chatId);
|
|
1041
|
-
}
|
|
1539
|
+
if (!chat) return null;
|
|
1042
1540
|
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
: undefined;
|
|
1047
|
-
}, chatId, content, internalOptions, sendSeen);
|
|
1541
|
+
if (sendSeen) {
|
|
1542
|
+
await window.WWebJS.sendSeen(chatId);
|
|
1543
|
+
}
|
|
1048
1544
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1545
|
+
const msg = await window.WWebJS.sendMessage(
|
|
1546
|
+
chat,
|
|
1547
|
+
content,
|
|
1548
|
+
options,
|
|
1549
|
+
);
|
|
1550
|
+
return msg ? window.WWebJS.getMessageModel(msg) : undefined;
|
|
1551
|
+
},
|
|
1552
|
+
chatId,
|
|
1553
|
+
content,
|
|
1554
|
+
internalOptions,
|
|
1555
|
+
sendSeen,
|
|
1556
|
+
);
|
|
1557
|
+
|
|
1558
|
+
return sentMsg ? new Message(this, sentMsg) : undefined;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
/**
|
|
1562
|
+
* Send an emoji reaction to a specific message
|
|
1563
|
+
* @param {string} messageId - Id of the message to add the reaction.
|
|
1564
|
+
* @param {string} reaction - Emoji to react with. Send an empty string to remove the reaction.
|
|
1565
|
+
* @return {Promise}
|
|
1566
|
+
*/
|
|
1567
|
+
async sendReaction(messageId, reaction) {
|
|
1568
|
+
await this.pupPage.evaluate(
|
|
1569
|
+
async (messageId, reaction) => {
|
|
1570
|
+
if (!messageId) return null;
|
|
1571
|
+
const msg =
|
|
1572
|
+
window.require('WAWebCollections').Msg.get(messageId) ||
|
|
1573
|
+
(
|
|
1574
|
+
await window
|
|
1575
|
+
.require('WAWebCollections')
|
|
1576
|
+
.Msg.getMessagesById([messageId])
|
|
1577
|
+
)?.messages?.[0];
|
|
1578
|
+
if (!msg) return null;
|
|
1579
|
+
await window
|
|
1580
|
+
.require('WAWebSendReactionMsgAction')
|
|
1581
|
+
.sendReactionToMsg(msg, reaction);
|
|
1582
|
+
},
|
|
1583
|
+
messageId,
|
|
1584
|
+
reaction,
|
|
1585
|
+
);
|
|
1052
1586
|
}
|
|
1053
1587
|
|
|
1054
1588
|
/**
|
|
@@ -1060,34 +1594,45 @@ class Client extends EventEmitter {
|
|
|
1060
1594
|
* Sends a channel admin invitation to a user, allowing them to become an admin of the channel
|
|
1061
1595
|
* @param {string} chatId The ID of a user to send the channel admin invitation to
|
|
1062
1596
|
* @param {string} channelId The ID of a channel for which the invitation is being sent
|
|
1063
|
-
* @param {SendChannelAdminInviteOptions} options
|
|
1597
|
+
* @param {SendChannelAdminInviteOptions} options
|
|
1064
1598
|
* @returns {Promise<boolean>} Returns true if an invitation was sent successfully, false otherwise
|
|
1065
1599
|
*/
|
|
1066
1600
|
async sendChannelAdminInvite(chatId, channelId, options = {}) {
|
|
1067
|
-
const response = await this.pupPage.evaluate(
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
newsletterWid: channelWid,
|
|
1081
|
-
invitee: chatWid,
|
|
1082
|
-
inviteMessage: options.comment,
|
|
1083
|
-
base64Thumb: await window.WWebJS.getProfilePicThumbToBase64(channelWid)
|
|
1601
|
+
const response = await this.pupPage.evaluate(
|
|
1602
|
+
async (chatId, channelId, options) => {
|
|
1603
|
+
const { createWid } = window.require('WAWebWidFactory');
|
|
1604
|
+
const channelWid = createWid(channelId);
|
|
1605
|
+
const chatWid = createWid(chatId);
|
|
1606
|
+
const chat =
|
|
1607
|
+
window.require('WAWebCollections').Chat.get(chatWid) ||
|
|
1608
|
+
(await window
|
|
1609
|
+
.require('WAWebCollections')
|
|
1610
|
+
.Chat.find(chatWid));
|
|
1611
|
+
|
|
1612
|
+
if (!chatWid.isUser()) {
|
|
1613
|
+
return false;
|
|
1084
1614
|
}
|
|
1085
|
-
|
|
1086
|
-
|
|
1615
|
+
|
|
1616
|
+
return await window
|
|
1617
|
+
.require('WAWebNewsletterSendMsgAction')
|
|
1618
|
+
.sendNewsletterAdminInviteMessage(chat, {
|
|
1619
|
+
newsletterWid: channelWid,
|
|
1620
|
+
invitee: chatWid,
|
|
1621
|
+
inviteMessage: options.comment,
|
|
1622
|
+
base64Thumb:
|
|
1623
|
+
await window.WWebJS.getProfilePicThumbToBase64(
|
|
1624
|
+
channelWid,
|
|
1625
|
+
),
|
|
1626
|
+
});
|
|
1627
|
+
},
|
|
1628
|
+
chatId,
|
|
1629
|
+
channelId,
|
|
1630
|
+
options,
|
|
1631
|
+
);
|
|
1087
1632
|
|
|
1088
1633
|
return response.messageSendResult === 'OK';
|
|
1089
1634
|
}
|
|
1090
|
-
|
|
1635
|
+
|
|
1091
1636
|
/**
|
|
1092
1637
|
* Searches for messages
|
|
1093
1638
|
* @param {string} query
|
|
@@ -1098,12 +1643,22 @@ class Client extends EventEmitter {
|
|
|
1098
1643
|
* @returns {Promise<Message[]>}
|
|
1099
1644
|
*/
|
|
1100
1645
|
async searchMessages(query, options = {}) {
|
|
1101
|
-
const messages = await this.pupPage.evaluate(
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1646
|
+
const messages = await this.pupPage.evaluate(
|
|
1647
|
+
async (query, page, count, remote) => {
|
|
1648
|
+
const { messages } = await window
|
|
1649
|
+
.require('WAWebCollections')
|
|
1650
|
+
.Msg.search(query, page, count, remote);
|
|
1651
|
+
return messages.map((msg) =>
|
|
1652
|
+
window.WWebJS.getMessageModel(msg),
|
|
1653
|
+
);
|
|
1654
|
+
},
|
|
1655
|
+
query,
|
|
1656
|
+
options.page,
|
|
1657
|
+
options.limit,
|
|
1658
|
+
options.chatId,
|
|
1659
|
+
);
|
|
1105
1660
|
|
|
1106
|
-
return messages.map(msg => new Message(this, msg));
|
|
1661
|
+
return messages.map((msg) => new Message(this, msg));
|
|
1107
1662
|
}
|
|
1108
1663
|
|
|
1109
1664
|
/**
|
|
@@ -1115,7 +1670,7 @@ class Client extends EventEmitter {
|
|
|
1115
1670
|
return await window.WWebJS.getChats();
|
|
1116
1671
|
});
|
|
1117
1672
|
|
|
1118
|
-
return chats.map(chat => ChatFactory.create(this, chat));
|
|
1673
|
+
return chats.map((chat) => ChatFactory.create(this, chat));
|
|
1119
1674
|
}
|
|
1120
1675
|
|
|
1121
1676
|
/**
|
|
@@ -1132,16 +1687,14 @@ class Client extends EventEmitter {
|
|
|
1132
1687
|
|
|
1133
1688
|
/**
|
|
1134
1689
|
* Gets chat or channel instance by ID
|
|
1135
|
-
* @param {string} chatId
|
|
1690
|
+
* @param {string} chatId
|
|
1136
1691
|
* @returns {Promise<Chat|Channel>}
|
|
1137
1692
|
*/
|
|
1138
1693
|
async getChatById(chatId) {
|
|
1139
|
-
const chat = await this.pupPage.evaluate(async chatId => {
|
|
1694
|
+
const chat = await this.pupPage.evaluate(async (chatId) => {
|
|
1140
1695
|
return await window.WWebJS.getChat(chatId);
|
|
1141
1696
|
}, chatId);
|
|
1142
|
-
return chat
|
|
1143
|
-
? ChatFactory.create(this, chat)
|
|
1144
|
-
: undefined;
|
|
1697
|
+
return chat ? ChatFactory.create(this, chat) : undefined;
|
|
1145
1698
|
}
|
|
1146
1699
|
|
|
1147
1700
|
/**
|
|
@@ -1153,7 +1706,8 @@ class Client extends EventEmitter {
|
|
|
1153
1706
|
const channel = await this.pupPage.evaluate(async (inviteCode) => {
|
|
1154
1707
|
let channelMetadata;
|
|
1155
1708
|
try {
|
|
1156
|
-
channelMetadata =
|
|
1709
|
+
channelMetadata =
|
|
1710
|
+
await window.WWebJS.getChannelMetadata(inviteCode);
|
|
1157
1711
|
} catch (err) {
|
|
1158
1712
|
if (err.name === 'ServerStatusCodeError') return null;
|
|
1159
1713
|
throw err;
|
|
@@ -1161,9 +1715,7 @@ class Client extends EventEmitter {
|
|
|
1161
1715
|
return await window.WWebJS.getChat(channelMetadata.id);
|
|
1162
1716
|
}, inviteCode);
|
|
1163
1717
|
|
|
1164
|
-
return channel
|
|
1165
|
-
? ChatFactory.create(this, channel)
|
|
1166
|
-
: undefined;
|
|
1718
|
+
return channel ? ChatFactory.create(this, channel) : undefined;
|
|
1167
1719
|
}
|
|
1168
1720
|
|
|
1169
1721
|
/**
|
|
@@ -1175,7 +1727,7 @@ class Client extends EventEmitter {
|
|
|
1175
1727
|
return window.WWebJS.getContacts();
|
|
1176
1728
|
});
|
|
1177
1729
|
|
|
1178
|
-
return contacts.map(contact => ContactFactory.create(this, contact));
|
|
1730
|
+
return contacts.map((contact) => ContactFactory.create(this, contact));
|
|
1179
1731
|
}
|
|
1180
1732
|
|
|
1181
1733
|
/**
|
|
@@ -1184,7 +1736,7 @@ class Client extends EventEmitter {
|
|
|
1184
1736
|
* @returns {Promise<Contact>}
|
|
1185
1737
|
*/
|
|
1186
1738
|
async getContactById(contactId) {
|
|
1187
|
-
let contact = await this.pupPage.evaluate(contactId => {
|
|
1739
|
+
let contact = await this.pupPage.evaluate((contactId) => {
|
|
1188
1740
|
return window.WWebJS.getContact(contactId);
|
|
1189
1741
|
}, contactId);
|
|
1190
1742
|
|
|
@@ -1197,20 +1749,24 @@ class Client extends EventEmitter {
|
|
|
1197
1749
|
* @returns {Promise<Message>}
|
|
1198
1750
|
*/
|
|
1199
1751
|
async getMessageById(messageId) {
|
|
1200
|
-
const msg = await this.pupPage.evaluate(async messageId => {
|
|
1201
|
-
let msg =
|
|
1202
|
-
if(msg) return window.WWebJS.getMessageModel(msg);
|
|
1752
|
+
const msg = await this.pupPage.evaluate(async (messageId) => {
|
|
1753
|
+
let msg = window.require('WAWebCollections').Msg.get(messageId);
|
|
1754
|
+
if (msg) return window.WWebJS.getMessageModel(msg);
|
|
1203
1755
|
|
|
1204
1756
|
const params = messageId.split('_');
|
|
1205
|
-
if (params.length !== 3 && params.length !== 4)
|
|
1757
|
+
if (params.length !== 3 && params.length !== 4)
|
|
1758
|
+
throw new Error('Invalid serialized message id specified');
|
|
1759
|
+
|
|
1760
|
+
let messagesObject = await window
|
|
1761
|
+
.require('WAWebCollections')
|
|
1762
|
+
.Msg.getMessagesById([messageId]);
|
|
1763
|
+
if (messagesObject && messagesObject.messages.length)
|
|
1764
|
+
msg = messagesObject.messages[0];
|
|
1206
1765
|
|
|
1207
|
-
|
|
1208
|
-
if (messagesObject && messagesObject.messages.length) msg = messagesObject.messages[0];
|
|
1209
|
-
|
|
1210
|
-
if(msg) return window.WWebJS.getMessageModel(msg);
|
|
1766
|
+
if (msg) return window.WWebJS.getMessageModel(msg);
|
|
1211
1767
|
}, messageId);
|
|
1212
1768
|
|
|
1213
|
-
if(msg) return new Message(this, msg);
|
|
1769
|
+
if (msg) return new Message(this, msg);
|
|
1214
1770
|
return null;
|
|
1215
1771
|
}
|
|
1216
1772
|
|
|
@@ -1222,23 +1778,36 @@ class Client extends EventEmitter {
|
|
|
1222
1778
|
async getPinnedMessages(chatId) {
|
|
1223
1779
|
const pinnedMsgs = await this.pupPage.evaluate(async (chatId) => {
|
|
1224
1780
|
const chatWid = window.require('WAWebWidFactory').createWid(chatId);
|
|
1225
|
-
const chat =
|
|
1781
|
+
const chat =
|
|
1782
|
+
window.require('WAWebCollections').Chat.get(chatWid) ??
|
|
1783
|
+
(await window.require('WAWebCollections').Chat.find(chatWid));
|
|
1226
1784
|
if (!chat) return [];
|
|
1227
|
-
|
|
1228
|
-
const msgs = await
|
|
1785
|
+
|
|
1786
|
+
const msgs = await window
|
|
1787
|
+
.require('WAWebPinInChatSchema')
|
|
1788
|
+
.getTable()
|
|
1789
|
+
.equals(['chatId'], chatWid.toString());
|
|
1229
1790
|
|
|
1230
1791
|
const pinnedMsgs = (
|
|
1231
1792
|
await Promise.all(
|
|
1232
|
-
msgs
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1793
|
+
msgs
|
|
1794
|
+
.filter((msg) => msg.pinType == 1)
|
|
1795
|
+
.map(async (msg) => {
|
|
1796
|
+
const res = await window
|
|
1797
|
+
.require('WAWebCollections')
|
|
1798
|
+
.Msg.getMessagesById([msg.parentMsgKey]);
|
|
1799
|
+
return res?.messages?.[0];
|
|
1800
|
+
}),
|
|
1236
1801
|
)
|
|
1237
1802
|
).filter(Boolean);
|
|
1238
1803
|
|
|
1239
1804
|
return !pinnedMsgs.length
|
|
1240
1805
|
? []
|
|
1241
|
-
: await Promise.all(
|
|
1806
|
+
: await Promise.all(
|
|
1807
|
+
pinnedMsgs.map((msg) =>
|
|
1808
|
+
window.WWebJS.getMessageModel(msg),
|
|
1809
|
+
),
|
|
1810
|
+
);
|
|
1242
1811
|
}, chatId);
|
|
1243
1812
|
|
|
1244
1813
|
return pinnedMsgs.map((msg) => new Message(this, msg));
|
|
@@ -1246,12 +1815,14 @@ class Client extends EventEmitter {
|
|
|
1246
1815
|
|
|
1247
1816
|
/**
|
|
1248
1817
|
* Returns an object with information about the invite code's group
|
|
1249
|
-
* @param {string} inviteCode
|
|
1818
|
+
* @param {string} inviteCode
|
|
1250
1819
|
* @returns {Promise<object>} Invite information
|
|
1251
1820
|
*/
|
|
1252
1821
|
async getInviteInfo(inviteCode) {
|
|
1253
|
-
return await this.pupPage.evaluate(inviteCode => {
|
|
1254
|
-
return
|
|
1822
|
+
return await this.pupPage.evaluate((inviteCode) => {
|
|
1823
|
+
return window
|
|
1824
|
+
.require('WAWebGroupQueryJob')
|
|
1825
|
+
.queryGroupInvite(inviteCode);
|
|
1255
1826
|
}, inviteCode);
|
|
1256
1827
|
}
|
|
1257
1828
|
|
|
@@ -1261,8 +1832,10 @@ class Client extends EventEmitter {
|
|
|
1261
1832
|
* @returns {Promise<string>} Id of the joined Chat
|
|
1262
1833
|
*/
|
|
1263
1834
|
async acceptInvite(inviteCode) {
|
|
1264
|
-
const res = await this.pupPage.evaluate(async inviteCode => {
|
|
1265
|
-
return await
|
|
1835
|
+
const res = await this.pupPage.evaluate(async (inviteCode) => {
|
|
1836
|
+
return await window
|
|
1837
|
+
.require('WAWebGroupInviteJob')
|
|
1838
|
+
.joinGroupViaInvite(inviteCode);
|
|
1266
1839
|
}, inviteCode);
|
|
1267
1840
|
|
|
1268
1841
|
return res.gid._serialized;
|
|
@@ -1276,7 +1849,9 @@ class Client extends EventEmitter {
|
|
|
1276
1849
|
async acceptChannelAdminInvite(channelId) {
|
|
1277
1850
|
return await this.pupPage.evaluate(async (channelId) => {
|
|
1278
1851
|
try {
|
|
1279
|
-
await
|
|
1852
|
+
await window
|
|
1853
|
+
.require('WAWebMexAcceptNewsletterAdminInviteJob')
|
|
1854
|
+
.acceptNewsletterAdminInvite(channelId);
|
|
1280
1855
|
return true;
|
|
1281
1856
|
} catch (err) {
|
|
1282
1857
|
if (err.name === 'ServerStatusCodeError') return false;
|
|
@@ -1292,16 +1867,24 @@ class Client extends EventEmitter {
|
|
|
1292
1867
|
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
1293
1868
|
*/
|
|
1294
1869
|
async revokeChannelAdminInvite(channelId, userId) {
|
|
1295
|
-
return await this.pupPage.evaluate(
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1870
|
+
return await this.pupPage.evaluate(
|
|
1871
|
+
async (channelId, userId) => {
|
|
1872
|
+
try {
|
|
1873
|
+
const userWid = window
|
|
1874
|
+
.require('WAWebWidFactory')
|
|
1875
|
+
.createWid(userId);
|
|
1876
|
+
await window
|
|
1877
|
+
.require('WAWebMexRevokeNewsletterAdminInviteJob')
|
|
1878
|
+
.revokeNewsletterAdminInvite(channelId, userWid);
|
|
1879
|
+
return true;
|
|
1880
|
+
} catch (err) {
|
|
1881
|
+
if (err.name === 'ServerStatusCodeError') return false;
|
|
1882
|
+
throw err;
|
|
1883
|
+
}
|
|
1884
|
+
},
|
|
1885
|
+
channelId,
|
|
1886
|
+
userId,
|
|
1887
|
+
);
|
|
1305
1888
|
}
|
|
1306
1889
|
|
|
1307
1890
|
/**
|
|
@@ -1311,16 +1894,24 @@ class Client extends EventEmitter {
|
|
|
1311
1894
|
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
1312
1895
|
*/
|
|
1313
1896
|
async demoteChannelAdmin(channelId, userId) {
|
|
1314
|
-
return await this.pupPage.evaluate(
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1897
|
+
return await this.pupPage.evaluate(
|
|
1898
|
+
async (channelId, userId) => {
|
|
1899
|
+
try {
|
|
1900
|
+
const userWid = window
|
|
1901
|
+
.require('WAWebWidFactory')
|
|
1902
|
+
.createWid(userId);
|
|
1903
|
+
await window
|
|
1904
|
+
.require('WAWebDemoteNewsletterAdminAction')
|
|
1905
|
+
.demoteNewsletterAdmin(channelId, userWid);
|
|
1906
|
+
return true;
|
|
1907
|
+
} catch (err) {
|
|
1908
|
+
if (err.name === 'ServerStatusCodeError') return false;
|
|
1909
|
+
throw err;
|
|
1910
|
+
}
|
|
1911
|
+
},
|
|
1912
|
+
channelId,
|
|
1913
|
+
userId,
|
|
1914
|
+
);
|
|
1324
1915
|
}
|
|
1325
1916
|
|
|
1326
1917
|
/**
|
|
@@ -1329,12 +1920,20 @@ class Client extends EventEmitter {
|
|
|
1329
1920
|
* @returns {Promise<Object>}
|
|
1330
1921
|
*/
|
|
1331
1922
|
async acceptGroupV4Invite(inviteInfo) {
|
|
1332
|
-
if (!inviteInfo.inviteCode)
|
|
1923
|
+
if (!inviteInfo.inviteCode)
|
|
1924
|
+
throw 'Invalid invite code, try passing the message.inviteV4 object';
|
|
1333
1925
|
if (inviteInfo.inviteCodeExp == 0) throw 'Expired invite code';
|
|
1334
|
-
return this.pupPage.evaluate(async inviteInfo => {
|
|
1926
|
+
return this.pupPage.evaluate(async (inviteInfo) => {
|
|
1335
1927
|
let { groupId, fromId, inviteCode, inviteCodeExp } = inviteInfo;
|
|
1336
1928
|
let userWid = window.require('WAWebWidFactory').createWid(fromId);
|
|
1337
|
-
return await
|
|
1929
|
+
return await window
|
|
1930
|
+
.require('WAWebGroupInviteV4Job')
|
|
1931
|
+
.joinGroupViaInviteV4(
|
|
1932
|
+
inviteCode,
|
|
1933
|
+
String(inviteCodeExp),
|
|
1934
|
+
groupId,
|
|
1935
|
+
userWid,
|
|
1936
|
+
);
|
|
1338
1937
|
}, inviteInfo);
|
|
1339
1938
|
}
|
|
1340
1939
|
|
|
@@ -1343,30 +1942,35 @@ class Client extends EventEmitter {
|
|
|
1343
1942
|
* @param {string} status New status message
|
|
1344
1943
|
*/
|
|
1345
1944
|
async setStatus(status) {
|
|
1346
|
-
await this.pupPage.evaluate(async status => {
|
|
1347
|
-
return await
|
|
1945
|
+
await this.pupPage.evaluate(async (status) => {
|
|
1946
|
+
return await window
|
|
1947
|
+
.require('WAWebContactStatusBridge')
|
|
1948
|
+
.setMyStatus(status);
|
|
1348
1949
|
}, status);
|
|
1349
1950
|
}
|
|
1350
1951
|
|
|
1351
1952
|
/**
|
|
1352
|
-
* Sets the current user's display name.
|
|
1953
|
+
* Sets the current user's display name.
|
|
1353
1954
|
* This is the name shown to WhatsApp users that have not added you as a contact beside your number in groups and in your profile.
|
|
1354
1955
|
* @param {string} displayName New display name
|
|
1355
1956
|
* @returns {Promise<Boolean>}
|
|
1356
1957
|
*/
|
|
1357
1958
|
async setDisplayName(displayName) {
|
|
1358
|
-
const couldSet = await this.pupPage.evaluate(async displayName => {
|
|
1359
|
-
if(!
|
|
1360
|
-
|
|
1959
|
+
const couldSet = await this.pupPage.evaluate(async (displayName) => {
|
|
1960
|
+
if (!window.require('WAWebConnModel').Conn.canSetMyPushname())
|
|
1961
|
+
return false;
|
|
1962
|
+
await window
|
|
1963
|
+
.require('WAWebSetPushnameConnAction')
|
|
1964
|
+
.setPushname(displayName);
|
|
1361
1965
|
return true;
|
|
1362
1966
|
}, displayName);
|
|
1363
1967
|
|
|
1364
1968
|
return couldSet;
|
|
1365
1969
|
}
|
|
1366
|
-
|
|
1970
|
+
|
|
1367
1971
|
/**
|
|
1368
1972
|
* Gets the current connection state for the client
|
|
1369
|
-
* @returns {WAState}
|
|
1973
|
+
* @returns {WAState}
|
|
1370
1974
|
*/
|
|
1371
1975
|
async getState() {
|
|
1372
1976
|
return await this.pupPage.evaluate(() => {
|
|
@@ -1379,7 +1983,9 @@ class Client extends EventEmitter {
|
|
|
1379
1983
|
*/
|
|
1380
1984
|
async sendPresenceAvailable() {
|
|
1381
1985
|
return await this.pupPage.evaluate(() => {
|
|
1382
|
-
return window
|
|
1986
|
+
return window
|
|
1987
|
+
.require('WAWebPresenceChatAction')
|
|
1988
|
+
.sendPresenceAvailable();
|
|
1383
1989
|
});
|
|
1384
1990
|
}
|
|
1385
1991
|
|
|
@@ -1388,7 +1994,9 @@ class Client extends EventEmitter {
|
|
|
1388
1994
|
*/
|
|
1389
1995
|
async sendPresenceUnavailable() {
|
|
1390
1996
|
return await this.pupPage.evaluate(() => {
|
|
1391
|
-
return window
|
|
1997
|
+
return window
|
|
1998
|
+
.require('WAWebPresenceChatAction')
|
|
1999
|
+
.sendPresenceUnavailable();
|
|
1392
2000
|
});
|
|
1393
2001
|
}
|
|
1394
2002
|
|
|
@@ -1397,9 +2005,11 @@ class Client extends EventEmitter {
|
|
|
1397
2005
|
* @returns {boolean}
|
|
1398
2006
|
*/
|
|
1399
2007
|
async archiveChat(chatId) {
|
|
1400
|
-
return await this.pupPage.evaluate(async chatId => {
|
|
1401
|
-
let chat = await window.WWebJS.getChat(chatId, {
|
|
1402
|
-
|
|
2008
|
+
return await this.pupPage.evaluate(async (chatId) => {
|
|
2009
|
+
let chat = await window.WWebJS.getChat(chatId, {
|
|
2010
|
+
getAsModel: false,
|
|
2011
|
+
});
|
|
2012
|
+
await window.require('WAWebCmd').Cmd.archiveChat(chat, true);
|
|
1403
2013
|
return true;
|
|
1404
2014
|
}, chatId);
|
|
1405
2015
|
}
|
|
@@ -1409,9 +2019,11 @@ class Client extends EventEmitter {
|
|
|
1409
2019
|
* @returns {boolean}
|
|
1410
2020
|
*/
|
|
1411
2021
|
async unarchiveChat(chatId) {
|
|
1412
|
-
return await this.pupPage.evaluate(async chatId => {
|
|
1413
|
-
let chat = await window.WWebJS.getChat(chatId, {
|
|
1414
|
-
|
|
2022
|
+
return await this.pupPage.evaluate(async (chatId) => {
|
|
2023
|
+
let chat = await window.WWebJS.getChat(chatId, {
|
|
2024
|
+
getAsModel: false,
|
|
2025
|
+
});
|
|
2026
|
+
await window.require('WAWebCmd').Cmd.archiveChat(chat, false);
|
|
1415
2027
|
return false;
|
|
1416
2028
|
}, chatId);
|
|
1417
2029
|
}
|
|
@@ -1421,20 +2033,24 @@ class Client extends EventEmitter {
|
|
|
1421
2033
|
* @returns {Promise<boolean>} New pin state. Could be false if the max number of pinned chats was reached.
|
|
1422
2034
|
*/
|
|
1423
2035
|
async pinChat(chatId) {
|
|
1424
|
-
return this.pupPage.evaluate(async chatId => {
|
|
1425
|
-
let chat = await window.WWebJS.getChat(chatId, {
|
|
2036
|
+
return this.pupPage.evaluate(async (chatId) => {
|
|
2037
|
+
let chat = await window.WWebJS.getChat(chatId, {
|
|
2038
|
+
getAsModel: false,
|
|
2039
|
+
});
|
|
1426
2040
|
if (chat.pin) {
|
|
1427
2041
|
return true;
|
|
1428
2042
|
}
|
|
1429
2043
|
const MAX_PIN_COUNT = 3;
|
|
1430
|
-
const chatModels =
|
|
2044
|
+
const chatModels = window
|
|
2045
|
+
.require('WAWebCollections')
|
|
2046
|
+
.Chat.getModelsArray();
|
|
1431
2047
|
if (chatModels.length > MAX_PIN_COUNT) {
|
|
1432
2048
|
let maxPinned = chatModels[MAX_PIN_COUNT - 1].pin;
|
|
1433
2049
|
if (maxPinned) {
|
|
1434
2050
|
return false;
|
|
1435
2051
|
}
|
|
1436
2052
|
}
|
|
1437
|
-
await
|
|
2053
|
+
await window.require('WAWebCmd').Cmd.pinChat(chat, true);
|
|
1438
2054
|
return true;
|
|
1439
2055
|
}, chatId);
|
|
1440
2056
|
}
|
|
@@ -1444,12 +2060,14 @@ class Client extends EventEmitter {
|
|
|
1444
2060
|
* @returns {Promise<boolean>} New pin state
|
|
1445
2061
|
*/
|
|
1446
2062
|
async unpinChat(chatId) {
|
|
1447
|
-
return this.pupPage.evaluate(async chatId => {
|
|
1448
|
-
let chat = await window.WWebJS.getChat(chatId, {
|
|
2063
|
+
return this.pupPage.evaluate(async (chatId) => {
|
|
2064
|
+
let chat = await window.WWebJS.getChat(chatId, {
|
|
2065
|
+
getAsModel: false,
|
|
2066
|
+
});
|
|
1449
2067
|
if (!chat.pin) {
|
|
1450
2068
|
return false;
|
|
1451
2069
|
}
|
|
1452
|
-
await
|
|
2070
|
+
await window.require('WAWebCmd').Cmd.pinChat(chat, false);
|
|
1453
2071
|
return false;
|
|
1454
2072
|
}, chatId);
|
|
1455
2073
|
}
|
|
@@ -1481,14 +2099,29 @@ class Client extends EventEmitter {
|
|
|
1481
2099
|
* @param {number} unmuteDateTs Timestamp at which the chat will be unmuted
|
|
1482
2100
|
* @returns {Promise<{isMuted: boolean, muteExpiration: number}>}
|
|
1483
2101
|
*/
|
|
1484
|
-
async _muteUnmuteChat
|
|
1485
|
-
return this.pupPage.evaluate(
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
2102
|
+
async _muteUnmuteChat(chatId, action, unmuteDateTs) {
|
|
2103
|
+
return this.pupPage.evaluate(
|
|
2104
|
+
async (chatId, action, unmuteDateTs) => {
|
|
2105
|
+
const chat =
|
|
2106
|
+
window.require('WAWebCollections').Chat.get(chatId) ??
|
|
2107
|
+
(await window
|
|
2108
|
+
.require('WAWebCollections')
|
|
2109
|
+
.Chat.find(chatId));
|
|
2110
|
+
action === 'MUTE'
|
|
2111
|
+
? await chat.mute.mute({
|
|
2112
|
+
expiration: unmuteDateTs,
|
|
2113
|
+
sendDevice: true,
|
|
2114
|
+
})
|
|
2115
|
+
: await chat.mute.unmute({ sendDevice: true });
|
|
2116
|
+
return {
|
|
2117
|
+
isMuted: chat.mute.expiration !== 0,
|
|
2118
|
+
muteExpiration: chat.mute.expiration,
|
|
2119
|
+
};
|
|
2120
|
+
},
|
|
2121
|
+
chatId,
|
|
2122
|
+
action,
|
|
2123
|
+
unmuteDateTs || -1,
|
|
2124
|
+
);
|
|
1492
2125
|
}
|
|
1493
2126
|
|
|
1494
2127
|
/**
|
|
@@ -1496,9 +2129,11 @@ class Client extends EventEmitter {
|
|
|
1496
2129
|
* @param {string} chatId ID of the chat that will be marked as unread
|
|
1497
2130
|
*/
|
|
1498
2131
|
async markChatUnread(chatId) {
|
|
1499
|
-
await this.pupPage.evaluate(async chatId => {
|
|
1500
|
-
let chat = await window.WWebJS.getChat(chatId, {
|
|
1501
|
-
|
|
2132
|
+
await this.pupPage.evaluate(async (chatId) => {
|
|
2133
|
+
let chat = await window.WWebJS.getChat(chatId, {
|
|
2134
|
+
getAsModel: false,
|
|
2135
|
+
});
|
|
2136
|
+
await window.require('WAWebCmd').Cmd.markChatUnread(chat, true);
|
|
1502
2137
|
}, chatId);
|
|
1503
2138
|
}
|
|
1504
2139
|
|
|
@@ -1508,18 +2143,18 @@ class Client extends EventEmitter {
|
|
|
1508
2143
|
* @returns {Promise<string>}
|
|
1509
2144
|
*/
|
|
1510
2145
|
async getProfilePicUrl(contactId) {
|
|
1511
|
-
const profilePic = await this.pupPage.evaluate(async contactId => {
|
|
2146
|
+
const profilePic = await this.pupPage.evaluate(async (contactId) => {
|
|
1512
2147
|
try {
|
|
1513
|
-
const
|
|
1514
|
-
return window
|
|
1515
|
-
|
|
1516
|
-
|
|
2148
|
+
const chat = await window.WWebJS.getChat(contactId);
|
|
2149
|
+
return await window
|
|
2150
|
+
.require('WAWebContactProfilePicThumbBridge')
|
|
2151
|
+
.requestProfilePicFromServer(chat);
|
|
1517
2152
|
} catch (err) {
|
|
1518
|
-
if(err.name === 'ServerStatusCodeError') return undefined;
|
|
2153
|
+
if (err.name === 'ServerStatusCodeError') return undefined;
|
|
1519
2154
|
throw err;
|
|
1520
2155
|
}
|
|
1521
2156
|
}, contactId);
|
|
1522
|
-
|
|
2157
|
+
|
|
1523
2158
|
return profilePic ? profilePic.eurl : undefined;
|
|
1524
2159
|
}
|
|
1525
2160
|
|
|
@@ -1530,17 +2165,26 @@ class Client extends EventEmitter {
|
|
|
1530
2165
|
*/
|
|
1531
2166
|
async getCommonGroups(contactId) {
|
|
1532
2167
|
const commonGroups = await this.pupPage.evaluate(async (contactId) => {
|
|
1533
|
-
let contact =
|
|
2168
|
+
let contact = window
|
|
2169
|
+
.require('WAWebCollections')
|
|
2170
|
+
.Contact.get(contactId);
|
|
1534
2171
|
if (!contact) {
|
|
1535
|
-
const wid = window
|
|
1536
|
-
|
|
1537
|
-
|
|
2172
|
+
const wid = window
|
|
2173
|
+
.require('WAWebWidFactory')
|
|
2174
|
+
.createWid(contactId);
|
|
2175
|
+
const chatConstructor = window
|
|
2176
|
+
.require('WAWebCollections')
|
|
2177
|
+
.Contact.getModelsArray()
|
|
2178
|
+
.find((c) => !c.isGroup).constructor;
|
|
2179
|
+
contact = new chatConstructor({ id: wid });
|
|
1538
2180
|
}
|
|
1539
2181
|
|
|
1540
2182
|
if (contact.commonGroups) {
|
|
1541
2183
|
return contact.commonGroups.serialize();
|
|
1542
2184
|
}
|
|
1543
|
-
const status = await
|
|
2185
|
+
const status = await window
|
|
2186
|
+
.require('WAWebFindCommonGroupsContactAction')
|
|
2187
|
+
.findCommonGroups(contact);
|
|
1544
2188
|
if (status) {
|
|
1545
2189
|
return contact.commonGroups.serialize();
|
|
1546
2190
|
}
|
|
@@ -1555,10 +2199,10 @@ class Client extends EventEmitter {
|
|
|
1555
2199
|
|
|
1556
2200
|
/**
|
|
1557
2201
|
* Force reset of connection state for the client
|
|
1558
|
-
|
|
2202
|
+
*/
|
|
1559
2203
|
async resetState() {
|
|
1560
2204
|
await this.pupPage.evaluate(() => {
|
|
1561
|
-
window.require('WAWebSocketModel').Socket.reconnect();
|
|
2205
|
+
window.require('WAWebSocketModel').Socket.reconnect();
|
|
1562
2206
|
});
|
|
1563
2207
|
}
|
|
1564
2208
|
|
|
@@ -1572,7 +2216,7 @@ class Client extends EventEmitter {
|
|
|
1572
2216
|
}
|
|
1573
2217
|
|
|
1574
2218
|
/**
|
|
1575
|
-
* Get the registered WhatsApp ID for a number.
|
|
2219
|
+
* Get the registered WhatsApp ID for a number.
|
|
1576
2220
|
* Will return null if the number is not registered on WhatsApp.
|
|
1577
2221
|
* @param {string} number Number or ID ("@c.us" will be automatically appended if not specified)
|
|
1578
2222
|
* @returns {Promise<Object|null>}
|
|
@@ -1582,9 +2226,11 @@ class Client extends EventEmitter {
|
|
|
1582
2226
|
number += '@c.us';
|
|
1583
2227
|
}
|
|
1584
2228
|
|
|
1585
|
-
return await this.pupPage.evaluate(async number => {
|
|
2229
|
+
return await this.pupPage.evaluate(async (number) => {
|
|
1586
2230
|
const wid = window.require('WAWebWidFactory').createWid(number);
|
|
1587
|
-
const result = await
|
|
2231
|
+
const result = await window
|
|
2232
|
+
.require('WAWebQueryExistsJob')
|
|
2233
|
+
.queryWidExists(wid);
|
|
1588
2234
|
if (!result || result.wid === undefined) return null;
|
|
1589
2235
|
return result.wid;
|
|
1590
2236
|
}, number);
|
|
@@ -1596,11 +2242,15 @@ class Client extends EventEmitter {
|
|
|
1596
2242
|
* @returns {Promise<string>}
|
|
1597
2243
|
*/
|
|
1598
2244
|
async getFormattedNumber(number) {
|
|
1599
|
-
if (!number.endsWith('@s.whatsapp.net'))
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
2245
|
+
if (!number.endsWith('@s.whatsapp.net'))
|
|
2246
|
+
number = number.replace('c.us', 's.whatsapp.net');
|
|
2247
|
+
if (!number.includes('@s.whatsapp.net'))
|
|
2248
|
+
number = `${number}@s.whatsapp.net`;
|
|
2249
|
+
|
|
2250
|
+
return await this.pupPage.evaluate(async (numberId) => {
|
|
2251
|
+
return window
|
|
2252
|
+
.require('WAWebPhoneUtils')
|
|
2253
|
+
.formattedPhoneNumber(numberId);
|
|
1604
2254
|
}, number);
|
|
1605
2255
|
}
|
|
1606
2256
|
|
|
@@ -1612,7 +2262,7 @@ class Client extends EventEmitter {
|
|
|
1612
2262
|
async getCountryCode(number) {
|
|
1613
2263
|
number = number.replace(' ', '').replace('+', '').replace('@c.us', '');
|
|
1614
2264
|
|
|
1615
|
-
return await this.pupPage.evaluate(async numberId => {
|
|
2265
|
+
return await this.pupPage.evaluate(async (numberId) => {
|
|
1616
2266
|
return window.require('WAPhoneFindCC').findCC(numberId);
|
|
1617
2267
|
}, number);
|
|
1618
2268
|
}
|
|
@@ -1659,92 +2309,137 @@ class Client extends EventEmitter {
|
|
|
1659
2309
|
*/
|
|
1660
2310
|
async createGroup(title, participants = [], options = {}) {
|
|
1661
2311
|
!Array.isArray(participants) && (participants = [participants]);
|
|
1662
|
-
participants.map(p => (p instanceof Contact
|
|
1663
|
-
|
|
1664
|
-
return await this.pupPage.evaluate(
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
2312
|
+
participants.map((p) => (p instanceof Contact ? p.id._serialized : p));
|
|
2313
|
+
|
|
2314
|
+
return await this.pupPage.evaluate(
|
|
2315
|
+
async (title, participants, options) => {
|
|
2316
|
+
const {
|
|
2317
|
+
messageTimer = 0,
|
|
2318
|
+
parentGroupId,
|
|
2319
|
+
autoSendInviteV4 = true,
|
|
2320
|
+
comment = '',
|
|
2321
|
+
} = options;
|
|
2322
|
+
const participantData = {},
|
|
2323
|
+
participantWids = [],
|
|
2324
|
+
failedParticipants = [];
|
|
2325
|
+
let createGroupResult, parentGroupWid;
|
|
2326
|
+
|
|
2327
|
+
const addParticipantResultCodes = {
|
|
2328
|
+
default:
|
|
2329
|
+
'An unknown error occupied while adding a participant',
|
|
2330
|
+
200: 'The participant was added successfully',
|
|
2331
|
+
403: 'The participant can be added by sending private invitation only',
|
|
2332
|
+
404: 'The phone number is not registered on WhatsApp',
|
|
2333
|
+
};
|
|
2334
|
+
|
|
2335
|
+
for (const participant of participants) {
|
|
2336
|
+
const pWid = window
|
|
2337
|
+
.require('WAWebWidFactory')
|
|
2338
|
+
.createWid(participant);
|
|
2339
|
+
if (
|
|
2340
|
+
(
|
|
2341
|
+
await window
|
|
2342
|
+
.require('WAWebQueryExistsJob')
|
|
2343
|
+
.queryWidExists(pWid)
|
|
2344
|
+
)?.wid
|
|
2345
|
+
) {
|
|
2346
|
+
participantWids.push({ phoneNumber: pWid });
|
|
2347
|
+
} else failedParticipants.push(participant);
|
|
1685
2348
|
}
|
|
1686
|
-
else failedParticipants.push(participant);
|
|
1687
|
-
}
|
|
1688
2349
|
|
|
1689
|
-
|
|
2350
|
+
parentGroupId &&
|
|
2351
|
+
(parentGroupWid = window
|
|
2352
|
+
.require('WAWebWidFactory')
|
|
2353
|
+
.createWid(parentGroupId));
|
|
2354
|
+
|
|
2355
|
+
try {
|
|
2356
|
+
createGroupResult = await window
|
|
2357
|
+
.require('WAWebGroupCreateJob')
|
|
2358
|
+
.createGroup(
|
|
2359
|
+
{
|
|
2360
|
+
addressingModeOverride: 'lid',
|
|
2361
|
+
memberAddMode: options.memberAddMode ?? false,
|
|
2362
|
+
membershipApprovalMode:
|
|
2363
|
+
options.membershipApprovalMode ?? false,
|
|
2364
|
+
announce: options.announce ?? false,
|
|
2365
|
+
restrict:
|
|
2366
|
+
options.isRestrict !== undefined
|
|
2367
|
+
? !options.isRestrict
|
|
2368
|
+
: false,
|
|
2369
|
+
ephemeralDuration: messageTimer,
|
|
2370
|
+
parentGroupId: parentGroupWid,
|
|
2371
|
+
title: title,
|
|
2372
|
+
},
|
|
2373
|
+
participantWids,
|
|
2374
|
+
);
|
|
2375
|
+
} catch (ignoredError) {
|
|
2376
|
+
return 'CreateGroupError: An unknown error occupied while creating a group';
|
|
2377
|
+
}
|
|
1690
2378
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
2379
|
+
for (const participant of createGroupResult.participants) {
|
|
2380
|
+
let isInviteV4Sent = false;
|
|
2381
|
+
participant.wid.server == 'lid' &&
|
|
2382
|
+
(participant.wid = window
|
|
2383
|
+
.require('WAWebApiContact')
|
|
2384
|
+
.getPhoneNumber(participant.wid));
|
|
2385
|
+
const participantId = participant.wid._serialized;
|
|
2386
|
+
const statusCode = participant.error || 200;
|
|
2387
|
+
|
|
2388
|
+
if (autoSendInviteV4 && statusCode === 403) {
|
|
2389
|
+
window
|
|
2390
|
+
.require('WAWebCollections')
|
|
2391
|
+
.Contact.gadd(participant.wid, { silent: true });
|
|
2392
|
+
const addParticipantResult = await window
|
|
2393
|
+
.require('WAWebChatSendMessages')
|
|
2394
|
+
.sendGroupInviteMessage(
|
|
2395
|
+
window
|
|
2396
|
+
.require('WAWebCollections')
|
|
2397
|
+
.Chat.get(participant.wid) ||
|
|
2398
|
+
(await window
|
|
2399
|
+
.require('WAWebCollections')
|
|
2400
|
+
.Chat.find(participant.wid)),
|
|
2401
|
+
createGroupResult.wid._serialized,
|
|
2402
|
+
createGroupResult.subject,
|
|
2403
|
+
participant.invite_code,
|
|
2404
|
+
participant.invite_code_exp,
|
|
2405
|
+
comment,
|
|
2406
|
+
await window.WWebJS.getProfilePicThumbToBase64(
|
|
2407
|
+
createGroupResult.wid,
|
|
2408
|
+
),
|
|
2409
|
+
);
|
|
2410
|
+
isInviteV4Sent =
|
|
2411
|
+
addParticipantResult.messageSendResult === 'OK';
|
|
2412
|
+
}
|
|
1708
2413
|
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
const addParticipantResult = await (window.require('WAWebChatSendMessages')).sendGroupInviteMessage(
|
|
1718
|
-
(window.require('WAWebCollections')).Chat.get(participant.wid) || await (window.require('WAWebCollections')).Chat.find(participant.wid),
|
|
1719
|
-
createGroupResult.wid._serialized,
|
|
1720
|
-
createGroupResult.subject,
|
|
1721
|
-
participant.invite_code,
|
|
1722
|
-
participant.invite_code_exp,
|
|
1723
|
-
comment,
|
|
1724
|
-
await window.WWebJS.getProfilePicThumbToBase64(createGroupResult.wid)
|
|
1725
|
-
);
|
|
1726
|
-
isInviteV4Sent = addParticipantResult.messageSendResult === 'OK';
|
|
2414
|
+
participantData[participantId] = {
|
|
2415
|
+
statusCode: statusCode,
|
|
2416
|
+
message:
|
|
2417
|
+
addParticipantResultCodes[statusCode] ||
|
|
2418
|
+
addParticipantResultCodes.default,
|
|
2419
|
+
isGroupCreator: participant.type === 'superadmin',
|
|
2420
|
+
isInviteV4Sent: isInviteV4Sent,
|
|
2421
|
+
};
|
|
1727
2422
|
}
|
|
1728
2423
|
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
2424
|
+
for (const f of failedParticipants) {
|
|
2425
|
+
participantData[f] = {
|
|
2426
|
+
statusCode: 404,
|
|
2427
|
+
message: addParticipantResultCodes[404],
|
|
2428
|
+
isGroupCreator: false,
|
|
2429
|
+
isInviteV4Sent: false,
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
1736
2432
|
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
isGroupCreator: false,
|
|
1742
|
-
isInviteV4Sent: false
|
|
2433
|
+
return {
|
|
2434
|
+
title: title,
|
|
2435
|
+
gid: createGroupResult.wid,
|
|
2436
|
+
participants: participantData,
|
|
1743
2437
|
};
|
|
1744
|
-
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2438
|
+
},
|
|
2439
|
+
title,
|
|
2440
|
+
participants,
|
|
2441
|
+
options,
|
|
2442
|
+
);
|
|
1748
2443
|
}
|
|
1749
2444
|
|
|
1750
2445
|
/**
|
|
@@ -1769,46 +2464,61 @@ class Client extends EventEmitter {
|
|
|
1769
2464
|
/**
|
|
1770
2465
|
* Creates a new channel
|
|
1771
2466
|
* @param {string} title The channel name
|
|
1772
|
-
* @param {CreateChannelOptions} options
|
|
2467
|
+
* @param {CreateChannelOptions} options
|
|
1773
2468
|
* @returns {Promise<CreateChannelResult|string>} Returns an object that handles the result for the channel creation or an error message as a string
|
|
1774
2469
|
*/
|
|
1775
2470
|
async createChannel(title, options = {}) {
|
|
1776
|
-
return await this.pupPage.evaluate(
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
2471
|
+
return await this.pupPage.evaluate(
|
|
2472
|
+
async (title, options) => {
|
|
2473
|
+
let response,
|
|
2474
|
+
{ description = null, picture = null } = options;
|
|
2475
|
+
|
|
2476
|
+
if (
|
|
2477
|
+
!window
|
|
2478
|
+
.require('WAWebNewsletterGatingUtils')
|
|
2479
|
+
.isNewsletterCreationEnabled()
|
|
2480
|
+
) {
|
|
2481
|
+
return 'CreateChannelError: A channel creation is not enabled';
|
|
2482
|
+
}
|
|
1782
2483
|
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
2484
|
+
if (picture) {
|
|
2485
|
+
picture = await window.WWebJS.cropAndResizeImage(picture, {
|
|
2486
|
+
asDataUrl: true,
|
|
2487
|
+
mimetype: 'image/jpeg',
|
|
2488
|
+
size: 640,
|
|
2489
|
+
quality: 1,
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
1791
2492
|
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
2493
|
+
try {
|
|
2494
|
+
response = await window
|
|
2495
|
+
.require('WAWebNewsletterCreateQueryJob')
|
|
2496
|
+
.createNewsletterQuery({
|
|
2497
|
+
name: title,
|
|
2498
|
+
description: description,
|
|
2499
|
+
picture: picture,
|
|
2500
|
+
});
|
|
2501
|
+
} catch (err) {
|
|
2502
|
+
if (err.name === 'ServerStatusCodeError') {
|
|
2503
|
+
return 'CreateChannelError: An error occupied while creating a channel';
|
|
2504
|
+
}
|
|
2505
|
+
throw err;
|
|
1801
2506
|
}
|
|
1802
|
-
throw err;
|
|
1803
|
-
}
|
|
1804
2507
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
2508
|
+
return {
|
|
2509
|
+
title: title,
|
|
2510
|
+
nid: window
|
|
2511
|
+
.require('WAWebJidToWid')
|
|
2512
|
+
.newsletterJidToWid(response.idJid),
|
|
2513
|
+
inviteLink: `https://whatsapp.com/channel/${response.newsletterInviteLinkMetadataMixin.inviteCode}`,
|
|
2514
|
+
createdAtTs:
|
|
2515
|
+
response.newsletterCreationTimeMetadataMixin
|
|
2516
|
+
.creationTimeValue,
|
|
2517
|
+
};
|
|
2518
|
+
},
|
|
2519
|
+
title,
|
|
2520
|
+
options,
|
|
2521
|
+
);
|
|
1812
2522
|
}
|
|
1813
2523
|
|
|
1814
2524
|
/**
|
|
@@ -1818,7 +2528,10 @@ class Client extends EventEmitter {
|
|
|
1818
2528
|
*/
|
|
1819
2529
|
async subscribeToChannel(channelId) {
|
|
1820
2530
|
return await this.pupPage.evaluate(async (channelId) => {
|
|
1821
|
-
return await window.WWebJS.subscribeToUnsubscribeFromChannel(
|
|
2531
|
+
return await window.WWebJS.subscribeToUnsubscribeFromChannel(
|
|
2532
|
+
channelId,
|
|
2533
|
+
'Subscribe',
|
|
2534
|
+
);
|
|
1822
2535
|
}, channelId);
|
|
1823
2536
|
}
|
|
1824
2537
|
|
|
@@ -1835,9 +2548,17 @@ class Client extends EventEmitter {
|
|
|
1835
2548
|
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
1836
2549
|
*/
|
|
1837
2550
|
async unsubscribeFromChannel(channelId, options) {
|
|
1838
|
-
return await this.pupPage.evaluate(
|
|
1839
|
-
|
|
1840
|
-
|
|
2551
|
+
return await this.pupPage.evaluate(
|
|
2552
|
+
async (channelId, options) => {
|
|
2553
|
+
return await window.WWebJS.subscribeToUnsubscribeFromChannel(
|
|
2554
|
+
channelId,
|
|
2555
|
+
'Unsubscribe',
|
|
2556
|
+
options,
|
|
2557
|
+
);
|
|
2558
|
+
},
|
|
2559
|
+
channelId,
|
|
2560
|
+
options,
|
|
2561
|
+
);
|
|
1841
2562
|
}
|
|
1842
2563
|
|
|
1843
2564
|
/**
|
|
@@ -1855,26 +2576,51 @@ class Client extends EventEmitter {
|
|
|
1855
2576
|
* @returns {Promise<boolean>} Returns true if the operation completed successfully, false otherwise
|
|
1856
2577
|
*/
|
|
1857
2578
|
async transferChannelOwnership(channelId, newOwnerId, options = {}) {
|
|
1858
|
-
return await this.pupPage.evaluate(
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2579
|
+
return await this.pupPage.evaluate(
|
|
2580
|
+
async (channelId, newOwnerId, options) => {
|
|
2581
|
+
const channel = await window.WWebJS.getChat(channelId, {
|
|
2582
|
+
getAsModel: false,
|
|
2583
|
+
});
|
|
2584
|
+
const newOwner =
|
|
2585
|
+
window
|
|
2586
|
+
.require('WAWebCollections')
|
|
2587
|
+
.Contact.get(newOwnerId) ||
|
|
2588
|
+
(await window
|
|
2589
|
+
.require('WAWebCollections')
|
|
2590
|
+
.Contact.find(newOwnerId));
|
|
2591
|
+
if (!channel.newsletterMetadata) {
|
|
2592
|
+
await window
|
|
2593
|
+
.require('WAWebCollections')
|
|
2594
|
+
.NewsletterMetadataCollection.update(channel.id);
|
|
2595
|
+
}
|
|
1867
2596
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
2597
|
+
try {
|
|
2598
|
+
await window
|
|
2599
|
+
.require('WAWebChangeNewsletterOwnerAction')
|
|
2600
|
+
.changeNewsletterOwnerAction(channel, newOwner);
|
|
2601
|
+
|
|
2602
|
+
if (options.shouldDismissSelfAsAdmin) {
|
|
2603
|
+
const meContact = window
|
|
2604
|
+
.require('WAWebContactCollection')
|
|
2605
|
+
.getMeContact();
|
|
2606
|
+
meContact &&
|
|
2607
|
+
(await window
|
|
2608
|
+
.require('WAWebNewsletterDemoteAdminJob')
|
|
2609
|
+
.demoteNewsletterAdminAction(
|
|
2610
|
+
channel,
|
|
2611
|
+
meContact,
|
|
2612
|
+
));
|
|
2613
|
+
}
|
|
2614
|
+
} catch (ignoredError) {
|
|
2615
|
+
return false;
|
|
1871
2616
|
}
|
|
1872
|
-
} catch (error) {
|
|
1873
|
-
return false;
|
|
1874
|
-
}
|
|
1875
2617
|
|
|
1876
|
-
|
|
1877
|
-
|
|
2618
|
+
return true;
|
|
2619
|
+
},
|
|
2620
|
+
channelId,
|
|
2621
|
+
newOwnerId,
|
|
2622
|
+
options,
|
|
2623
|
+
);
|
|
1878
2624
|
}
|
|
1879
2625
|
|
|
1880
2626
|
/**
|
|
@@ -1897,51 +2643,78 @@ class Client extends EventEmitter {
|
|
|
1897
2643
|
* @returns {Promise<Array<Channel>>} Returns an array of Channel objects or an empty array if no channels were found
|
|
1898
2644
|
*/
|
|
1899
2645
|
async searchChannels(searchOptions = {}) {
|
|
1900
|
-
return await this.pupPage.evaluate(
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2646
|
+
return await this.pupPage.evaluate(
|
|
2647
|
+
async ({
|
|
2648
|
+
searchText = '',
|
|
2649
|
+
countryCodes = [],
|
|
2650
|
+
skipSubscribedNewsletters = false,
|
|
2651
|
+
view = 0,
|
|
2652
|
+
limit = 50,
|
|
2653
|
+
}) => {
|
|
2654
|
+
searchText = searchText.trim();
|
|
2655
|
+
const currentRegion = window.require('WAWebL10N').getRegion();
|
|
2656
|
+
if (countryCodes.length === 0) countryCodes[0] = currentRegion;
|
|
2657
|
+
if (![0, 1, 2, 3].includes(view)) view = 0;
|
|
2658
|
+
|
|
2659
|
+
const { countryCodesIso } = window.require(
|
|
2660
|
+
'WAWebCountriesNativeCountryNames',
|
|
2661
|
+
);
|
|
2662
|
+
|
|
2663
|
+
countryCodes =
|
|
2664
|
+
countryCodes.length === 1 &&
|
|
2665
|
+
countryCodes[0] === currentRegion
|
|
2666
|
+
? countryCodes
|
|
2667
|
+
: countryCodes.filter((code) =>
|
|
2668
|
+
Object.keys(countryCodesIso).includes(code),
|
|
2669
|
+
);
|
|
2670
|
+
|
|
2671
|
+
const viewTypeMapping = {
|
|
2672
|
+
0: 'RECOMMENDED',
|
|
2673
|
+
1: 'TRENDING',
|
|
2674
|
+
2: 'POPULAR',
|
|
2675
|
+
3: 'NEW',
|
|
2676
|
+
};
|
|
2677
|
+
|
|
2678
|
+
searchOptions = {
|
|
2679
|
+
searchText: searchText,
|
|
2680
|
+
countryCodes: countryCodes,
|
|
2681
|
+
skipSubscribedNewsletters: skipSubscribedNewsletters,
|
|
2682
|
+
view: viewTypeMapping[view],
|
|
2683
|
+
categories: [],
|
|
2684
|
+
cursorToken: '',
|
|
2685
|
+
};
|
|
2686
|
+
|
|
2687
|
+
const originalFunction = window.require(
|
|
2688
|
+
'WAWebNewsletterGatingUtils',
|
|
2689
|
+
).getNewsletterDirectoryPageSize;
|
|
2690
|
+
limit !== 50 &&
|
|
2691
|
+
(window.require(
|
|
2692
|
+
'WAWebNewsletterGatingUtils',
|
|
2693
|
+
).getNewsletterDirectoryPageSize = () => limit);
|
|
2694
|
+
|
|
2695
|
+
const channels = (
|
|
2696
|
+
await window
|
|
2697
|
+
.require('WAWebNewsletterDirectorySearchAction')
|
|
2698
|
+
.fetchNewsletterDirectories(searchOptions)
|
|
2699
|
+
).newsletters;
|
|
2700
|
+
|
|
2701
|
+
limit !== 50 &&
|
|
2702
|
+
(window.require(
|
|
2703
|
+
'WAWebNewsletterGatingUtils',
|
|
2704
|
+
).getNewsletterDirectoryPageSize = originalFunction);
|
|
2705
|
+
|
|
2706
|
+
return channels
|
|
2707
|
+
? await Promise.all(
|
|
2708
|
+
channels.map((channel) =>
|
|
2709
|
+
window.WWebJS.getChatModel(channel, {
|
|
2710
|
+
isChannel: true,
|
|
2711
|
+
}),
|
|
2712
|
+
),
|
|
2713
|
+
)
|
|
2714
|
+
: [];
|
|
2715
|
+
},
|
|
2716
|
+
searchOptions,
|
|
2717
|
+
);
|
|
1945
2718
|
}
|
|
1946
2719
|
|
|
1947
2720
|
/**
|
|
@@ -1951,10 +2724,14 @@ class Client extends EventEmitter {
|
|
|
1951
2724
|
*/
|
|
1952
2725
|
async deleteChannel(channelId) {
|
|
1953
2726
|
return await this.pupPage.evaluate(async (channelId) => {
|
|
1954
|
-
const channel = await window.WWebJS.getChat(channelId, {
|
|
2727
|
+
const channel = await window.WWebJS.getChat(channelId, {
|
|
2728
|
+
getAsModel: false,
|
|
2729
|
+
});
|
|
1955
2730
|
if (!channel) return false;
|
|
1956
2731
|
try {
|
|
1957
|
-
await
|
|
2732
|
+
await window
|
|
2733
|
+
.require('WAWebNewsletterDeleteAction')
|
|
2734
|
+
.deleteNewsletterAction(channel);
|
|
1958
2735
|
return true;
|
|
1959
2736
|
} catch (err) {
|
|
1960
2737
|
if (err.name === 'ServerStatusCodeError') return false;
|
|
@@ -1972,7 +2749,7 @@ class Client extends EventEmitter {
|
|
|
1972
2749
|
return window.WWebJS.getLabels();
|
|
1973
2750
|
});
|
|
1974
2751
|
|
|
1975
|
-
return labels.map(data => new Label(this, data));
|
|
2752
|
+
return labels.map((data) => new Label(this, data));
|
|
1976
2753
|
}
|
|
1977
2754
|
|
|
1978
2755
|
/**
|
|
@@ -1983,7 +2760,7 @@ class Client extends EventEmitter {
|
|
|
1983
2760
|
const broadcasts = await this.pupPage.evaluate(async () => {
|
|
1984
2761
|
return window.WWebJS.getAllStatuses();
|
|
1985
2762
|
});
|
|
1986
|
-
return broadcasts.map(data => new Broadcast(this, data));
|
|
2763
|
+
return broadcasts.map((data) => new Broadcast(this, data));
|
|
1987
2764
|
}
|
|
1988
2765
|
|
|
1989
2766
|
/**
|
|
@@ -1995,9 +2772,11 @@ class Client extends EventEmitter {
|
|
|
1995
2772
|
const broadcast = await this.pupPage.evaluate(async (userId) => {
|
|
1996
2773
|
let status;
|
|
1997
2774
|
try {
|
|
1998
|
-
status =
|
|
2775
|
+
status = window.require('WAWebCollections').Status.get(userId);
|
|
1999
2776
|
if (!status) {
|
|
2000
|
-
status = await
|
|
2777
|
+
status = await window
|
|
2778
|
+
.require('WAWebCollections')
|
|
2779
|
+
.Status.find(userId);
|
|
2001
2780
|
}
|
|
2002
2781
|
} catch {
|
|
2003
2782
|
status = null;
|
|
@@ -2015,17 +2794,26 @@ class Client extends EventEmitter {
|
|
|
2015
2794
|
*/
|
|
2016
2795
|
async revokeStatusMessage(messageId) {
|
|
2017
2796
|
return await this.pupPage.evaluate(async (msgId) => {
|
|
2018
|
-
const status =
|
|
2797
|
+
const status = window
|
|
2798
|
+
.require('WAWebCollections')
|
|
2799
|
+
.Status.getMyStatus();
|
|
2019
2800
|
if (!status) return;
|
|
2020
2801
|
|
|
2021
2802
|
const msg =
|
|
2022
|
-
|
|
2803
|
+
window.require('WAWebCollections').Msg.get(msgId) ||
|
|
2804
|
+
(
|
|
2805
|
+
await window
|
|
2806
|
+
.require('WAWebCollections')
|
|
2807
|
+
.Msg.getMessagesById([msgId])
|
|
2808
|
+
)?.messages?.[0];
|
|
2023
2809
|
if (!msg) return;
|
|
2024
2810
|
|
|
2025
2811
|
if (!msg.id.fromMe || !msg.id.remote.isStatus())
|
|
2026
2812
|
throw 'Invalid usage! Can only revoke the message its from own status broadcast';
|
|
2027
2813
|
|
|
2028
|
-
return await
|
|
2814
|
+
return await window
|
|
2815
|
+
.require('WAWebRevokeStatusAction')
|
|
2816
|
+
.sendStatusRevokeMsgAction(status, msg);
|
|
2029
2817
|
}, messageId);
|
|
2030
2818
|
}
|
|
2031
2819
|
|
|
@@ -2043,7 +2831,7 @@ class Client extends EventEmitter {
|
|
|
2043
2831
|
}
|
|
2044
2832
|
|
|
2045
2833
|
/**
|
|
2046
|
-
* Get all Labels assigned to a chat
|
|
2834
|
+
* Get all Labels assigned to a chat
|
|
2047
2835
|
* @param {string} chatId
|
|
2048
2836
|
* @returns {Promise<Array<Label>>}
|
|
2049
2837
|
*/
|
|
@@ -2052,7 +2840,7 @@ class Client extends EventEmitter {
|
|
|
2052
2840
|
return window.WWebJS.getChatLabels(chatId);
|
|
2053
2841
|
}, chatId);
|
|
2054
2842
|
|
|
2055
|
-
return labels.map(data => new Label(this, data));
|
|
2843
|
+
return labels.map((data) => new Label(this, data));
|
|
2056
2844
|
}
|
|
2057
2845
|
|
|
2058
2846
|
/**
|
|
@@ -2062,7 +2850,7 @@ class Client extends EventEmitter {
|
|
|
2062
2850
|
*/
|
|
2063
2851
|
async getChatsByLabelId(labelId) {
|
|
2064
2852
|
const chatIds = await this.pupPage.evaluate(async (labelId) => {
|
|
2065
|
-
const label =
|
|
2853
|
+
const label = window.require('WAWebCollections').Label.get(labelId);
|
|
2066
2854
|
const labelItems = label.labelItemCollection.getModelsArray();
|
|
2067
2855
|
return labelItems.reduce((result, item) => {
|
|
2068
2856
|
if (item.parentType === 'Chat') {
|
|
@@ -2072,7 +2860,7 @@ class Client extends EventEmitter {
|
|
|
2072
2860
|
}, []);
|
|
2073
2861
|
}, labelId);
|
|
2074
2862
|
|
|
2075
|
-
return Promise.all(chatIds.map(id => this.getChatById(id)));
|
|
2863
|
+
return Promise.all(chatIds.map((id) => this.getChatById(id)));
|
|
2076
2864
|
}
|
|
2077
2865
|
|
|
2078
2866
|
/**
|
|
@@ -2081,11 +2869,18 @@ class Client extends EventEmitter {
|
|
|
2081
2869
|
*/
|
|
2082
2870
|
async getBlockedContacts() {
|
|
2083
2871
|
const blockedContacts = await this.pupPage.evaluate(() => {
|
|
2084
|
-
let chatIds =
|
|
2085
|
-
|
|
2872
|
+
let chatIds = window
|
|
2873
|
+
.require('WAWebCollections')
|
|
2874
|
+
.Blocklist.getModelsArray()
|
|
2875
|
+
.map((a) => a.id._serialized);
|
|
2876
|
+
return Promise.all(
|
|
2877
|
+
chatIds.map((id) => window.WWebJS.getContact(id)),
|
|
2878
|
+
);
|
|
2086
2879
|
});
|
|
2087
2880
|
|
|
2088
|
-
return blockedContacts.map(contact =>
|
|
2881
|
+
return blockedContacts.map((contact) =>
|
|
2882
|
+
ContactFactory.create(this.client, contact),
|
|
2883
|
+
);
|
|
2089
2884
|
}
|
|
2090
2885
|
|
|
2091
2886
|
/**
|
|
@@ -2094,9 +2889,13 @@ class Client extends EventEmitter {
|
|
|
2094
2889
|
* @returns {Promise<boolean>} Returns true if the picture was properly updated.
|
|
2095
2890
|
*/
|
|
2096
2891
|
async setProfilePicture(media) {
|
|
2097
|
-
const success = await this.pupPage.evaluate(
|
|
2098
|
-
|
|
2099
|
-
|
|
2892
|
+
const success = await this.pupPage.evaluate(
|
|
2893
|
+
(chatid, media) => {
|
|
2894
|
+
return window.WWebJS.setPicture(chatid, media);
|
|
2895
|
+
},
|
|
2896
|
+
this.info.wid._serialized,
|
|
2897
|
+
media,
|
|
2898
|
+
);
|
|
2100
2899
|
|
|
2101
2900
|
return success;
|
|
2102
2901
|
}
|
|
@@ -2112,7 +2911,7 @@ class Client extends EventEmitter {
|
|
|
2112
2911
|
|
|
2113
2912
|
return success;
|
|
2114
2913
|
}
|
|
2115
|
-
|
|
2914
|
+
|
|
2116
2915
|
/**
|
|
2117
2916
|
* Change labels in chats
|
|
2118
2917
|
* @param {Array<number|string>} labelIds
|
|
@@ -2120,26 +2919,42 @@ class Client extends EventEmitter {
|
|
|
2120
2919
|
* @returns {Promise<void>}
|
|
2121
2920
|
*/
|
|
2122
2921
|
async addOrRemoveLabels(labelIds, chatIds) {
|
|
2922
|
+
return this.pupPage.evaluate(
|
|
2923
|
+
async (labelIds, chatIds) => {
|
|
2924
|
+
if (
|
|
2925
|
+
['smba', 'smbi'].indexOf(
|
|
2926
|
+
window.require('WAWebConnModel').Conn.platform,
|
|
2927
|
+
) === -1
|
|
2928
|
+
) {
|
|
2929
|
+
throw '[LT01] Only Whatsapp business';
|
|
2930
|
+
}
|
|
2931
|
+
const labels = window.WWebJS.getLabels().filter(
|
|
2932
|
+
(e) => labelIds.find((l) => l == e.id) !== undefined,
|
|
2933
|
+
);
|
|
2934
|
+
const chats = window
|
|
2935
|
+
.require('WAWebCollections')
|
|
2936
|
+
.Chat.filter((e) => chatIds.includes(e.id._serialized));
|
|
2123
2937
|
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
const labels = window.WWebJS.getLabels().filter(e => labelIds.find(l => l == e.id) !== undefined);
|
|
2129
|
-
const chats = (window.require('WAWebCollections')).Chat.filter(e => chatIds.includes(e.id._serialized));
|
|
2130
|
-
|
|
2131
|
-
let actions = labels.map(label => ({id: label.id, type: 'add'}));
|
|
2938
|
+
let actions = labels.map((label) => ({
|
|
2939
|
+
id: label.id,
|
|
2940
|
+
type: 'add',
|
|
2941
|
+
}));
|
|
2132
2942
|
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2943
|
+
chats.forEach((chat) => {
|
|
2944
|
+
(chat.labels || []).forEach((n) => {
|
|
2945
|
+
if (!actions.find((e) => e.id == n)) {
|
|
2946
|
+
actions.push({ id: n, type: 'remove' });
|
|
2947
|
+
}
|
|
2948
|
+
});
|
|
2138
2949
|
});
|
|
2139
|
-
});
|
|
2140
2950
|
|
|
2141
|
-
|
|
2142
|
-
|
|
2951
|
+
return await window
|
|
2952
|
+
.require('WAWebCollections')
|
|
2953
|
+
.Label.addOrRemoveLabels(actions, chats);
|
|
2954
|
+
},
|
|
2955
|
+
labelIds,
|
|
2956
|
+
chatIds,
|
|
2957
|
+
);
|
|
2143
2958
|
}
|
|
2144
2959
|
|
|
2145
2960
|
/**
|
|
@@ -2159,8 +2974,12 @@ class Client extends EventEmitter {
|
|
|
2159
2974
|
*/
|
|
2160
2975
|
async getGroupMembershipRequests(groupId) {
|
|
2161
2976
|
return await this.pupPage.evaluate(async (groupId) => {
|
|
2162
|
-
const groupWid = window
|
|
2163
|
-
|
|
2977
|
+
const groupWid = window
|
|
2978
|
+
.require('WAWebWidFactory')
|
|
2979
|
+
.createWid(groupId);
|
|
2980
|
+
return await window
|
|
2981
|
+
.require('WAWebApiMembershipApprovalRequestStore')
|
|
2982
|
+
.getMembershipApprovalRequests(groupWid);
|
|
2164
2983
|
}, groupId);
|
|
2165
2984
|
}
|
|
2166
2985
|
|
|
@@ -2186,10 +3005,19 @@ class Client extends EventEmitter {
|
|
|
2186
3005
|
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were approved and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
|
2187
3006
|
*/
|
|
2188
3007
|
async approveGroupMembershipRequests(groupId, options = {}) {
|
|
2189
|
-
return await this.pupPage.evaluate(
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
3008
|
+
return await this.pupPage.evaluate(
|
|
3009
|
+
async (groupId, options) => {
|
|
3010
|
+
const { requesterIds = null, sleep = [250, 500] } = options;
|
|
3011
|
+
return await window.WWebJS.membershipRequestAction(
|
|
3012
|
+
groupId,
|
|
3013
|
+
'Approve',
|
|
3014
|
+
requesterIds,
|
|
3015
|
+
sleep,
|
|
3016
|
+
);
|
|
3017
|
+
},
|
|
3018
|
+
groupId,
|
|
3019
|
+
options,
|
|
3020
|
+
);
|
|
2193
3021
|
}
|
|
2194
3022
|
|
|
2195
3023
|
/**
|
|
@@ -2199,24 +3027,36 @@ class Client extends EventEmitter {
|
|
|
2199
3027
|
* @returns {Promise<Array<MembershipRequestActionResult>>} Returns an array of requester IDs whose membership requests were rejected and an error for each requester, if any occurred during the operation. If there are no requests, an empty array will be returned
|
|
2200
3028
|
*/
|
|
2201
3029
|
async rejectGroupMembershipRequests(groupId, options = {}) {
|
|
2202
|
-
return await this.pupPage.evaluate(
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
3030
|
+
return await this.pupPage.evaluate(
|
|
3031
|
+
async (groupId, options) => {
|
|
3032
|
+
const { requesterIds = null, sleep = [250, 500] } = options;
|
|
3033
|
+
return await window.WWebJS.membershipRequestAction(
|
|
3034
|
+
groupId,
|
|
3035
|
+
'Reject',
|
|
3036
|
+
requesterIds,
|
|
3037
|
+
sleep,
|
|
3038
|
+
);
|
|
3039
|
+
},
|
|
3040
|
+
groupId,
|
|
3041
|
+
options,
|
|
3042
|
+
);
|
|
2206
3043
|
}
|
|
2207
3044
|
|
|
2208
|
-
|
|
2209
3045
|
/**
|
|
2210
3046
|
* Setting autoload download audio
|
|
2211
3047
|
* @param {boolean} flag true/false
|
|
2212
3048
|
*/
|
|
2213
3049
|
async setAutoDownloadAudio(flag) {
|
|
2214
|
-
await this.pupPage.evaluate(async flag => {
|
|
2215
|
-
const autoDownload =
|
|
3050
|
+
await this.pupPage.evaluate(async (flag) => {
|
|
3051
|
+
const autoDownload = window
|
|
3052
|
+
.require('WAWebUserPrefsGeneral')
|
|
3053
|
+
.getAutoDownloadAudio();
|
|
2216
3054
|
if (autoDownload === flag) {
|
|
2217
3055
|
return flag;
|
|
2218
3056
|
}
|
|
2219
|
-
await
|
|
3057
|
+
await window
|
|
3058
|
+
.require('WAWebUserPrefsGeneral')
|
|
3059
|
+
.setAutoDownloadAudio(flag);
|
|
2220
3060
|
return flag;
|
|
2221
3061
|
}, flag);
|
|
2222
3062
|
}
|
|
@@ -2226,12 +3066,16 @@ class Client extends EventEmitter {
|
|
|
2226
3066
|
* @param {boolean} flag true/false
|
|
2227
3067
|
*/
|
|
2228
3068
|
async setAutoDownloadDocuments(flag) {
|
|
2229
|
-
await this.pupPage.evaluate(async flag => {
|
|
2230
|
-
const autoDownload =
|
|
3069
|
+
await this.pupPage.evaluate(async (flag) => {
|
|
3070
|
+
const autoDownload = window
|
|
3071
|
+
.require('WAWebUserPrefsGeneral')
|
|
3072
|
+
.getAutoDownloadDocuments();
|
|
2231
3073
|
if (autoDownload === flag) {
|
|
2232
3074
|
return flag;
|
|
2233
3075
|
}
|
|
2234
|
-
await
|
|
3076
|
+
await window
|
|
3077
|
+
.require('WAWebUserPrefsGeneral')
|
|
3078
|
+
.setAutoDownloadDocuments(flag);
|
|
2235
3079
|
return flag;
|
|
2236
3080
|
}, flag);
|
|
2237
3081
|
}
|
|
@@ -2241,12 +3085,16 @@ class Client extends EventEmitter {
|
|
|
2241
3085
|
* @param {boolean} flag true/false
|
|
2242
3086
|
*/
|
|
2243
3087
|
async setAutoDownloadPhotos(flag) {
|
|
2244
|
-
await this.pupPage.evaluate(async flag => {
|
|
2245
|
-
const autoDownload =
|
|
3088
|
+
await this.pupPage.evaluate(async (flag) => {
|
|
3089
|
+
const autoDownload = window
|
|
3090
|
+
.require('WAWebUserPrefsGeneral')
|
|
3091
|
+
.getAutoDownloadPhotos();
|
|
2246
3092
|
if (autoDownload === flag) {
|
|
2247
3093
|
return flag;
|
|
2248
3094
|
}
|
|
2249
|
-
await
|
|
3095
|
+
await window
|
|
3096
|
+
.require('WAWebUserPrefsGeneral')
|
|
3097
|
+
.setAutoDownloadPhotos(flag);
|
|
2250
3098
|
return flag;
|
|
2251
3099
|
}, flag);
|
|
2252
3100
|
}
|
|
@@ -2256,12 +3104,16 @@ class Client extends EventEmitter {
|
|
|
2256
3104
|
* @param {boolean} flag true/false
|
|
2257
3105
|
*/
|
|
2258
3106
|
async setAutoDownloadVideos(flag) {
|
|
2259
|
-
await this.pupPage.evaluate(async flag => {
|
|
2260
|
-
const autoDownload =
|
|
3107
|
+
await this.pupPage.evaluate(async (flag) => {
|
|
3108
|
+
const autoDownload = window
|
|
3109
|
+
.require('WAWebUserPrefsGeneral')
|
|
3110
|
+
.getAutoDownloadVideos();
|
|
2261
3111
|
if (autoDownload === flag) {
|
|
2262
3112
|
return flag;
|
|
2263
3113
|
}
|
|
2264
|
-
await
|
|
3114
|
+
await window
|
|
3115
|
+
.require('WAWebUserPrefsGeneral')
|
|
3116
|
+
.setAutoDownloadVideos(flag);
|
|
2265
3117
|
return flag;
|
|
2266
3118
|
}, flag);
|
|
2267
3119
|
}
|
|
@@ -2273,16 +3125,20 @@ class Client extends EventEmitter {
|
|
|
2273
3125
|
* @returns {Promise<boolean>}
|
|
2274
3126
|
*/
|
|
2275
3127
|
async setBackgroundSync(flag) {
|
|
2276
|
-
return await this.pupPage.evaluate(async flag => {
|
|
2277
|
-
const backSync =
|
|
3128
|
+
return await this.pupPage.evaluate(async (flag) => {
|
|
3129
|
+
const backSync = window
|
|
3130
|
+
.require('WAWebUserPrefsNotifications')
|
|
3131
|
+
.getGlobalOfflineNotifications();
|
|
2278
3132
|
if (backSync === flag) {
|
|
2279
3133
|
return flag;
|
|
2280
3134
|
}
|
|
2281
|
-
await
|
|
3135
|
+
await window
|
|
3136
|
+
.require('WAWebUserPrefsNotifications')
|
|
3137
|
+
.setGlobalOfflineNotifications(flag);
|
|
2282
3138
|
return flag;
|
|
2283
3139
|
}, flag);
|
|
2284
3140
|
}
|
|
2285
|
-
|
|
3141
|
+
|
|
2286
3142
|
/**
|
|
2287
3143
|
* Get user device count by ID
|
|
2288
3144
|
* Each WaWeb Connection counts as one device, and the phone (if exists) counts as one
|
|
@@ -2292,8 +3148,17 @@ class Client extends EventEmitter {
|
|
|
2292
3148
|
*/
|
|
2293
3149
|
async getContactDeviceCount(userId) {
|
|
2294
3150
|
return await this.pupPage.evaluate(async (userId) => {
|
|
2295
|
-
const devices = await
|
|
2296
|
-
|
|
3151
|
+
const devices = await window
|
|
3152
|
+
.require('WAWebApiDeviceList')
|
|
3153
|
+
.getDeviceIds([
|
|
3154
|
+
window.require('WAWebWidFactory').createWid(userId),
|
|
3155
|
+
]);
|
|
3156
|
+
if (
|
|
3157
|
+
devices &&
|
|
3158
|
+
devices.length &&
|
|
3159
|
+
devices[0] != null &&
|
|
3160
|
+
typeof devices[0].devices == 'object'
|
|
3161
|
+
) {
|
|
2297
3162
|
return devices[0].devices.length;
|
|
2298
3163
|
}
|
|
2299
3164
|
return 0;
|
|
@@ -2308,17 +3173,21 @@ class Client extends EventEmitter {
|
|
|
2308
3173
|
async syncHistory(chatId) {
|
|
2309
3174
|
return await this.pupPage.evaluate(async (chatId) => {
|
|
2310
3175
|
const chatWid = window.require('WAWebWidFactory').createWid(chatId);
|
|
2311
|
-
const chat =
|
|
3176
|
+
const chat =
|
|
3177
|
+
window.require('WAWebCollections').Chat.get(chatWid) ??
|
|
3178
|
+
(await window.require('WAWebCollections').Chat.find(chatWid));
|
|
2312
3179
|
if (chat?.endOfHistoryTransferType === 0) {
|
|
2313
|
-
await
|
|
2314
|
-
|
|
2315
|
-
|
|
3180
|
+
await window
|
|
3181
|
+
.require('WAWebSendNonMessageDataRequest')
|
|
3182
|
+
.sendPeerDataOperationRequest(3, {
|
|
3183
|
+
chatId: chat.id,
|
|
3184
|
+
});
|
|
2316
3185
|
return true;
|
|
2317
3186
|
}
|
|
2318
3187
|
return false;
|
|
2319
3188
|
}, chatId);
|
|
2320
3189
|
}
|
|
2321
|
-
|
|
3190
|
+
|
|
2322
3191
|
/**
|
|
2323
3192
|
* Generates a WhatsApp call link (video call or voice call)
|
|
2324
3193
|
* @param {Date} startTime The start time of the call
|
|
@@ -2327,17 +3196,27 @@ class Client extends EventEmitter {
|
|
|
2327
3196
|
*/
|
|
2328
3197
|
async createCallLink(startTime, callType) {
|
|
2329
3198
|
if (!['video', 'voice'].includes(callType)) {
|
|
2330
|
-
throw new class CreateCallLinkError extends Error {
|
|
2331
|
-
constructor(m) {
|
|
2332
|
-
|
|
3199
|
+
throw new (class CreateCallLinkError extends Error {
|
|
3200
|
+
constructor(m) {
|
|
3201
|
+
super(m);
|
|
3202
|
+
}
|
|
3203
|
+
})(
|
|
3204
|
+
"Invalid 'callType' parameter value is provided. Valid values are: 'voice' | 'video'.",
|
|
3205
|
+
);
|
|
2333
3206
|
}
|
|
2334
3207
|
|
|
2335
3208
|
startTime = Math.floor(startTime.getTime() / 1000);
|
|
2336
|
-
|
|
2337
|
-
return await this.pupPage.evaluate(
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
3209
|
+
|
|
3210
|
+
return await this.pupPage.evaluate(
|
|
3211
|
+
async (startTimeTs, callType) => {
|
|
3212
|
+
const response = await window
|
|
3213
|
+
.require('WAWebGenerateEventCallLink')
|
|
3214
|
+
.createEventCallLink(startTimeTs, callType);
|
|
3215
|
+
return response ?? '';
|
|
3216
|
+
},
|
|
3217
|
+
startTime,
|
|
3218
|
+
callType,
|
|
3219
|
+
);
|
|
2341
3220
|
}
|
|
2342
3221
|
|
|
2343
3222
|
/**
|
|
@@ -2349,35 +3228,59 @@ class Client extends EventEmitter {
|
|
|
2349
3228
|
async sendResponseToScheduledEvent(response, eventMessageId) {
|
|
2350
3229
|
if (![0, 1, 2, 3].includes(response)) return false;
|
|
2351
3230
|
|
|
2352
|
-
return await this.pupPage.evaluate(
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
3231
|
+
return await this.pupPage.evaluate(
|
|
3232
|
+
async (response, msgId) => {
|
|
3233
|
+
const eventMsg =
|
|
3234
|
+
window.require('WAWebCollections').Msg.get(msgId) ||
|
|
3235
|
+
(
|
|
3236
|
+
await window
|
|
3237
|
+
.require('WAWebCollections')
|
|
3238
|
+
.Msg.getMessagesById([msgId])
|
|
3239
|
+
)?.messages?.[0];
|
|
3240
|
+
if (!eventMsg) return false;
|
|
3241
|
+
|
|
3242
|
+
await window
|
|
3243
|
+
.require('WAWebSendEventResponseMsgAction')
|
|
3244
|
+
.sendEventResponseMsg(response, eventMsg);
|
|
3245
|
+
return true;
|
|
3246
|
+
},
|
|
3247
|
+
response,
|
|
3248
|
+
eventMessageId,
|
|
3249
|
+
);
|
|
2359
3250
|
}
|
|
2360
|
-
|
|
3251
|
+
|
|
2361
3252
|
/**
|
|
2362
3253
|
* Save new contact to user's addressbook or edit the existing one
|
|
2363
3254
|
* @param {string} phoneNumber The contact's phone number in a format "17182222222", where "1" is a country code
|
|
2364
|
-
* @param {string} firstName
|
|
2365
|
-
* @param {string} lastName
|
|
3255
|
+
* @param {string} firstName
|
|
3256
|
+
* @param {string} lastName
|
|
2366
3257
|
* @param {boolean} [syncToAddressbook = false] If set to true, the contact will also be saved to the user's address book on their phone. False by default
|
|
2367
3258
|
* @returns {Promise<void>}
|
|
2368
3259
|
*/
|
|
2369
|
-
async saveOrEditAddressbookContact(
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
3260
|
+
async saveOrEditAddressbookContact(
|
|
3261
|
+
phoneNumber,
|
|
3262
|
+
firstName,
|
|
3263
|
+
lastName,
|
|
3264
|
+
syncToAddressbook = false,
|
|
3265
|
+
) {
|
|
3266
|
+
return await this.pupPage.evaluate(
|
|
3267
|
+
async (phoneNumber, firstName, lastName, syncToAddressbook) => {
|
|
3268
|
+
return await window
|
|
3269
|
+
.require('WAWebSaveContactAction')
|
|
3270
|
+
.saveContactAction({
|
|
3271
|
+
firstName: firstName,
|
|
3272
|
+
lastName: lastName,
|
|
3273
|
+
phoneNumber: phoneNumber,
|
|
3274
|
+
prevPhoneNumber: phoneNumber,
|
|
3275
|
+
syncToAddressbook: syncToAddressbook,
|
|
3276
|
+
username: undefined,
|
|
3277
|
+
});
|
|
3278
|
+
},
|
|
3279
|
+
phoneNumber,
|
|
3280
|
+
firstName,
|
|
3281
|
+
lastName,
|
|
3282
|
+
syncToAddressbook,
|
|
3283
|
+
);
|
|
2381
3284
|
}
|
|
2382
3285
|
|
|
2383
3286
|
/**
|
|
@@ -2385,11 +3288,14 @@ class Client extends EventEmitter {
|
|
|
2385
3288
|
* @param {string} phoneNumber The contact's phone number in a format "17182222222", where "1" is a country code
|
|
2386
3289
|
* @returns {Promise<void>}
|
|
2387
3290
|
*/
|
|
2388
|
-
async deleteAddressbookContact(phoneNumber)
|
|
2389
|
-
{
|
|
3291
|
+
async deleteAddressbookContact(phoneNumber) {
|
|
2390
3292
|
return await this.pupPage.evaluate(async (phoneNumber) => {
|
|
2391
|
-
const wid = window
|
|
2392
|
-
|
|
3293
|
+
const wid = window
|
|
3294
|
+
.require('WAWebWidFactory')
|
|
3295
|
+
.createWid(phoneNumber);
|
|
3296
|
+
return await window
|
|
3297
|
+
.require('WAWebDeleteContactAction')
|
|
3298
|
+
.deleteContactAction({ phoneNumber: wid });
|
|
2393
3299
|
}, phoneNumber);
|
|
2394
3300
|
}
|
|
2395
3301
|
|
|
@@ -2402,14 +3308,17 @@ class Client extends EventEmitter {
|
|
|
2402
3308
|
return await this.pupPage.evaluate(async (userIds) => {
|
|
2403
3309
|
if (!Array.isArray(userIds)) userIds = [userIds];
|
|
2404
3310
|
|
|
2405
|
-
return await Promise.all(
|
|
2406
|
-
|
|
3311
|
+
return await Promise.all(
|
|
3312
|
+
userIds.map(async (userId) => {
|
|
3313
|
+
const { lid, phone } =
|
|
3314
|
+
await window.WWebJS.enforceLidAndPnRetrieval(userId);
|
|
2407
3315
|
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
3316
|
+
return {
|
|
3317
|
+
lid: lid?._serialized,
|
|
3318
|
+
pn: phone?._serialized,
|
|
3319
|
+
};
|
|
3320
|
+
}),
|
|
3321
|
+
);
|
|
2413
3322
|
}, userIds);
|
|
2414
3323
|
}
|
|
2415
3324
|
|
|
@@ -2421,15 +3330,28 @@ class Client extends EventEmitter {
|
|
|
2421
3330
|
* @returns {Promise<void>}
|
|
2422
3331
|
*/
|
|
2423
3332
|
async addOrEditCustomerNote(userId, note) {
|
|
2424
|
-
return await this.pupPage.evaluate(
|
|
2425
|
-
|
|
3333
|
+
return await this.pupPage.evaluate(
|
|
3334
|
+
async (userId, note) => {
|
|
3335
|
+
if (!window.require('WAWebBizGatingUtils').smbNotesV1Enabled())
|
|
3336
|
+
return;
|
|
2426
3337
|
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
3338
|
+
return window
|
|
3339
|
+
.require('WAWebNoteAction')
|
|
3340
|
+
.noteAddAction(
|
|
3341
|
+
'unstructured',
|
|
3342
|
+
window
|
|
3343
|
+
.require('WAWebWidToJid')
|
|
3344
|
+
.widToUserJid(
|
|
3345
|
+
window
|
|
3346
|
+
.require('WAWebWidFactory')
|
|
3347
|
+
.createWid(userId),
|
|
3348
|
+
),
|
|
3349
|
+
note,
|
|
3350
|
+
);
|
|
3351
|
+
},
|
|
3352
|
+
userId,
|
|
3353
|
+
note,
|
|
3354
|
+
);
|
|
2433
3355
|
}
|
|
2434
3356
|
|
|
2435
3357
|
/**
|
|
@@ -2447,47 +3369,65 @@ class Client extends EventEmitter {
|
|
|
2447
3369
|
*/
|
|
2448
3370
|
async getCustomerNote(userId) {
|
|
2449
3371
|
return await this.pupPage.evaluate(async (userId) => {
|
|
2450
|
-
if (!
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
3372
|
+
if (!window.require('WAWebBizGatingUtils').smbNotesV1Enabled())
|
|
3373
|
+
return null;
|
|
3374
|
+
|
|
3375
|
+
const note = await window
|
|
3376
|
+
.require('WAWebNoteAction')
|
|
3377
|
+
.retrieveOnlyNoteForChatJid(
|
|
3378
|
+
window
|
|
3379
|
+
.require('WAWebWidToJid')
|
|
3380
|
+
.widToUserJid(
|
|
3381
|
+
window.require('WAWebWidFactory').createWid(userId),
|
|
3382
|
+
),
|
|
3383
|
+
);
|
|
2455
3384
|
|
|
2456
3385
|
let serialized = note?.serialize();
|
|
2457
3386
|
|
|
2458
3387
|
if (!serialized) return null;
|
|
2459
3388
|
|
|
2460
|
-
serialized.chatId = window
|
|
3389
|
+
serialized.chatId = window
|
|
3390
|
+
.require('WAWebJidToWid')
|
|
3391
|
+
.userJidToUserWid(serialized.chatJid)._serialized;
|
|
2461
3392
|
delete serialized.chatJid;
|
|
2462
3393
|
|
|
2463
3394
|
return serialized;
|
|
2464
3395
|
}, userId);
|
|
2465
3396
|
}
|
|
2466
|
-
|
|
3397
|
+
|
|
2467
3398
|
/**
|
|
2468
3399
|
* Get Poll Votes
|
|
2469
3400
|
* @param {string} messageId
|
|
2470
|
-
* @return {Promise<Array<PollVote>>}
|
|
3401
|
+
* @return {Promise<Array<PollVote>>}
|
|
2471
3402
|
*/
|
|
2472
3403
|
async getPollVotes(messageId) {
|
|
2473
3404
|
const msg = await this.getMessageById(messageId);
|
|
2474
3405
|
if (!msg) return [];
|
|
2475
|
-
if (msg.type != MessageTypes.POLL_CREATION)
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
3406
|
+
if (msg.type != MessageTypes.POLL_CREATION)
|
|
3407
|
+
throw 'Invalid usage! Can only be used with a pollCreation message';
|
|
3408
|
+
|
|
3409
|
+
const pollVotes = await this.pupPage.evaluate(async (msg) => {
|
|
3410
|
+
const msgKey = window
|
|
3411
|
+
.require('WAWebMsgKey')
|
|
3412
|
+
.fromString(msg.id._serialized);
|
|
3413
|
+
let pollVotes = await window
|
|
3414
|
+
.require('WAWebPollsVotesSchema')
|
|
3415
|
+
.getTable()
|
|
3416
|
+
.equals(['parentMsgKey'], msgKey.toString());
|
|
3417
|
+
|
|
3418
|
+
return pollVotes.map((item) => {
|
|
2482
3419
|
const typedArray = new Uint8Array(item.selectedOptionLocalIds);
|
|
2483
3420
|
return {
|
|
2484
3421
|
...item,
|
|
2485
|
-
selectedOptionLocalIds: Array.from(typedArray)
|
|
3422
|
+
selectedOptionLocalIds: Array.from(typedArray),
|
|
2486
3423
|
};
|
|
2487
3424
|
});
|
|
2488
3425
|
}, msg);
|
|
2489
3426
|
|
|
2490
|
-
return pollVotes.map(
|
|
3427
|
+
return pollVotes.map(
|
|
3428
|
+
(pollVote) =>
|
|
3429
|
+
new PollVote(this.client, { ...pollVote, parentMessage: msg }),
|
|
3430
|
+
);
|
|
2491
3431
|
}
|
|
2492
3432
|
}
|
|
2493
3433
|
|