@eryxenx/insta-chat 2.0.0 → 2.0.3
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/CHANGELOG.md +95 -8
- package/index.js +105 -1
- package/module/login.js +51 -1
- package/package.json +9 -2
- package/src/api/action/getAppState.js +19 -1
- package/src/api/action/getCookies.js +7 -1
- package/src/api/action/getCurrentUserID.js +7 -1
- package/src/api/action/setOptions.js +8 -1
- package/src/api/messaging/editMessage.js +19 -1
- package/src/api/messaging/markAsRead.js +7 -1
- package/src/api/messaging/resolvePhotoUrl.js +8 -1
- package/src/api/messaging/sendMessage.js +45 -1
- package/src/api/messaging/sendMessageSync.js +8 -1
- package/src/api/messaging/sendTypingIndicator.js +7 -1
- package/src/api/messaging/setMessageReaction.js +19 -1
- package/src/api/messaging/shareContact.js +19 -1
- package/src/api/messaging/unsendMessage.js +16 -1
- package/src/api/realtime/getInbox.js +7 -1
- package/src/api/realtime/listen.js +7 -1
- package/src/api/realtime/stopListening.js +7 -1
- package/src/api/threads/getThreadHistory.js +16 -1
- package/src/api/threads/getThreadInfo.js +59 -1
- package/src/api/threads/getThreadList.js +22 -1
- package/src/api/users/getUID.js +12 -1
- package/src/api/users/getUserInfo.js +37 -1
- package/src/api.js +253 -1
- package/src/app/InstaClient.js +352 -1
- package/src/app/InstaContext.js +46 -1
- package/src/app/createFcaClient.js +59 -1
- package/src/app/loadApiMethods.js +30 -1
- package/src/constants.js +53 -1
- package/src/cookies.js +41 -1
- package/src/deviceIdentity.js +31 -1
- package/src/events/normalizeEvent.js +142 -1
- package/src/http.js +381 -1
- package/src/messageContent.js +73 -1
- package/src/methods/inbox.js +464 -1
- package/src/methods/media.js +218 -1
- package/src/methods/message.js +115 -1
- package/src/methods/reactions.js +52 -1
- package/src/methods/thread.js +96 -1
- package/src/methods/typing.js +35 -1
- package/src/methods/user.js +33 -1
- package/src/session.js +94 -1
- package/src/threadDetail.js +36 -1
- package/src/utils/antiSuspension.js +269 -0
- package/src/utils/dataDir.js +11 -0
- package/src/utils/errors.js +106 -0
- package/src/utils/format.js +38 -1
- package/src/utils/messageStyle.js +57 -1
- package/src/utils/sessionGuard.js +93 -0
package/src/methods/typing.js
CHANGED
|
@@ -4,4 +4,38 @@
|
|
|
4
4
|
* Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
|
|
5
5
|
* Original author credit must be retained in all copies and derivatives.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
const { EP } = require("../constants");
|
|
9
|
+
|
|
10
|
+
const FALLBACK_PATHS = [
|
|
11
|
+
(t) => `https://www.instagram.com/api/v1/direct_v2/threads/${t}/indicate_activity/`,
|
|
12
|
+
(t) => `https://www.instagram.com/api/v1/direct_v2/typing/`
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
class TypingMethods {
|
|
16
|
+
constructor(http) {
|
|
17
|
+
this.http = http;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async _try(threadID, isActive) {
|
|
21
|
+
const form = { thread_id: threadID, activity_status: isActive ? "1" : "0" };
|
|
22
|
+
|
|
23
|
+
for (const build of [() => EP.TYPING(threadID), ...FALLBACK_PATHS.map((f) => () => f(threadID))]) {
|
|
24
|
+
try {
|
|
25
|
+
await this.http.postForm(build(), form);
|
|
26
|
+
return true;
|
|
27
|
+
} catch (_) {}
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async start(threadID) {
|
|
33
|
+
return this._try(threadID, true);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async stop(threadID) {
|
|
37
|
+
return this._try(threadID, false);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = TypingMethods;
|
package/src/methods/user.js
CHANGED
|
@@ -4,4 +4,36 @@
|
|
|
4
4
|
* Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
|
|
5
5
|
* Original author credit must be retained in all copies and derivatives.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
const { EP } = require("../constants");
|
|
9
|
+
|
|
10
|
+
class UserMethods {
|
|
11
|
+
constructor(http) {
|
|
12
|
+
this.http = http;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async getInfo(userID) {
|
|
16
|
+
const res = await this.http.get(EP.USER_INFO(userID));
|
|
17
|
+
return res?.user || null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async getInfoByUsername(username) {
|
|
21
|
+
try {
|
|
22
|
+
const res = await this.http.get(EP.USER_BY_USERNAME(username));
|
|
23
|
+
if (res?.user) return res.user;
|
|
24
|
+
} catch (_) {}
|
|
25
|
+
|
|
26
|
+
const res = await this.http.get(EP.USER_SEARCH(username, 30));
|
|
27
|
+
const match = (res?.users || []).find(
|
|
28
|
+
(u) => u.username?.toLowerCase() === username.toLowerCase()
|
|
29
|
+
);
|
|
30
|
+
return match || null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async search(query, limit = 20) {
|
|
34
|
+
const res = await this.http.get(EP.USER_SEARCH(query, limit));
|
|
35
|
+
return res?.users || [];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = UserMethods;
|
package/src/session.js
CHANGED
|
@@ -4,4 +4,97 @@
|
|
|
4
4
|
* Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
|
|
5
5
|
* Original author credit must be retained in all copies and derivatives.
|
|
6
6
|
*/
|
|
7
|
-
function _0x4497(_0x38d0ac,_0xf3662c){_0x38d0ac=_0x38d0ac-0x136;const _0x5e30cc=_0x5e30();let _0x4497f5=_0x5e30cc[_0x38d0ac];if(_0x4497['HTiiGt']===undefined){var _0x43aa0b=function(_0x376d1b){const _0x16d116='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x22b1c6='',_0x475ec5='';for(let _0x2511f1=0x0,_0x2f016d,_0x53a832,_0x12bd53=0x0;_0x53a832=_0x376d1b['charAt'](_0x12bd53++);~_0x53a832&&(_0x2f016d=_0x2511f1%0x4?_0x2f016d*0x40+_0x53a832:_0x53a832,_0x2511f1++%0x4)?_0x22b1c6+=String['fromCharCode'](0xff&_0x2f016d>>(-0x2*_0x2511f1&0x6)):0x0){_0x53a832=_0x16d116['indexOf'](_0x53a832);}for(let _0x2b7ca7=0x0,_0x43b0f7=_0x22b1c6['length'];_0x2b7ca7<_0x43b0f7;_0x2b7ca7++){_0x475ec5+='%'+('00'+_0x22b1c6['charCodeAt'](_0x2b7ca7)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x475ec5);};const _0x295305=function(_0x128f67,_0x3cb689){let _0x4b308c=[],_0x742b34=0x0,_0x397172,_0x16eda1='';_0x128f67=_0x43aa0b(_0x128f67);let _0x31710b;for(_0x31710b=0x0;_0x31710b<0x100;_0x31710b++){_0x4b308c[_0x31710b]=_0x31710b;}for(_0x31710b=0x0;_0x31710b<0x100;_0x31710b++){_0x742b34=(_0x742b34+_0x4b308c[_0x31710b]+_0x3cb689['charCodeAt'](_0x31710b%_0x3cb689['length']))%0x100,_0x397172=_0x4b308c[_0x31710b],_0x4b308c[_0x31710b]=_0x4b308c[_0x742b34],_0x4b308c[_0x742b34]=_0x397172;}_0x31710b=0x0,_0x742b34=0x0;for(let _0x4699fd=0x0;_0x4699fd<_0x128f67['length'];_0x4699fd++){_0x31710b=(_0x31710b+0x1)%0x100,_0x742b34=(_0x742b34+_0x4b308c[_0x31710b])%0x100,_0x397172=_0x4b308c[_0x31710b],_0x4b308c[_0x31710b]=_0x4b308c[_0x742b34],_0x4b308c[_0x742b34]=_0x397172,_0x16eda1+=String['fromCharCode'](_0x128f67['charCodeAt'](_0x4699fd)^_0x4b308c[(_0x4b308c[_0x31710b]+_0x4b308c[_0x742b34])%0x100]);}return _0x16eda1;};_0x4497['YygtOO']=_0x295305,_0x4497['IBTUpj']={},_0x4497['HTiiGt']=!![];}const _0x39c6dd=_0x5e30cc[0x0],_0x22375e=_0x38d0ac+_0x39c6dd,_0x45eb4a=_0x4497['IBTUpj'][_0x22375e];return!_0x45eb4a?(_0x4497['GDfQMh']===undefined&&(_0x4497['GDfQMh']=!![]),_0x4497f5=_0x4497['YygtOO'](_0x4497f5,_0xf3662c),_0x4497['IBTUpj'][_0x22375e]=_0x4497f5):_0x4497f5=_0x45eb4a,_0x4497f5;}const _0x3b85f6=_0x4497,_0x288f98=_0x4497;function _0x5e30(){const _0x54be80=['pSkXW6NcIx7dSa','W7hdTWW9zSkPwG','WPPOWPDlE0u','W7JdT3q3aW','W4yRW74aW4C','CLRcKCkoBmoy','W5GkrsTTpa','a8kJbJpcLW','WQ3dKGzJqSkn','WOjfnaz+WQ0','WP03W50bCmoT','yMFcKmo7WPS','WR4AE23dSmks','WORcH8oAWQnpxW','W7iWW68aW5CG','p8odWPTwWPJdGG','dCooFCo2C8kQW4/dLeK/W7PX','WOfHWOTaiSo3uvldJCoSWPddOmoi','W7GFW50kW44','xCk2lCo2ya','WOBdUWeJtG','W4a3W7veWOP+','hmoDW7/cN3pdJW','qmk5pmoUzcC','xLBdM8o9WPWb','W5f5dCo6W48','oCkabIhcUCk0','WRRdH8oOWQbega','xIXLWP0B','WQVdKuWQtmks','eCk+W51XjG4','Eq9SWRKVpq','itJdPmkLb3y','WQixsKVdTG','lSkhW4FdOvOP','F3GPnhBcUW','WPxdLNn8WPldOW','ymo2W5BcKJ4','uahdNdFdL8kl','W5qYW5exzaC','DdBdO2KDWOm','wYblWRub','WO/cLWLYWRG','qbXwWOCcuW','D2JdTxmXW4K','nhmKnNldUW','o8kvEIyefbZcGSkxW5pcVSoG','W5FcNdXnWP/cUa','W4JdIZXVWOZdTmoHBq','qfZcLSoBW5Ka','WRddLKX4emok','z2pdOg4cW5O','dwC5BaW','CSk1omkZdq','WQKCbG','AbLtWPPLdG','BdVdOgacW48','WRhdRmk0W5RcOwGRW6yQW5NcJmo0','gvLGa8o7wq','eCkFW4bwmaG','r17dGL41W7y','ESkUiCo5','gv0DvsBdJG','yCoplW','W4DyCb80W6i','W5v0WPq','cSkLW7a+W6ddLG','f0ajW55bga','BbrQ','ELySdLy','dfryhSolfW','smkWpCo7Aa','W5JcJZlcSLBcTW','W7rqe8obW5e','eCk+W5Pxpaq','mKxcKHK','W5FdNKqujXK','WO8oW4Whjb0','FhddVSkVt3C','WRLhrN1jeW','WPLUyfTRna','yCoRW5NcLd/dPG','WONdNmoOWR5fga','ouhcRmk+qmkI','ESoer2BdRCoYW4pcRCofqmkkW7q','WP08xa','W5RdKXJdVmoVoW','xCk+iSo/AJu','kSopAMrguq','w8kwkmo/AZq','W4fclSo3W48','W5DOn8oxW4G','ds9jWOaDxW','W6VdOmkbW4XoW4S','CSosm1zN','W77dK8oaW74Ura','netcGHtcMsm','WOtdKhBdSu3dJSoYamkDs09x','qbdcGc3dKmkg','WOVdH8oWWQK','WPWMtLpdKCkQ','WP40W5ymjqi','W5xdKGJcVSoJiG','W4BdQGzysSkI','petdIrhcMtq','qCozWQ/cNY/cIa','B8okWPuUW6Kd','mCoyedpdSCkM','WOJcNJ4rWPNdVG','W7OoEvXYma','wamQrmkic1ZdLIqnbSkRpG','W67dQhOJaW','WOKXj2JdUSkT','xmkWeSk/lW','W6mxaIqssCkTsIm2h8kl','W7qMk8kNW4/dRG','rSkwcCoIDq','W7HlqaxcJCoFW7FdUwuQW5lcNW','r199bmolwq','WRJcKSkyW6OXga','W6RcUmoIWOBdTY4','wauJrCkidq3dIrGNe8ku','WOGIW5yrjWa','WRtcKSob','quFcMSosWPGw','W5/cNrRdSCoYyW','WR4taLtdISkd','k8kze3ZcR8kL','bCoonKtdIrm','W5eMW5ua','W5ZdJX3dS8kUia','xCopW6BdR1eT','W5rZW4BdT8ksoq','uCorWO4RW6Kk','g8okmL/dJWG','lmk0WOLNprK','WONcIrpdJSo2jLFdIq','FaHW','qCkRW7BcMIpdUW','gv9Yamo2','W63cSSoKWO7dT3W','gmogiH7cNvu','W7jPAxC4','lmkneZlcQCk0','rL7cJmo5WQW','way9r8kega','bCk3W4WjnGm','WPtcH8o5WQvsxq','eXZdKY7dJmkz','W5JdGqhcPbRcKq','WQJdNmorW6ySba','cCkHW7eJW6RcLqNdS8kyiSkE','WRhdRmkYW5xcO24iW4atW7ZcNmoG','Cxq/DxddPG','vCovW6hcKG','W5pcHdlcTHBcIa','W4pdVvKhda','n8kwW7z0fd8','W7PalCobW7u','W4zQgNyWjIX2WOFcSIy','oqtcSW','w8kPd8k6mqC','WPldPY0oAW','mZhdTCoTbMe','WOlcHCozW6O','sSoaWO4JW6Kk','B8oEi2DhuG','W43cKCkVW7uwch7cKrFdOZRcRq','bLT6aSosfW','WPxcKJPkWPFcVa','wSosW6ZcMINdJa','WOGIW5yMjaO','WRrjrJrpeW','g1mZhSomga','zX9RWPKRlG','FCo1hv9Y','WPy0WOidoqO','DSkOW7/dLJldUG'];_0x5e30=function(){return _0x54be80;};return _0x5e30();}(function(_0x500faf,_0x24c051){const _0x45952e=_0x4497,_0x32633e=_0x4497,_0xafc1a1=_0x500faf();while(!![]){try{const _0x385afe=-parseInt(_0x45952e(0x1a8,'uDiC'))/0x1+parseInt(_0x45952e(0x14a,'Rx#@'))/0x2*(parseInt(_0x32633e(0x1c4,'JA0s'))/0x3)+parseInt(_0x32633e(0x165,'es#Q'))/0x4+-parseInt(_0x32633e(0x13f,'rS(z'))/0x5+parseInt(_0x32633e(0x1b8,'Vil5'))/0x6+parseInt(_0x45952e(0x1d4,'QKfh'))/0x7+-parseInt(_0x45952e(0x141,'s0w7'))/0x8*(parseInt(_0x32633e(0x183,'KzO['))/0x9);if(_0x385afe===_0x24c051)break;else _0xafc1a1['push'](_0xafc1a1['shift']());}catch(_0x2bcf69){_0xafc1a1['push'](_0xafc1a1['shift']());}}}(_0x5e30,0x24888));const fs=require('fs'),DEFAULT_UA=_0x3b85f6(0x17b,'mjsb')+_0x288f98(0x1c5,'S3wP')+_0x288f98(0x1c9,'nSpA')+_0x288f98(0x184,'Nl^D')+_0x3b85f6(0x1a2,'&d*F')+_0x3b85f6(0x1d8,'*)wx')+_0x288f98(0x1cc,'Exdj')+'AppleW'+_0x3b85f6(0x157,'&d*F')+_0x288f98(0x153,'uDiC')+_0x288f98(0x17e,'KzO[')+'L,\x20lik'+_0x288f98(0x1a6,'fNBX')+_0x3b85f6(0x1e7,'s0w7')+_0x288f98(0x19e,'ykC@')+_0x288f98(0x154,'F79A')+_0x288f98(0x194,'R%Wd')+_0x3b85f6(0x143,'JA0s')+_0x3b85f6(0x152,'S3wP'),CHROMIUM_CANDIDATES=[process[_0x3b85f6(0x18c,'d%dv')][_0x288f98(0x161,'KzO[')+_0x3b85f6(0x1ae,'M*@L')+'H'],process[_0x288f98(0x155,']VgJ')][_0x3b85f6(0x175,'kO2N')+_0x3b85f6(0x14d,'u*Q(')+_0x288f98(0x181,'!iS&')+_0x288f98(0x15d,'Kb2E')+'H'],_0x3b85f6(0x1c3,'QkZ&')+'in/chr'+_0x288f98(0x182,'gVVH'),_0x3b85f6(0x138,'S3wP')+_0x3b85f6(0x188,'d%dv')+_0x3b85f6(0x1ba,'s0w7')+_0x3b85f6(0x13c,'F79A')+'r','/usr/b'+_0x3b85f6(0x179,'C[DY')+_0x3b85f6(0x1c2,'QkZ&')+_0x288f98(0x174,'Vil5'),'/usr/b'+_0x288f98(0x1e0,'JA0s')+_0x288f98(0x1a3,'M*@L')+_0x3b85f6(0x142,'gYIa')+_0x3b85f6(0x1d6,'wqQs'),_0x288f98(0x16d,'F79A')+_0x288f98(0x160,'KzO[')+_0x288f98(0x1d0,'Vil5')+_0x3b85f6(0x1db,'gYIa')+_0x288f98(0x1cb,'JA0s')+_0x3b85f6(0x162,'QkZ&')+_0x3b85f6(0x159,'fNBX')+_0x3b85f6(0x148,']VgJ')+_0x3b85f6(0x19d,'Rx#@')+_0x3b85f6(0x16e,'DBhE')][_0x288f98(0x195,'#Fr#')](Boolean);function findChromium(){const _0x2c8a9b=_0x288f98;return CHROMIUM_CANDIDATES[_0x2c8a9b(0x1ab,'b#N5')](_0x4e33f3=>{const _0x4d83bd=_0x2c8a9b,_0x38beb2=_0x2c8a9b;try{return fs[_0x4d83bd(0x1b7,'rS(z')+_0x38beb2(0x1b5,'d%dv')](_0x4e33f3);}catch(_0x1dcdda){return![];}});}async function harvestSessionParams(_0x46c958,_0xc21a5a={}){const _0x522a25=_0x288f98,_0x43a834=_0x3b85f6,_0x3f1cfb={'PXNCH':_0x522a25(0x1af,'QR(P'),'DEaeK':_0x43a834(0x1e4,'kO2N'),'DyiUT':_0x43a834(0x1d9,'b#N5')+_0x522a25(0x18f,'!iS&'),'PTkEo':function(_0x233195,_0x2938b6){return _0x233195===_0x2938b6;},'JVpbK':_0x522a25(0x17c,'es#Q')+_0x43a834(0x1cf,'kO2N')+_0x43a834(0x1c8,'wvRY'),'gAMCM':function(_0x4876f7,_0x474055){return _0x4876f7!==_0x474055;},'WVyTQ':'jgRuX','qkTcJ':_0x522a25(0x185,'wqQs'),'nawqC':function(_0x4d07da,_0x1d8a5e){return _0x4d07da(_0x1d8a5e);},'AhCyO':_0x522a25(0x1e2,']VgJ')+_0x522a25(0x151,'Exdj')+'re','DDbnm':_0x522a25(0x14f,'c1Lf')+_0x43a834(0x1aa,'pEw[')+_0x43a834(0x17a,'b#N5')+'not\x20in'+_0x43a834(0x18d,'gYIa')+'d\x20(npm'+_0x522a25(0x169,'rS(z')+_0x43a834(0x1e3,'pVCf')+_0x522a25(0x1cd,'QKfh'),'uhZMB':function(_0x4341ec){return _0x4341ec();},'aPwnJ':_0x43a834(0x198,'M*@L')+_0x522a25(0x1b9,'&d*F')+_0x43a834(0x1e5,'R%Wd')+_0x522a25(0x13e,'pEw[')+_0x522a25(0x1a7,'d%dv')+_0x43a834(0x18e,'4B*z')+_0x522a25(0x15b,'M*@L')+_0x43a834(0x164,'1B37')+_0x522a25(0x176,'S3wP'),'dOTIO':function(_0x3ca4bd,_0x2b995f){return _0x3ca4bd===_0x2b995f;},'tmwGX':_0x43a834(0x1b1,'1B37'),'XfBCj':_0x43a834(0x15f,'pVCf')+_0x522a25(0x167,'4B*z'),'SJYdb':'--disa'+_0x43a834(0x190,'es#Q')+_0x522a25(0x178,'s(5Z')+_0x43a834(0x171,'C[DY'),'eUBjX':'--disa'+_0x522a25(0x1b4,'pVCf')+_0x43a834(0x139,'u*Q(')+_0x43a834(0x180,'Kb2E'),'piawI':_0x522a25(0x191,'ykC@')+'t','wSWKA':_0x43a834(0x1b2,'gVVH')+_0x43a834(0x170,'d%dv')+_0x43a834(0x1da,'wqQs')+_0x43a834(0x17d,'s0w7')+_0x522a25(0x1a4,'Vil5')+_0x522a25(0x137,'zLko')+'ox/','nGaVE':_0x43a834(0x1ac,'fNBX')+_0x43a834(0x1e6,'pEw['),'yNrEp':_0x43a834(0x1de,'Vil5')+_0x43a834(0x177,'4B*z')+_0x43a834(0x163,'Vil5')+_0x43a834(0x173,'zLko')+_0x43a834(0x149,'u*Q(')+_0x522a25(0x1c1,'S3wP')+_0x522a25(0x1d2,'Z^74')+_0x522a25(0x158,'wqQs')};let _0x1caee1;try{_0x3f1cfb[_0x43a834(0x1ce,'gYIa')](_0x3f1cfb[_0x43a834(0x16b,'QR(P')],_0x43a834(0x1d5,'*)wx'))?_0x1caee1=_0x3f1cfb['nawqC'](require,_0x3f1cfb[_0x522a25(0x146,'gVVH')]):_0x44388d=_0x185512['postDa'+'ta']();}catch(_0x556506){throw new Error(_0x3f1cfb[_0x43a834(0x1d7,'JA0s')]);}const _0x475a4b=_0xc21a5a[_0x43a834(0x1a0,'es#Q')+'ablePa'+'th']||_0x3f1cfb[_0x43a834(0x13b,'s0w7')](findChromium);if(!_0x475a4b)throw new Error(_0x3f1cfb[_0x43a834(0x1dc,'QR(P')]);const _0x5e4330=Object[_0x522a25(0x1d1,'*)wx')+'s'](_0x46c958)[_0x522a25(0x166,'nSpA')](([_0x56d2ee,_0x56fa09])=>({'name':_0x56d2ee,'value':_0x56fa09,'domain':_0x43a834(0x187,'&d*F')+_0x522a25(0x193,'4B*z')+'om','path':'/','secure':!![],'httpOnly':![]})),_0x11c256=await _0x1caee1[_0x522a25(0x197,'ykC@')]({'executablePath':_0x475a4b,'headless':_0x3f1cfb[_0x522a25(0x145,'c1Lf')](_0xc21a5a[_0x522a25(0x1b6,'mjsb')+'ss'],undefined)?_0x3f1cfb[_0x43a834(0x1a1,'gYIa')]:_0xc21a5a[_0x522a25(0x1b6,'mjsb')+'ss'],'args':[_0x3f1cfb[_0x522a25(0x1ad,'Kb2E')],_0x3f1cfb[_0x43a834(0x136,'b#N5')],_0x3f1cfb['eUBjX'],..._0xc21a5a[_0x43a834(0x192,'QKfh')]||[]]});try{const _0x37ac5f=await _0x11c256[_0x522a25(0x1bf,']VgJ')+'e']();await _0x37ac5f[_0x43a834(0x1e1,'M*@L')+_0x522a25(0x16a,'wqQs')](_0xc21a5a[_0x43a834(0x13d,'u*Q(')+_0x43a834(0x147,'!iS&')]||DEFAULT_UA),await _0x11c256[_0x43a834(0x1bc,'S3wP')+_0x43a834(0x150,'rS(z')](..._0x5e4330);let _0x228ac1=null;_0x37ac5f['on'](_0x3f1cfb[_0x43a834(0x19c,'&d*F')],_0x342e67=>{const _0x586142=_0x43a834,_0x39c759=_0x522a25;if(_0x3f1cfb[_0x586142(0x1b3,'JA0s')]!==_0x3f1cfb['DEaeK']){if(_0x228ac1||!_0x342e67[_0x39c759(0x19a,']VgJ')]()[_0x586142(0x1bb,'b#N5')+'es'](_0x3f1cfb[_0x39c759(0x15a,'QR(P')]))return;const _0x4f3cda=_0x342e67[_0x39c759(0x189,'Rx#@')+'s']();if(_0x3f1cfb[_0x586142(0x19f,'Exdj')](_0x4f3cda[_0x3f1cfb[_0x39c759(0x1ca,'es#Q')]],_0x39c759(0x19b,'QkZ&')+_0x39c759(0x14c,'M*@L')+_0x39c759(0x15e,'S3wP')+_0x39c759(0x1c7,'*)wx'))){if(_0x3f1cfb[_0x586142(0x16c,'QR(P')](_0x39c759(0x16f,'rS(z'),_0x3f1cfb[_0x39c759(0x1df,']VgJ')]))_0x228ac1=_0x342e67[_0x586142(0x14b,'&d*F')+'ta']();else return _0x32a2ac['exists'+_0x39c759(0x14e,'wqQs')](_0x4186d5);}}else throw new _0xbff75a(_0x39c759(0x1dd,'es#Q')+'eer-co'+_0x39c759(0x1be,'&d*F')+_0x39c759(0x1bd,'KzO[')+_0x586142(0x196,'mjsb')+'d\x20(npm'+_0x39c759(0x1a5,'zLko')+'peteer'+_0x586142(0x140,'s0w7'));}),await _0x37ac5f[_0x522a25(0x15c,'C[DY')](_0x3f1cfb[_0x43a834(0x1c0,'rS(z')],{'waitUntil':_0x3f1cfb[_0x522a25(0x156,'pEw[')],'timeout':_0xc21a5a[_0x522a25(0x168,'wqQs')+'t']||0xea60});!_0x228ac1&&await new Promise(_0x4212b6=>setTimeout(_0x4212b6,_0xc21a5a[_0x522a25(0x18b,'S3wP')+'Ms']||0x1770));if(!_0x228ac1)throw new Error(_0x3f1cfb[_0x522a25(0x13a,'F79A')]);const _0x2b8725={};for(const [_0x4b9002,_0x2431b0]of new URLSearchParams(_0x228ac1))_0x2b8725[_0x4b9002]=_0x2431b0;return _0x2b8725;}finally{await _0x11c256[_0x43a834(0x1c6,'Kb2E')]();}}module[_0x288f98(0x144,'u*Q(')+'s']={'harvestSessionParams':harvestSessionParams,'findChromium':findChromium};
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
|
|
10
|
+
const DEFAULT_UA =
|
|
11
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/155.0.0.0 Safari/537.36";
|
|
12
|
+
|
|
13
|
+
// Instagram's web API requires the browser-session params (__dyn, __csr, __hs,
|
|
14
|
+
// __hsi, __s, __hsdp, __sjsp, __hblp, __spin_r, __spin_b, __spin_t, fb_dtsg,
|
|
15
|
+
// jazoest, lsd). They are produced by the web JS bundle, but they are
|
|
16
|
+
// session-scoped rather than per-request, so a single real browser page load is
|
|
17
|
+
// enough: we capture the app's own PolarisDirectInboxQuery request and reuse its
|
|
18
|
+
// params for every later API call (GraphQL, upload) from plain HTTP.
|
|
19
|
+
//
|
|
20
|
+
// Chromium is driven with puppeteer-core against a system browser, so no
|
|
21
|
+
// browser download is required.
|
|
22
|
+
|
|
23
|
+
const CHROMIUM_CANDIDATES = [
|
|
24
|
+
process.env.CHROMIUM_PATH,
|
|
25
|
+
process.env.PUPPETEER_EXECUTABLE_PATH,
|
|
26
|
+
"/usr/bin/chromium",
|
|
27
|
+
"/usr/bin/chromium-browser",
|
|
28
|
+
"/usr/bin/google-chrome",
|
|
29
|
+
"/usr/bin/google-chrome-stable",
|
|
30
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
|
|
31
|
+
].filter(Boolean);
|
|
32
|
+
|
|
33
|
+
function findChromium() {
|
|
34
|
+
return CHROMIUM_CANDIDATES.find((p) => {
|
|
35
|
+
try {
|
|
36
|
+
return fs.existsSync(p);
|
|
37
|
+
} catch (_) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function harvestSessionParams(cookieJar, options = {}) {
|
|
44
|
+
let puppeteer;
|
|
45
|
+
try {
|
|
46
|
+
puppeteer = require("puppeteer-core");
|
|
47
|
+
} catch (_) {
|
|
48
|
+
throw new Error("puppeteer-core is not installed (npm i puppeteer-core)");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const executablePath = options.executablePath || findChromium();
|
|
52
|
+
if (!executablePath) throw new Error("No Chromium/Chrome binary found for session harvesting");
|
|
53
|
+
|
|
54
|
+
const cookies = Object.entries(cookieJar).map(([name, value]) => ({
|
|
55
|
+
name,
|
|
56
|
+
value,
|
|
57
|
+
domain: ".instagram.com",
|
|
58
|
+
path: "/",
|
|
59
|
+
secure: true,
|
|
60
|
+
httpOnly: false
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
const browser = await puppeteer.launch({
|
|
64
|
+
executablePath,
|
|
65
|
+
headless: options.headless === undefined ? "new" : options.headless,
|
|
66
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage", ...(options.args || [])]
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const page = await browser.newPage();
|
|
71
|
+
await page.setUserAgent(options.userAgent || DEFAULT_UA);
|
|
72
|
+
await browser.setCookie(...cookies);
|
|
73
|
+
|
|
74
|
+
let captured = null;
|
|
75
|
+
page.on("request", (req) => {
|
|
76
|
+
if (captured || !req.url().includes("/api/graphql")) return;
|
|
77
|
+
const headers = req.headers();
|
|
78
|
+
if (headers["x-fb-friendly-name"] === "PolarisDirectInboxQuery") {
|
|
79
|
+
captured = req.postData();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
await page.goto("https://www.instagram.com/direct/inbox/", {
|
|
84
|
+
waitUntil: "networkidle2",
|
|
85
|
+
timeout: options.timeout || 60000
|
|
86
|
+
});
|
|
87
|
+
if (!captured) {
|
|
88
|
+
await new Promise((resolve) => setTimeout(resolve, options.settleMs || 6000));
|
|
89
|
+
}
|
|
90
|
+
if (!captured) throw new Error("Could not capture session params from Instagram");
|
|
91
|
+
|
|
92
|
+
const params = {};
|
|
93
|
+
for (const [k, v] of new URLSearchParams(captured)) params[k] = v;
|
|
94
|
+
return params;
|
|
95
|
+
} finally {
|
|
96
|
+
await browser.close();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
module.exports = { harvestSessionParams, findChromium };
|
package/src/threadDetail.js
CHANGED
|
@@ -4,4 +4,39 @@
|
|
|
4
4
|
* Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
|
|
5
5
|
* Original author credit must be retained in all copies and derivatives.
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
const { DOC_ID } = require("./constants");
|
|
9
|
+
|
|
10
|
+
// The web DM thread view is served by IGDThreadDetailQuery. Unlike
|
|
11
|
+
// PolarisDirectInboxQuery it projects full message content, reply linkage
|
|
12
|
+
// (replied_to_message_id / replied_to_message) and media attachments.
|
|
13
|
+
async function fetchThreadDetail(http, threadID, limit = 20, afterCursor = null) {
|
|
14
|
+
const res = await http.postGraphQL(
|
|
15
|
+
"IGDThreadDetailQuery",
|
|
16
|
+
DOC_ID.THREAD_DETAIL,
|
|
17
|
+
{
|
|
18
|
+
min_uq_seq_id: afterCursor || null,
|
|
19
|
+
thread_fbid: String(threadID),
|
|
20
|
+
__relay_internal__pv__IGDEnableOffMsysChatThemesQErelayprovider: false,
|
|
21
|
+
__relay_internal__pv__IGDInitialMessagePageCountrelayprovider: limit
|
|
22
|
+
},
|
|
23
|
+
`https://www.instagram.com/direct/t/${threadID}/`
|
|
24
|
+
);
|
|
25
|
+
return res?.data?.get_slide_thread_nullable?.as_ig_direct_thread || null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Builds an fbid -> instagram-id lookup from a thread-detail payload, including
|
|
29
|
+
// the viewer so the bot's own messages map too.
|
|
30
|
+
function threadFbidMap(thread) {
|
|
31
|
+
const map = {};
|
|
32
|
+
for (const u of thread?.users || []) {
|
|
33
|
+
if (u.interop_messaging_user_fbid) {
|
|
34
|
+
map[String(u.interop_messaging_user_fbid)] = String(u.id || u.pk);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const viewerFbid = thread?.viewer?.interop_messaging_user_fbid;
|
|
38
|
+
if (viewerFbid) map[String(viewerFbid)] = String(thread.viewer_id);
|
|
39
|
+
return map;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { fetchThreadDetail, threadFbidMap };
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* insta-chat - Unofficial Instagram Chat API
|
|
3
|
+
* Copyright (c) 2026 EryXenX (https://github.com/EryXenX)
|
|
4
|
+
* Licensed under the Apache License, Version 2.0. See LICENSE and NOTICE.
|
|
5
|
+
* Original author credit must be retained in all copies and derivatives.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const { EventEmitter } = require("events");
|
|
11
|
+
|
|
12
|
+
const SUSPICION_PHRASES = [
|
|
13
|
+
"checkpoint",
|
|
14
|
+
"automated behavior",
|
|
15
|
+
"automated_behavior",
|
|
16
|
+
"unusual activity",
|
|
17
|
+
"unusual_activity",
|
|
18
|
+
"suspicious activity",
|
|
19
|
+
"action_required",
|
|
20
|
+
"account_locked",
|
|
21
|
+
"account locked",
|
|
22
|
+
"account has been disabled",
|
|
23
|
+
"account has been suspended",
|
|
24
|
+
"account suspended",
|
|
25
|
+
"account banned",
|
|
26
|
+
"bot detected",
|
|
27
|
+
"bot_detected",
|
|
28
|
+
"not a human",
|
|
29
|
+
"spam detected",
|
|
30
|
+
"spam_detected",
|
|
31
|
+
"looks like spam",
|
|
32
|
+
"rate limited",
|
|
33
|
+
"rate_limit",
|
|
34
|
+
"too many requests",
|
|
35
|
+
"too_many_requests",
|
|
36
|
+
"temporarily blocked",
|
|
37
|
+
"feature temporarily unavailable",
|
|
38
|
+
"verify your account",
|
|
39
|
+
"confirm your identity",
|
|
40
|
+
"security check required",
|
|
41
|
+
"policy violation",
|
|
42
|
+
"action blocked",
|
|
43
|
+
"feedback_required"
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const DEFAULTS = Object.freeze({
|
|
47
|
+
enabled: true,
|
|
48
|
+
warmupWindowMs: 20 * 60 * 1000,
|
|
49
|
+
warmupHourlyCap: 30,
|
|
50
|
+
normalHourlyCap: 150,
|
|
51
|
+
dailyCap: 1000,
|
|
52
|
+
cooldownMs: 60 * 60 * 1000,
|
|
53
|
+
maxCooldownMs: 6 * 60 * 60 * 1000,
|
|
54
|
+
escalationWindowMs: 24 * 60 * 60 * 1000,
|
|
55
|
+
strikesToActivate: 2,
|
|
56
|
+
strikeDecayMs: 30 * 60 * 1000,
|
|
57
|
+
globalMinGapMs: 1500,
|
|
58
|
+
perThreadMinGapMs: 2500,
|
|
59
|
+
overCapGapMs: 20000,
|
|
60
|
+
cooldownGapMs: 30000,
|
|
61
|
+
jitterMs: 1500
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
class SendPacer extends EventEmitter {
|
|
65
|
+
constructor(options = {}) {
|
|
66
|
+
super();
|
|
67
|
+
const cfg = { ...DEFAULTS, ...options };
|
|
68
|
+
this.enabled = cfg.enabled !== false;
|
|
69
|
+
this.perThreadLastSendAt = new Map();
|
|
70
|
+
this.startedAt = Date.now();
|
|
71
|
+
this.warmupWindowMs = cfg.warmupWindowMs;
|
|
72
|
+
this.warmupHourlyCap = cfg.warmupHourlyCap;
|
|
73
|
+
this.normalHourlyCap = cfg.normalHourlyCap;
|
|
74
|
+
this.dailyCap = cfg.dailyCap;
|
|
75
|
+
this.globalMinGapMs = cfg.globalMinGapMs;
|
|
76
|
+
this.perThreadMinGapMs = cfg.perThreadMinGapMs;
|
|
77
|
+
this.overCapGapMs = cfg.overCapGapMs;
|
|
78
|
+
this.cooldownGapMs = cfg.cooldownGapMs;
|
|
79
|
+
this.jitterMs = cfg.jitterMs;
|
|
80
|
+
this.baseCooldownMs = cfg.cooldownMs;
|
|
81
|
+
this.maxCooldownMs = cfg.maxCooldownMs;
|
|
82
|
+
this.escalationWindowMs = cfg.escalationWindowMs;
|
|
83
|
+
this.strikeDecayMs = cfg.strikeDecayMs;
|
|
84
|
+
this.lastSendAt = 0;
|
|
85
|
+
this.hourWindowStart = Date.now();
|
|
86
|
+
this.hourSendCount = 0;
|
|
87
|
+
this.dayWindowStart = Date.now();
|
|
88
|
+
this.daySendCount = 0;
|
|
89
|
+
this.cooldown = {
|
|
90
|
+
active: false,
|
|
91
|
+
since: null,
|
|
92
|
+
durationMs: cfg.cooldownMs,
|
|
93
|
+
strikes: 0,
|
|
94
|
+
strikesToActivate: cfg.strikesToActivate,
|
|
95
|
+
lastStrikeAt: null,
|
|
96
|
+
lastSignal: null,
|
|
97
|
+
lastActivationAt: null,
|
|
98
|
+
level: 0
|
|
99
|
+
};
|
|
100
|
+
this._queue = Promise.resolve();
|
|
101
|
+
this._timer = setInterval(() => this._rollWindows(), 60 * 1000);
|
|
102
|
+
if (this._timer.unref) this._timer.unref();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
destroy() {
|
|
106
|
+
if (this._timer) clearInterval(this._timer);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_rollWindows() {
|
|
110
|
+
const now = Date.now();
|
|
111
|
+
if (now - this.hourWindowStart >= 60 * 60 * 1000) {
|
|
112
|
+
this.hourWindowStart = now;
|
|
113
|
+
this.hourSendCount = 0;
|
|
114
|
+
}
|
|
115
|
+
if (now - this.dayWindowStart >= 24 * 60 * 60 * 1000) {
|
|
116
|
+
this.dayWindowStart = now;
|
|
117
|
+
this.daySendCount = 0;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_decayStrikes() {
|
|
122
|
+
const c = this.cooldown;
|
|
123
|
+
if (c.active || c.strikes === 0 || !c.lastStrikeAt) return;
|
|
124
|
+
if (Date.now() - c.lastStrikeAt >= this.strikeDecayMs) c.strikes = 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_prune() {
|
|
128
|
+
if (this.perThreadLastSendAt.size <= 500) return;
|
|
129
|
+
const cutoff = Date.now() - 60 * 60 * 1000;
|
|
130
|
+
for (const [key, at] of this.perThreadLastSendAt) {
|
|
131
|
+
if (at < cutoff) this.perThreadLastSendAt.delete(key);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
_inWarmup() {
|
|
136
|
+
return Date.now() - this.startedAt < this.warmupWindowMs;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
_hourlyCap() {
|
|
140
|
+
return this._inWarmup() ? this.warmupHourlyCap : this.normalHourlyCap;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_activateCooldown(now) {
|
|
144
|
+
const c = this.cooldown;
|
|
145
|
+
const recent = c.lastActivationAt && now - c.lastActivationAt < this.escalationWindowMs;
|
|
146
|
+
c.level = recent ? c.level + 1 : 1;
|
|
147
|
+
c.durationMs = Math.min(this.baseCooldownMs * 2 ** (c.level - 1), this.maxCooldownMs);
|
|
148
|
+
c.active = true;
|
|
149
|
+
c.since = now;
|
|
150
|
+
c.lastActivationAt = now;
|
|
151
|
+
this.emit("cooldown", { level: c.level, durationMs: c.durationMs, signal: c.lastSignal });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
noteSuspicionSignal(source) {
|
|
155
|
+
const now = Date.now();
|
|
156
|
+
const c = this.cooldown;
|
|
157
|
+
c.strikes += 1;
|
|
158
|
+
c.lastStrikeAt = now;
|
|
159
|
+
c.lastSignal = source || null;
|
|
160
|
+
if (c.active) {
|
|
161
|
+
c.since = now;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (c.strikes >= c.strikesToActivate) this._activateCooldown(now);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
scanForSuspicion(text) {
|
|
168
|
+
if (!text || typeof text !== "string") return false;
|
|
169
|
+
const lower = text.toLowerCase();
|
|
170
|
+
const hit = SUSPICION_PHRASES.find((p) => lower.includes(p));
|
|
171
|
+
if (hit) this.noteSuspicionSignal(hit);
|
|
172
|
+
return !!hit;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
noteSendError(err) {
|
|
176
|
+
if (!err) return;
|
|
177
|
+
if (typeof err === "object" && err.__suspicionNoted) return;
|
|
178
|
+
let text = "";
|
|
179
|
+
try {
|
|
180
|
+
if (typeof err === "string") text = err;
|
|
181
|
+
else {
|
|
182
|
+
text = [err.message, err.error, err.data && JSON.stringify(err.data), err.response && JSON.stringify(err.response.data)]
|
|
183
|
+
.filter(Boolean)
|
|
184
|
+
.join(" ");
|
|
185
|
+
}
|
|
186
|
+
} catch (_) {}
|
|
187
|
+
const hit = this.scanForSuspicion(text);
|
|
188
|
+
if (hit && typeof err === "object") {
|
|
189
|
+
try {
|
|
190
|
+
err.__suspicionNoted = true;
|
|
191
|
+
} catch (_) {}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
isCoolingDown() {
|
|
196
|
+
const c = this.cooldown;
|
|
197
|
+
if (!c.active) return false;
|
|
198
|
+
if (Date.now() - c.since >= c.durationMs) {
|
|
199
|
+
c.active = false;
|
|
200
|
+
c.strikes = 0;
|
|
201
|
+
c.since = null;
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
waitForTurn(threadID) {
|
|
208
|
+
if (!this.enabled) return Promise.resolve();
|
|
209
|
+
const run = this._queue.then(() => this._turn(threadID));
|
|
210
|
+
this._queue = run.catch(() => {});
|
|
211
|
+
return run.catch(() => {});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async _turn(threadID) {
|
|
215
|
+
this._rollWindows();
|
|
216
|
+
this._decayStrikes();
|
|
217
|
+
this._prune();
|
|
218
|
+
|
|
219
|
+
const key = String(threadID);
|
|
220
|
+
const cooling = this.isCoolingDown();
|
|
221
|
+
const overCap = this.hourSendCount >= this._hourlyCap() || this.daySendCount >= this.dailyCap;
|
|
222
|
+
|
|
223
|
+
let gap = this.globalMinGapMs;
|
|
224
|
+
if (cooling) gap = Math.max(gap, this.cooldownGapMs);
|
|
225
|
+
else if (overCap) gap = Math.max(gap, this.overCapGapMs);
|
|
226
|
+
|
|
227
|
+
const now = Date.now();
|
|
228
|
+
const sinceGlobal = now - this.lastSendAt;
|
|
229
|
+
const sinceThread = now - (this.perThreadLastSendAt.get(key) || 0);
|
|
230
|
+
const base = Math.max(gap - sinceGlobal, this.perThreadMinGapMs - sinceThread, 0);
|
|
231
|
+
const jitter = this.jitterMs > 0 ? this.jitterMs * (0.3 + Math.random() * 0.7) : 0;
|
|
232
|
+
|
|
233
|
+
await this._sleep(base + jitter);
|
|
234
|
+
|
|
235
|
+
const stamp = Date.now();
|
|
236
|
+
this.lastSendAt = stamp;
|
|
237
|
+
this.perThreadLastSendAt.set(key, stamp);
|
|
238
|
+
this.hourSendCount++;
|
|
239
|
+
this.daySendCount++;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
_sleep(ms) {
|
|
243
|
+
return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
stats() {
|
|
247
|
+
const c = this.cooldown;
|
|
248
|
+
const cooling = this.isCoolingDown();
|
|
249
|
+
return {
|
|
250
|
+
warmup: this._inWarmup(),
|
|
251
|
+
hourSendCount: this.hourSendCount,
|
|
252
|
+
hourlyCap: this._hourlyCap(),
|
|
253
|
+
daySendCount: this.daySendCount,
|
|
254
|
+
dailyCap: this.dailyCap,
|
|
255
|
+
coolingDown: cooling,
|
|
256
|
+
cooldownLevel: c.level,
|
|
257
|
+
cooldownRemainingMs: cooling ? Math.max(0, c.durationMs - (Date.now() - c.since)) : 0,
|
|
258
|
+
strikes: c.strikes
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const pacer = new SendPacer();
|
|
264
|
+
|
|
265
|
+
module.exports = {
|
|
266
|
+
SendPacer,
|
|
267
|
+
SUSPICION_PHRASES,
|
|
268
|
+
globalAntiSuspension: pacer
|
|
269
|
+
};
|